浏览代码
preparation for the optimization of composite and rasterization
preparation for the optimization of composite and rasterization
(1) create uiPicture and uiDrawCmds/main
xingwei.zhu
5 年前
当前提交
3ecb9cf0
共有 41 个文件被更改,包括 1679 次插入 和 1150 次删除
-
7Samples/UIWidgetSample/TextInput.unity
-
4Runtime/ui/utils/renderer/cmdbufferCanvas/command_buffer_canvas.cs
-
1001Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
-
301Runtime/ui/utils/renderer/common/base_canvas.cs
-
94Runtime/ui/utils/renderer/common/draw_cmd.cs
-
276Runtime/ui/utils/renderer/common/picture.cs
-
11Runtime/ui/utils/renderer/canvas_clip.cs.meta
-
981Runtime/ui/utils/renderer/canvas_impl.cs
-
11Runtime/ui/utils/renderer/canvas_impl.cs.meta
-
11Runtime/ui/utils/renderer/canvas_shader.cs.meta
-
11Runtime/ui/utils/renderer/canvas_shader_utils.cs.meta
-
11Runtime/ui/utils/renderer/canvas_utils.cs.meta
-
11Runtime/ui/utils/renderer/command_buffer_canvas.cs.meta
-
11Runtime/ui/utils/renderer/generic_list.cs.meta
-
11Runtime/ui/utils/renderer/mesh_mesh.cs.meta
-
11Runtime/ui/utils/renderer/path.cs.meta
-
11Runtime/ui/utils/renderer/path_cache.cs.meta
-
11Runtime/ui/utils/renderer/path_utils.cs.meta
-
11Runtime/ui/utils/renderer/pool_items.cs.meta
-
11Runtime/ui/utils/renderer/render_cmd.cs.meta
-
11Runtime/ui/utils/renderer/render_layer.cs.meta
-
11Runtime/ui/utils/renderer/tessellation_generator.cs.meta
-
0/Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/canvas_clip.cs
-
0/Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/canvas_shader.cs
-
0/Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/canvas_shader_utils.cs
-
0/Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/canvas_utils.cs
-
0/Runtime/ui/utils/renderer/cmdbufferCanvas/command_buffer_canvas.cs
-
0/Runtime/ui/utils/renderer/allocUtils/generic_list.cs
-
0/Runtime/ui/utils/renderer/geometry/mesh_mesh.cs
-
0/Runtime/ui/utils/renderer/geometry/path/path.cs
-
0/Runtime/ui/utils/renderer/geometry/path/path_cache.cs
-
0/Runtime/ui/utils/renderer/geometry/path/path_utils.cs
-
0/Runtime/ui/utils/renderer/allocUtils/pool_items.cs
-
0/Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/render_cmd.cs
-
0/Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/render_layer.cs
-
0/Runtime/ui/utils/renderer/geometry/path/tessellation_generator.cs
1001
Runtime/ui/utils/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
using System; |
|||
using Unity.UIWidgets.flow; |
|||
using Unity.UIWidgets.foundation; |
|||
using UnityEngine; |
|||
|
|||
namespace Unity.UIWidgets.ui { |
|||
public class uiRecorderCanvas : PoolItem, Canvas { |
|||
public uiRecorderCanvas(uiPictureRecorder recorder) { |
|||
this._recorder = recorder; |
|||
} |
|||
|
|||
protected readonly uiPictureRecorder _recorder; |
|||
|
|||
int _saveCount = 1; |
|||
|
|||
public void save() { |
|||
this._saveCount++; |
|||
this._recorder.addDrawCmd(new uiDrawSave { |
|||
}); |
|||
} |
|||
|
|||
public void saveLayer(Rect rect, Paint paint) { |
|||
this._saveCount++; |
|||
this._recorder.addDrawCmd(new uiDrawSaveLayer { |
|||
rect = rect, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void restore() { |
|||
this._saveCount--; |
|||
this._recorder.addDrawCmd(new uiDrawRestore { |
|||
}); |
|||
} |
|||
|
|||
public int getSaveCount() { |
|||
return this._saveCount; |
|||
} |
|||
|
|||
public void translate(float dx, float dy) { |
|||
this._recorder.addDrawCmd(new uiDrawTranslate { |
|||
dx = dx, |
|||
dy = dy, |
|||
}); |
|||
} |
|||
|
|||
public void scale(float sx, float? sy = null) { |
|||
this._recorder.addDrawCmd(new uiDrawScale { |
|||
sx = sx, |
|||
sy = sy, |
|||
}); |
|||
} |
|||
|
|||
public void rotate(float radians, Offset offset = null) { |
|||
this._recorder.addDrawCmd(new uiDrawRotate { |
|||
radians = radians, |
|||
offset = offset, |
|||
}); |
|||
} |
|||
|
|||
public void skew(float sx, float sy) { |
|||
this._recorder.addDrawCmd(new uiDrawSkew { |
|||
sx = sx, |
|||
sy = sy, |
|||
}); |
|||
} |
|||
|
|||
public void concat(Matrix3 matrix) { |
|||
this._recorder.addDrawCmd(new uiDrawConcat { |
|||
matrix = matrix, |
|||
}); |
|||
} |
|||
|
|||
public Matrix3 getTotalMatrix() { |
|||
return this._recorder.getTotalMatrix(); |
|||
} |
|||
|
|||
public void resetMatrix() { |
|||
this._recorder.addDrawCmd(new uiDrawResetMatrix { |
|||
}); |
|||
} |
|||
|
|||
public void setMatrix(Matrix3 matrix) { |
|||
this._recorder.addDrawCmd(new uiDrawSetMatrix { |
|||
matrix = matrix, |
|||
}); |
|||
} |
|||
|
|||
public virtual float getDevicePixelRatio() { |
|||
throw new Exception("not available in recorder"); |
|||
} |
|||
|
|||
public void clipRect(Rect rect) { |
|||
this._recorder.addDrawCmd(new uiDrawClipRect { |
|||
rect = rect, |
|||
}); |
|||
} |
|||
|
|||
public void clipRRect(RRect rrect) { |
|||
this._recorder.addDrawCmd(new uiDrawClipRRect { |
|||
rrect = rrect, |
|||
}); |
|||
} |
|||
|
|||
public void clipPath(Path path) { |
|||
this._recorder.addDrawCmd(new uiDrawClipPath { |
|||
path = path, |
|||
}); |
|||
} |
|||
|
|||
public void drawLine(Offset from, Offset to, Paint paint) { |
|||
var path = new Path(); |
|||
path.moveTo(from.dx, from.dy); |
|||
path.lineTo(to.dx, to.dy); |
|||
|
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawShadow(Path path, Color color, float elevation, bool transparentOccluder) { |
|||
float dpr = Window.instance.devicePixelRatio; |
|||
PhysicalShapeLayer.drawShadow(this, path, color, elevation, transparentOccluder, dpr); |
|||
} |
|||
|
|||
public void drawRect(Rect rect, Paint paint) { |
|||
if (rect.size.isEmpty) { |
|||
return; |
|||
} |
|||
|
|||
var path = new Path(); |
|||
path.addRect(rect); |
|||
|
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawRRect(RRect rrect, Paint paint) { |
|||
var path = new Path(); |
|||
path.addRRect(rrect); |
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawDRRect(RRect outer, RRect inner, Paint paint) { |
|||
var path = new Path(); |
|||
path.addRRect(outer); |
|||
path.addRRect(inner); |
|||
path.winding(PathWinding.clockwise); |
|||
|
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawOval(Rect rect, Paint paint) { |
|||
var w = rect.width / 2; |
|||
var h = rect.height / 2; |
|||
var path = new Path(); |
|||
path.addEllipse(rect.left + w, rect.top + h, w, h); |
|||
|
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawCircle(Offset c, float radius, Paint paint) { |
|||
var path = new Path(); |
|||
path.addCircle(c.dx, c.dy, radius); |
|||
|
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawArc(Rect rect, float startAngle, float sweepAngle, bool useCenter, Paint paint) { |
|||
var path = new Path(); |
|||
|
|||
if (useCenter) { |
|||
var center = rect.center; |
|||
path.moveTo(center.dx, center.dy); |
|||
} |
|||
|
|||
bool forceMoveTo = !useCenter; |
|||
while (sweepAngle <= -Mathf.PI * 2) { |
|||
path.arcTo(rect, startAngle, -Mathf.PI, forceMoveTo); |
|||
startAngle -= Mathf.PI; |
|||
path.arcTo(rect, startAngle, -Mathf.PI, false); |
|||
startAngle -= Mathf.PI; |
|||
forceMoveTo = false; |
|||
sweepAngle += Mathf.PI * 2; |
|||
} |
|||
|
|||
while (sweepAngle >= Mathf.PI * 2) { |
|||
path.arcTo(rect, startAngle, Mathf.PI, forceMoveTo); |
|||
startAngle += Mathf.PI; |
|||
path.arcTo(rect, startAngle, Mathf.PI, false); |
|||
startAngle += Mathf.PI; |
|||
forceMoveTo = false; |
|||
sweepAngle -= Mathf.PI * 2; |
|||
} |
|||
|
|||
path.arcTo(rect, startAngle, sweepAngle, forceMoveTo); |
|||
if (useCenter) { |
|||
path.close(); |
|||
} |
|||
|
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawPath(Path path, Paint paint) { |
|||
this._recorder.addDrawCmd(new uiDrawPath { |
|||
path = path, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawImage(Image image, Offset offset, Paint paint) { |
|||
this._recorder.addDrawCmd(new uiDrawImage { |
|||
image = image, |
|||
offset = offset, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawImageRect(Image image, Rect dst, Paint paint) { |
|||
this._recorder.addDrawCmd(new uiDrawImageRect { |
|||
image = image, |
|||
dst = dst, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawImageRect(Image image, Rect src, Rect dst, Paint paint) { |
|||
this._recorder.addDrawCmd(new uiDrawImageRect { |
|||
image = image, |
|||
src = src, |
|||
dst = dst, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawImageNine(Image image, Rect center, Rect dst, Paint paint) { |
|||
this._recorder.addDrawCmd(new uiDrawImageNine { |
|||
image = image, |
|||
center = center, |
|||
dst = dst, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawImageNine(Image image, Rect src, Rect center, Rect dst, Paint paint) { |
|||
this._recorder.addDrawCmd(new uiDrawImageNine { |
|||
image = image, |
|||
src = src, |
|||
center = center, |
|||
dst = dst, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawPicture(Picture picture) { |
|||
this._recorder.addDrawCmd(new uiDrawPicture { |
|||
picture = picture, |
|||
}); |
|||
} |
|||
|
|||
public void drawTextBlob(TextBlob textBlob, Offset offset, Paint paint) { |
|||
this._recorder.addDrawCmd(new uiDrawTextBlob { |
|||
textBlob = textBlob, |
|||
offset = offset, |
|||
paint = new Paint(paint), |
|||
}); |
|||
} |
|||
|
|||
public void drawParagraph(Paragraph paragraph, Offset offset) { |
|||
D.assert(paragraph != null); |
|||
D.assert(PaintingUtils._offsetIsValid(offset)); |
|||
paragraph.paint(this, offset); |
|||
} |
|||
|
|||
public virtual void flush() { |
|||
throw new Exception("not available in recorder"); |
|||
} |
|||
|
|||
public void reset() { |
|||
this._recorder.reset(); |
|||
} |
|||
} |
|||
} |
|
|||
namespace Unity.UIWidgets.ui { |
|||
public abstract class uiDrawCmd { |
|||
} |
|||
|
|||
public class uiDrawSave : uiDrawCmd { |
|||
} |
|||
|
|||
public class uiDrawSaveLayer : uiDrawCmd { |
|||
public Rect rect; |
|||
public Paint paint; |
|||
} |
|||
|
|||
public class uiDrawRestore : uiDrawCmd { |
|||
} |
|||
|
|||
public class uiDrawTranslate : uiDrawCmd { |
|||
public float dx; |
|||
public float dy; |
|||
} |
|||
|
|||
public class uiDrawScale : uiDrawCmd { |
|||
public float sx; |
|||
public float? sy; |
|||
} |
|||
|
|||
public class uiDrawRotate : uiDrawCmd { |
|||
public float radians; |
|||
public Offset offset; |
|||
} |
|||
|
|||
public class uiDrawSkew : uiDrawCmd { |
|||
public float sx; |
|||
public float sy; |
|||
} |
|||
|
|||
public class uiDrawConcat : uiDrawCmd { |
|||
public Matrix3 matrix; |
|||
} |
|||
|
|||
public class uiDrawResetMatrix : uiDrawCmd { |
|||
} |
|||
|
|||
public class uiDrawSetMatrix : uiDrawCmd { |
|||
public Matrix3 matrix; |
|||
} |
|||
|
|||
public class uiDrawClipRect : uiDrawCmd { |
|||
public Rect rect; |
|||
} |
|||
|
|||
public class uiDrawClipRRect : uiDrawCmd { |
|||
public RRect rrect; |
|||
} |
|||
|
|||
public class uiDrawClipPath : uiDrawCmd { |
|||
public Path path; |
|||
} |
|||
|
|||
public class uiDrawPath : uiDrawCmd { |
|||
public Path path; |
|||
public Paint paint; |
|||
} |
|||
|
|||
public class uiDrawImage : uiDrawCmd { |
|||
public Image image; |
|||
public Offset offset; |
|||
public Paint paint; |
|||
} |
|||
|
|||
public class uiDrawImageRect : uiDrawCmd { |
|||
public Image image; |
|||
public Rect src; |
|||
public Rect dst; |
|||
public Paint paint; |
|||
} |
|||
|
|||
public class uiDrawImageNine : uiDrawCmd { |
|||
public Image image; |
|||
public Rect src; |
|||
public Rect center; |
|||
public Rect dst; |
|||
public Paint paint; |
|||
} |
|||
|
|||
public class uiDrawPicture : uiDrawCmd { |
|||
public Picture picture; |
|||
} |
|||
|
|||
public class uiDrawTextBlob : uiDrawCmd { |
|||
public TextBlob textBlob; |
|||
public Offset offset; |
|||
public Paint paint; |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
|
|||
|
|||
namespace Unity.UIWidgets.ui { |
|||
public class uiPicture { |
|||
public uiPicture(List<uiDrawCmd> drawCmds, Rect paintBounds) { |
|||
this.drawCmds = drawCmds; |
|||
this.paintBounds = paintBounds; |
|||
} |
|||
|
|||
public readonly List<uiDrawCmd> drawCmds; |
|||
public readonly Rect paintBounds; |
|||
} |
|||
|
|||
public class uiPictureRecorder { |
|||
readonly List<uiDrawCmd> _drawCmds = new List<uiDrawCmd>(); |
|||
|
|||
readonly List<uiCanvasState> _states = new List<uiCanvasState>(); |
|||
|
|||
public uiPictureRecorder() { |
|||
this.reset(); |
|||
} |
|||
|
|||
uiCanvasState _getState() { |
|||
D.assert(this._states.Count > 0); |
|||
return this._states[this._states.Count - 1]; |
|||
} |
|||
|
|||
public Matrix3 getTotalMatrix() { |
|||
return this._getState().xform; |
|||
} |
|||
|
|||
public void reset() { |
|||
this._drawCmds.Clear(); |
|||
this._states.Clear(); |
|||
this._states.Add(new uiCanvasState { |
|||
xform = Matrix3.I(), |
|||
scissor = null, |
|||
saveLayer = false, |
|||
layerOffset = null, |
|||
paintBounds = Rect.zero, |
|||
}); |
|||
} |
|||
|
|||
public uiPicture endRecording() { |
|||
if (this._states.Count > 1) { |
|||
throw new Exception("unmatched save/restore commands"); |
|||
} |
|||
|
|||
var state = this._getState(); |
|||
return new uiPicture(new List<uiDrawCmd>(this._drawCmds), state.paintBounds); |
|||
} |
|||
|
|||
public void addDrawCmd(uiDrawCmd drawCmd) { |
|||
this._drawCmds.Add(drawCmd); |
|||
|
|||
switch (drawCmd) { |
|||
case uiDrawSave _: |
|||
this._states.Add(this._getState().copy()); |
|||
break; |
|||
case uiDrawSaveLayer cmd: { |
|||
this._states.Add(new uiCanvasState { |
|||
xform = Matrix3.I(), |
|||
scissor = cmd.rect.shift(-cmd.rect.topLeft), |
|||
saveLayer = true, |
|||
layerOffset = cmd.rect.topLeft, |
|||
paintBounds = Rect.zero, |
|||
}); |
|||
break; |
|||
} |
|||
case uiDrawRestore _: { |
|||
var stateToRestore = this._getState(); |
|||
this._states.RemoveAt(this._states.Count - 1); |
|||
var state = this._getState(); |
|||
|
|||
if (!stateToRestore.saveLayer) { |
|||
state.paintBounds = stateToRestore.paintBounds; |
|||
} else { |
|||
var paintBounds = stateToRestore.paintBounds.shift(stateToRestore.layerOffset); |
|||
paintBounds = state.xform.mapRect(paintBounds); |
|||
this._addPaintBounds(paintBounds); |
|||
} |
|||
break; |
|||
} |
|||
case uiDrawTranslate cmd: { |
|||
var state = this._getState(); |
|||
state.xform = new Matrix3(state.xform); |
|||
state.xform.preTranslate(cmd.dx, cmd.dy); |
|||
break; |
|||
} |
|||
case uiDrawScale cmd: { |
|||
var state = this._getState(); |
|||
state.xform = new Matrix3(state.xform); |
|||
state.xform.preScale(cmd.sx, (cmd.sy ?? cmd.sx)); |
|||
break; |
|||
} |
|||
case uiDrawRotate cmd: { |
|||
var state = this._getState(); |
|||
state.xform = new Matrix3(state.xform); |
|||
if (cmd.offset == null) { |
|||
state.xform.preRotate(cmd.radians); |
|||
} else { |
|||
state.xform.preRotate(cmd.radians, |
|||
cmd.offset.dx, |
|||
cmd.offset.dy); |
|||
} |
|||
break; |
|||
} |
|||
case uiDrawSkew cmd: { |
|||
var state = this._getState(); |
|||
state.xform = new Matrix3(state.xform); |
|||
state.xform.preSkew(cmd.sx, cmd.sy); |
|||
break; |
|||
} |
|||
case uiDrawConcat cmd: { |
|||
var state = this._getState(); |
|||
state.xform = new Matrix3(state.xform); |
|||
state.xform.preConcat(cmd.matrix); |
|||
break; |
|||
} |
|||
case uiDrawResetMatrix _: { |
|||
var state = this._getState(); |
|||
state.xform = Matrix3.I(); |
|||
break; |
|||
} |
|||
case uiDrawSetMatrix cmd: { |
|||
var state = this._getState(); |
|||
state.xform = new Matrix3(cmd.matrix); |
|||
break; |
|||
} |
|||
case uiDrawClipRect cmd: { |
|||
var state = this._getState(); |
|||
|
|||
var rect = state.xform.mapRect(cmd.rect); |
|||
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect); |
|||
break; |
|||
} |
|||
case uiDrawClipRRect cmd: { |
|||
var state = this._getState(); |
|||
|
|||
var rect = state.xform.mapRect(cmd.rrect.outerRect); |
|||
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect); |
|||
break; |
|||
} |
|||
case uiDrawClipPath cmd: { |
|||
var state = this._getState(); |
|||
var scale = XformUtils.getScale(state.xform); |
|||
|
|||
var rect = cmd.path.flatten( |
|||
scale * Window.instance.devicePixelRatio |
|||
).getFillMesh(out _).transform(state.xform).bounds; |
|||
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect); |
|||
break; |
|||
} |
|||
case uiDrawPath cmd: { |
|||
var state = this._getState(); |
|||
var scale = XformUtils.getScale(state.xform); |
|||
var path = cmd.path; |
|||
var paint = cmd.paint; |
|||
var devicePixelRatio = Window.instance.devicePixelRatio; |
|||
|
|||
MeshMesh mesh; |
|||
if (paint.style == PaintingStyle.fill) { |
|||
var cache = path.flatten(scale * devicePixelRatio); |
|||
mesh = cache.getFillMesh(out _).transform(state.xform); |
|||
} else { |
|||
float strokeWidth = (paint.strokeWidth * scale).clamp(0, 200.0f); |
|||
float fringeWidth = 1 / devicePixelRatio; |
|||
|
|||
if (strokeWidth < fringeWidth) { |
|||
strokeWidth = fringeWidth; |
|||
} |
|||
|
|||
var cache = path.flatten(scale * devicePixelRatio); |
|||
mesh = cache.getStrokeMesh( |
|||
strokeWidth / scale * 0.5f, |
|||
paint.strokeCap, |
|||
paint.strokeJoin, |
|||
paint.strokeMiterLimit).transform(state.xform); |
|||
} |
|||
|
|||
if (paint.maskFilter != null && paint.maskFilter.sigma != 0) { |
|||
float sigma = scale * paint.maskFilter.sigma; |
|||
float sigma3 = 3 * sigma; |
|||
this._addPaintBounds(mesh.bounds.inflate(sigma3)); |
|||
} else { |
|||
this._addPaintBounds(mesh.bounds); |
|||
} |
|||
break; |
|||
} |
|||
case uiDrawImage 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 uiDrawImageRect cmd: { |
|||
var state = this._getState(); |
|||
var rect = state.xform.mapRect(cmd.dst); |
|||
this._addPaintBounds(rect); |
|||
break; |
|||
} |
|||
case uiDrawImageNine cmd: { |
|||
var state = this._getState(); |
|||
var rect = state.xform.mapRect(cmd.dst); |
|||
this._addPaintBounds(rect); |
|||
break; |
|||
} |
|||
case uiDrawPicture cmd: { |
|||
var state = this._getState(); |
|||
var rect = state.xform.mapRect(cmd.picture.paintBounds); |
|||
this._addPaintBounds(rect); |
|||
break; |
|||
} |
|||
case uiDrawTextBlob cmd: { |
|||
var state = this._getState(); |
|||
var scale = XformUtils.getScale(state.xform); |
|||
var rect = cmd.textBlob.boundsInText.shift(cmd.offset); |
|||
rect = state.xform.mapRect(rect); |
|||
|
|||
var paint = cmd.paint; |
|||
if (paint.maskFilter != null && paint.maskFilter.sigma != 0) { |
|||
float sigma = scale * paint.maskFilter.sigma; |
|||
float sigma3 = 3 * sigma; |
|||
this._addPaintBounds(rect.inflate(sigma3)); |
|||
} else { |
|||
this._addPaintBounds(rect); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
default: |
|||
throw new Exception("unknown drawCmd: " + drawCmd); |
|||
} |
|||
} |
|||
|
|||
void _addPaintBounds(Rect paintBounds) { |
|||
var state = this._getState(); |
|||
if (state.scissor != null) { |
|||
paintBounds = paintBounds.intersect(state.scissor); |
|||
} |
|||
|
|||
if (paintBounds == null || paintBounds.isEmpty) { |
|||
return; |
|||
} |
|||
|
|||
if (state.paintBounds.isEmpty) { |
|||
state.paintBounds = paintBounds; |
|||
} else { |
|||
state.paintBounds = state.paintBounds.expandToInclude(paintBounds); |
|||
} |
|||
} |
|||
|
|||
class uiCanvasState { |
|||
public Matrix3 xform; |
|||
public Rect scissor; |
|||
public bool saveLayer; |
|||
public Offset layerOffset; |
|||
public Rect paintBounds; |
|||
|
|||
public uiCanvasState copy() { |
|||
return new uiCanvasState { |
|||
xform = this.xform, |
|||
scissor = this.scissor, |
|||
saveLayer = false, |
|||
layerOffset = null, |
|||
paintBounds = this.paintBounds, |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a68726f5c264a40e8a0ab3cf5c5170cb |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using UnityEngine; |
|||
using UnityEngine.Rendering; |
|||
|
|||
namespace Unity.UIWidgets.ui { |
|||
public partial class PictureFlusher { |
|||
readonly RenderTexture _renderTexture; |
|||
readonly float _fringeWidth; |
|||
readonly float _devicePixelRatio; |
|||
readonly MeshPool _meshPool; |
|||
|
|||
readonly List<RenderLayer> _layers = new List<RenderLayer>(); |
|||
RenderLayer _currentLayer; |
|||
uiRect? _lastScissor; |
|||
|
|||
public void dispose() { |
|||
if (this._currentLayer != null) { |
|||
this._clearLayer(this._currentLayer); |
|||
this._currentLayer.dispose(); |
|||
this._currentLayer = null; |
|||
this._lastScissor = null; |
|||
this._layers.Clear(); |
|||
} |
|||
} |
|||
|
|||
public PictureFlusher(RenderTexture renderTexture, float devicePixelRatio, MeshPool meshPool) { |
|||
D.assert(renderTexture); |
|||
D.assert(devicePixelRatio > 0); |
|||
D.assert(meshPool != null); |
|||
|
|||
this._renderTexture = renderTexture; |
|||
this._fringeWidth = 1.0f / devicePixelRatio; |
|||
this._devicePixelRatio = devicePixelRatio; |
|||
this._meshPool = meshPool; |
|||
} |
|||
|
|||
public float getDevicePixelRatio() { |
|||
return this._devicePixelRatio; |
|||
} |
|||
|
|||
void _reset() { |
|||
//clear all states
|
|||
D.assert(this._layers.Count == 0 || (this._layers.Count == 1 && this._layers[0] == this._currentLayer)); |
|||
if (this._currentLayer != null) { |
|||
this._clearLayer(this._currentLayer); |
|||
this._currentLayer.dispose(); |
|||
this._currentLayer = null; |
|||
this._lastScissor = null; |
|||
this._layers.Clear(); |
|||
} |
|||
|
|||
var width = this._renderTexture.width; |
|||
var height = this._renderTexture.height; |
|||
|
|||
var bounds = uiRectHelper.fromLTWH(0, 0, |
|||
width * this._fringeWidth, |
|||
height * this._fringeWidth); |
|||
|
|||
RenderLayer firstLayer = RenderLayer.create( |
|||
width: width, |
|||
height: height, |
|||
layerBounds: bounds |
|||
); |
|||
|
|||
this._layers.Add(firstLayer); |
|||
this._currentLayer = firstLayer; |
|||
} |
|||
|
|||
void _save() { |
|||
var layer = this._currentLayer; |
|||
layer.currentState = layer.currentState.copy(); |
|||
layer.states.Add(layer.currentState); |
|||
layer.clipStack.save(); |
|||
} |
|||
|
|||
readonly uiOffset[] _saveLayer_Points = new uiOffset[4]; |
|||
|
|||
void _saveLayer(uiRect bounds, Paint paint) { |
|||
D.assert(bounds.width > 0); |
|||
D.assert(bounds.height > 0); |
|||
D.assert(paint != null); |
|||
|
|||
var parentLayer = this._currentLayer; |
|||
var state = parentLayer.currentState; |
|||
var textureWidth = Mathf.CeilToInt( |
|||
bounds.width * state.scale * this._devicePixelRatio); |
|||
if (textureWidth < 1) { |
|||
textureWidth = 1; |
|||
} |
|||
|
|||
var textureHeight = Mathf.CeilToInt( |
|||
bounds.height * state.scale * this._devicePixelRatio); |
|||
if (textureHeight < 1) { |
|||
textureHeight = 1; |
|||
} |
|||
|
|||
var layer = RenderLayer.create( |
|||
rtID: Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count), |
|||
width: textureWidth, |
|||
height: textureHeight, |
|||
layerBounds: bounds, |
|||
layerPaint: paint |
|||
); |
|||
|
|||
parentLayer.addLayer(layer); |
|||
this._layers.Add(layer); |
|||
this._currentLayer = layer; |
|||
|
|||
if (paint.backdrop != null) { |
|||
if (paint.backdrop is _BlurImageFilter) { |
|||
var filter = (_BlurImageFilter) paint.backdrop; |
|||
if (!(filter.sigmaX == 0 && filter.sigmaY == 0)) { |
|||
this._saveLayer_Points[0] = bounds.topLeft; |
|||
this._saveLayer_Points[1] = bounds.bottomLeft; |
|||
this._saveLayer_Points[2] = bounds.bottomRight; |
|||
this._saveLayer_Points[3] = bounds.topRight; |
|||
|
|||
state.matrix.Value.mapPoints(this._saveLayer_Points); |
|||
|
|||
var parentBounds = parentLayer.layerBounds; |
|||
for (int i = 0; i < 4; i++) { |
|||
this._saveLayer_Points[i] = new uiOffset( |
|||
(this._saveLayer_Points[i].dx - parentBounds.left) / parentBounds.width, |
|||
(this._saveLayer_Points[i].dy - parentBounds.top) / parentBounds.height |
|||
); |
|||
} |
|||
|
|||
var mesh = ImageMeshGenerator.imageMesh( |
|||
null, |
|||
this._saveLayer_Points[0], |
|||
this._saveLayer_Points[1], |
|||
this._saveLayer_Points[2], |
|||
this._saveLayer_Points[3], |
|||
bounds); |
|||
var renderDraw = CanvasShader.texRT(layer, layer.layerPaint, mesh, parentLayer); |
|||
layer.draws.Add(renderDraw); |
|||
|
|||
var blurLayer = this._createBlurLayer(layer, filter.sigmaX, filter.sigmaY, layer); |
|||
var blurMesh = ImageMeshGenerator.imageMesh(null, uiRectHelper.one, bounds); |
|||
layer.draws.Add(CanvasShader.texRT(layer, paint, blurMesh, blurLayer)); |
|||
} |
|||
} |
|||
else if (paint.backdrop is _MatrixImageFilter) { |
|||
var filter = (_MatrixImageFilter) paint.backdrop; |
|||
if (!filter.transform.isIdentity()) { |
|||
layer.filterMode = filter.filterMode; |
|||
|
|||
this._saveLayer_Points[0] = bounds.topLeft; |
|||
this._saveLayer_Points[1] = bounds.bottomLeft; |
|||
this._saveLayer_Points[2] = bounds.bottomRight; |
|||
this._saveLayer_Points[3] = bounds.topRight; |
|||
state.matrix.Value.mapPoints(this._saveLayer_Points); |
|||
|
|||
var parentBounds = parentLayer.layerBounds; |
|||
for (int i = 0; i < 4; i++) { |
|||
this._saveLayer_Points[i] = new uiOffset( |
|||
(this._saveLayer_Points[i].dx - parentBounds.left) / parentBounds.width, |
|||
(this._saveLayer_Points[i].dy - parentBounds.top) / parentBounds.height |
|||
); |
|||
} |
|||
|
|||
var matrix = uiMatrix3.makeTrans(-bounds.left, -bounds.top); |
|||
matrix.postConcat(uiMatrix3.fromMatrix3(filter.transform)); |
|||
matrix.postTranslate(bounds.left, bounds.top); |
|||
|
|||
var mesh = ImageMeshGenerator.imageMesh( |
|||
matrix, |
|||
this._saveLayer_Points[0], |
|||
this._saveLayer_Points[1], |
|||
this._saveLayer_Points[2], |
|||
this._saveLayer_Points[3], |
|||
bounds); |
|||
var renderDraw = CanvasShader.texRT(layer, layer.layerPaint, mesh, parentLayer); |
|||
layer.draws.Add(renderDraw); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void _restore() { |
|||
var layer = this._currentLayer; |
|||
D.assert(layer.states.Count > 0); |
|||
if (layer.states.Count > 1) { |
|||
layer.states[layer.states.Count - 1].dispose(); |
|||
layer.states.RemoveAt(layer.states.Count - 1); |
|||
layer.currentState = layer.states[layer.states.Count - 1]; |
|||
layer.clipStack.restore(); |
|||
return; |
|||
} |
|||
|
|||
this._layers.RemoveAt(this._layers.Count - 1); |
|||
var currentLayer = this._currentLayer = this._layers[this._layers.Count - 1]; |
|||
var state = currentLayer.currentState; |
|||
|
|||
var mesh = ImageMeshGenerator.imageMesh(state.matrix, uiRectHelper.one, layer.layerBounds); |
|||
|
|||
if (!this._applyClip(mesh.bounds)) { |
|||
mesh.dispose(); |
|||
return; |
|||
} |
|||
|
|||
var renderDraw = CanvasShader.texRT(currentLayer, layer.layerPaint, mesh, layer); |
|||
currentLayer.draws.Add(renderDraw); |
|||
} |
|||
|
|||
void _translate(float dx, float dy) { |
|||
var state = this._currentLayer.currentState; |
|||
var matrix = uiMatrix3.makeTrans(dx, dy); |
|||
matrix.postConcat(state.matrix.Value); |
|||
state.matrix = matrix; |
|||
} |
|||
|
|||
void _scale(float sx, float? sy = null) { |
|||
var state = this._currentLayer.currentState; |
|||
var matrix = uiMatrix3.makeScale(sx, (sy ?? sx)); |
|||
matrix.postConcat(state.matrix.Value); |
|||
state.matrix = matrix; |
|||
} |
|||
|
|||
void _rotate(float radians, uiOffset? offset = null) { |
|||
var state = this._currentLayer.currentState; |
|||
if (offset == null) { |
|||
var matrix = uiMatrix3.makeRotate(radians); |
|||
matrix.postConcat(state.matrix.Value); |
|||
state.matrix = matrix; |
|||
} |
|||
else { |
|||
var matrix = uiMatrix3.makeRotate(radians, offset.Value.dx, offset.Value.dy); |
|||
matrix.postConcat(state.matrix.Value); |
|||
state.matrix = matrix; |
|||
} |
|||
} |
|||
|
|||
void _skew(float sx, float sy) { |
|||
var state = this._currentLayer.currentState; |
|||
var matrix = uiMatrix3.makeSkew(sx, sy); |
|||
matrix.postConcat(state.matrix.Value); |
|||
state.matrix = matrix; |
|||
} |
|||
|
|||
void _concat(uiMatrix3 matrix) { |
|||
var state = this._currentLayer.currentState; |
|||
matrix = new uiMatrix3(matrix); |
|||
matrix.postConcat(state.matrix.Value); |
|||
state.matrix = matrix; |
|||
} |
|||
|
|||
void _resetMatrix() { |
|||
var state = this._currentLayer.currentState; |
|||
state.matrix = uiMatrix3.I(); |
|||
} |
|||
|
|||
void _setMatrix(uiMatrix3 matrix) { |
|||
var state = this._currentLayer.currentState; |
|||
state.matrix = new uiMatrix3(matrix); |
|||
} |
|||
|
|||
void _clipRect(Rect rect) { |
|||
var path = uiPath.create(); |
|||
path.addRect(rect); |
|||
this._clipPath(path); |
|||
} |
|||
|
|||
void _clipRRect(RRect rrect) { |
|||
var path = uiPath.create(); |
|||
path.addRRect(rrect); |
|||
this._clipPath(path); |
|||
} |
|||
|
|||
void _clipPath(uiPath path) { |
|||
var layer = this._currentLayer; |
|||
var state = layer.currentState; |
|||
layer.clipStack.clipPath(path, state.matrix.Value, state.scale * this._devicePixelRatio); |
|||
path.dispose(); |
|||
} |
|||
|
|||
void _tryAddScissor(RenderLayer layer, uiRect? scissor) { |
|||
if (uiRectHelper.equals(scissor, this._lastScissor)) { |
|||
return; |
|||
} |
|||
|
|||
layer.draws.Add(CmdScissor.create( |
|||
deviceScissor: scissor |
|||
)); |
|||
this._lastScissor = scissor; |
|||
} |
|||
|
|||
bool _applyClip(uiRect? queryBounds) { |
|||
if (queryBounds == null || queryBounds.Value.isEmpty) { |
|||
return false; |
|||
} |
|||
|
|||
var layer = this._currentLayer; |
|||
var layerBounds = layer.layerBounds; |
|||
ReducedClip reducedClip = ReducedClip.create(layer.clipStack, layerBounds, queryBounds.Value); |
|||
if (reducedClip.isEmpty()) { |
|||
reducedClip.dispose(); |
|||
return false; |
|||
} |
|||
|
|||
var scissor = reducedClip.scissor; |
|||
var physicalRect = uiRectHelper.fromLTRB(0, 0, layer.width, layer.height); |
|||
|
|||
if (uiRectHelper.equals(scissor,layerBounds)) { |
|||
this._tryAddScissor(layer, null); |
|||
} |
|||
else { |
|||
var deviceScissor = uiRectHelper.fromLTRB( |
|||
scissor.Value.left - layerBounds.left, layerBounds.bottom - scissor.Value.bottom, |
|||
scissor.Value.right - layerBounds.left, layerBounds.bottom - scissor.Value.top |
|||
); |
|||
deviceScissor = uiRectHelper.scale(deviceScissor, layer.width / layerBounds.width, layer.height / layerBounds.height); |
|||
deviceScissor = uiRectHelper.roundOut(deviceScissor); |
|||
deviceScissor = uiRectHelper.intersect(deviceScissor, physicalRect); |
|||
|
|||
if (deviceScissor.isEmpty) { |
|||
reducedClip.dispose(); |
|||
return false; |
|||
} |
|||
|
|||
this._tryAddScissor(layer, deviceScissor); |
|||
} |
|||
|
|||
var maskGenID = reducedClip.maskGenID(); |
|||
if (this._mustRenderClip(maskGenID, reducedClip.scissor.Value)) { |
|||
if (maskGenID == ClipStack.wideOpenGenID) { |
|||
layer.ignoreClip = true; |
|||
} |
|||
else { |
|||
layer.ignoreClip = false; |
|||
|
|||
// need to inflate a bit to make sure all area is cleared.
|
|||
var inflatedScissor = uiRectHelper.inflate(reducedClip.scissor.Value, this._fringeWidth); |
|||
var boundsMesh = uiMeshMesh.create(inflatedScissor); |
|||
layer.draws.Add(CanvasShader.stencilClear(layer, boundsMesh)); |
|||
|
|||
foreach (var maskElement in reducedClip.maskElements) { |
|||
layer.draws.Add(CanvasShader.stencil0(layer, maskElement.mesh.duplicate())); |
|||
layer.draws.Add(CanvasShader.stencil1(layer, boundsMesh.duplicate())); |
|||
} |
|||
} |
|||
|
|||
this._setLastClipGenId(maskGenID, reducedClip.scissor.Value); |
|||
} |
|||
|
|||
reducedClip.dispose(); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void _setLastClipGenId(uint clipGenId, uiRect clipBounds) { |
|||
var layer = this._currentLayer; |
|||
layer.lastClipGenId = clipGenId; |
|||
layer.lastClipBounds = clipBounds; |
|||
} |
|||
|
|||
bool _mustRenderClip(uint clipGenId, uiRect clipBounds) { |
|||
var layer = this._currentLayer; |
|||
return layer.lastClipGenId != clipGenId || !uiRectHelper.equals(layer.lastClipBounds, clipBounds); |
|||
} |
|||
|
|||
RenderLayer _createMaskLayer(RenderLayer parentLayer, uiRect maskBounds, _drawPathDrawMeshCallbackDelegate drawCallback, |
|||
Paint paint, bool convex, float alpha, Texture tex, uiRect texBound, TextBlobMesh textMesh, uiMeshMesh mesh) { |
|||
var textureWidth = Mathf.CeilToInt(maskBounds.width * this._devicePixelRatio); |
|||
if (textureWidth < 1) { |
|||
textureWidth = 1; |
|||
} |
|||
|
|||
var textureHeight = Mathf.CeilToInt(maskBounds.height * this._devicePixelRatio); |
|||
if (textureHeight < 1) { |
|||
textureHeight = 1; |
|||
} |
|||
|
|||
var maskLayer = RenderLayer.create( |
|||
rtID: Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count), |
|||
width: textureWidth, |
|||
height: textureHeight, |
|||
layerBounds: maskBounds, |
|||
filterMode: FilterMode.Bilinear, |
|||
noMSAA: true |
|||
); |
|||
|
|||
parentLayer.addLayer(maskLayer); |
|||
this._layers.Add(maskLayer); |
|||
this._currentLayer = maskLayer; |
|||
|
|||
var parentState = parentLayer.states[parentLayer.states.Count - 1]; |
|||
var maskState = maskLayer.states[maskLayer.states.Count - 1]; |
|||
maskState.matrix = parentState.matrix; |
|||
|
|||
drawCallback.Invoke(Paint.shapeOnly(paint), mesh, convex, alpha, tex, texBound, textMesh); |
|||
|
|||
var removed = this._layers.removeLast(); |
|||
D.assert(removed == maskLayer); |
|||
this._currentLayer = this._layers[this._layers.Count - 1]; |
|||
|
|||
return maskLayer; |
|||
} |
|||
|
|||
RenderLayer _createBlurLayer(RenderLayer maskLayer, float sigmaX, float sigmaY, RenderLayer parentLayer) { |
|||
sigmaX = BlurUtils.adjustSigma(sigmaX, out var scaleFactorX, out var radiusX); |
|||
sigmaY = BlurUtils.adjustSigma(sigmaY, out var scaleFactorY, out var radiusY); |
|||
|
|||
var textureWidth = Mathf.CeilToInt((float) maskLayer.width / scaleFactorX); |
|||
if (textureWidth < 1) { |
|||
textureWidth = 1; |
|||
} |
|||
|
|||
var textureHeight = Mathf.CeilToInt((float) maskLayer.height / scaleFactorY); |
|||
if (textureHeight < 1) { |
|||
textureHeight = 1; |
|||
} |
|||
|
|||
var blurXLayer = RenderLayer.create( |
|||
rtID: Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count), |
|||
width: textureWidth, |
|||
height: textureHeight, |
|||
layerBounds: maskLayer.layerBounds, |
|||
filterMode: FilterMode.Bilinear, |
|||
noMSAA: true |
|||
); |
|||
|
|||
parentLayer.addLayer(blurXLayer); |
|||
|
|||
var blurYLayer = RenderLayer.create( |
|||
rtID: Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count), |
|||
width: textureWidth, |
|||
height: textureHeight, |
|||
layerBounds: maskLayer.layerBounds, |
|||
filterMode: FilterMode.Bilinear, |
|||
noMSAA: true |
|||
); |
|||
|
|||
parentLayer.addLayer(blurYLayer); |
|||
|
|||
var blurMesh = ImageMeshGenerator.imageMesh(null, uiRectHelper.one, maskLayer.layerBounds); |
|||
|
|||
var kernelX = BlurUtils.get1DGaussianKernel(sigmaX, radiusX); |
|||
var kernelY = BlurUtils.get1DGaussianKernel(sigmaY, radiusY); |
|||
|
|||
blurXLayer.draws.Add(CanvasShader.maskFilter( |
|||
blurXLayer, blurMesh, maskLayer, |
|||
radiusX, new Vector2(1f / textureWidth, 0), kernelX)); |
|||
|
|||
blurYLayer.draws.Add(CanvasShader.maskFilter( |
|||
blurYLayer, blurMesh.duplicate(), blurXLayer, |
|||
radiusY, new Vector2(0, -1f / textureHeight), kernelY)); |
|||
|
|||
return blurYLayer; |
|||
} |
|||
|
|||
void _drawWithMaskFilter(uiRect meshBounds, Paint paint, MaskFilter maskFilter, |
|||
uiMeshMesh mesh, bool convex, float alpha, Texture tex, uiRect texBound, TextBlobMesh textMesh, |
|||
_drawPathDrawMeshCallbackDelegate drawCallback) { |
|||
var layer = this._currentLayer; |
|||
var clipBounds = layer.layerBounds; |
|||
|
|||
uiRect? stackBounds; |
|||
bool iior; |
|||
layer.clipStack.getBounds(out stackBounds, out iior); |
|||
|
|||
if (stackBounds != null) { |
|||
clipBounds = uiRectHelper.intersect(clipBounds,stackBounds.Value); |
|||
} |
|||
|
|||
if (clipBounds.isEmpty) { |
|||
this._drawPathDrawMeshQuit(mesh); |
|||
return; |
|||
} |
|||
|
|||
var state = layer.currentState; |
|||
float sigma = state.scale * maskFilter.sigma; |
|||
if (sigma <= 0) { |
|||
this._drawPathDrawMeshQuit(mesh); |
|||
return; |
|||
} |
|||
|
|||
float sigma3 = 3 * sigma; |
|||
var maskBounds = uiRectHelper.inflate(meshBounds, sigma3); |
|||
maskBounds = uiRectHelper.intersect(maskBounds, uiRectHelper.inflate(clipBounds,sigma3)); |
|||
if (maskBounds.isEmpty) { |
|||
this._drawPathDrawMeshQuit(mesh); |
|||
return; |
|||
} |
|||
|
|||
var maskLayer = this._createMaskLayer(layer, maskBounds, drawCallback, paint, convex, alpha, tex, texBound, textMesh, mesh); |
|||
|
|||
var blurLayer = this._createBlurLayer(maskLayer, sigma, sigma, layer); |
|||
|
|||
var blurMesh = ImageMeshGenerator.imageMesh(null, uiRectHelper.one, maskBounds); |
|||
if (!this._applyClip(blurMesh.bounds)) { |
|||
blurMesh.dispose(); |
|||
this._drawPathDrawMeshQuit(mesh); |
|||
return; |
|||
} |
|||
|
|||
layer.draws.Add(CanvasShader.texRT(layer, paint, blurMesh, blurLayer)); |
|||
} |
|||
|
|||
delegate void _drawPathDrawMeshCallbackDelegate(Paint p, uiMeshMesh mesh, bool convex, float alpha, Texture tex, uiRect textBlobBounds, TextBlobMesh textMesh); |
|||
|
|||
void _drawPathDrawMeshCallback(Paint p, uiMeshMesh mesh, bool convex, float alpha, Texture tex, uiRect textBlobBounds, TextBlobMesh textMesh) { |
|||
if (!this._applyClip(mesh.bounds)) { |
|||
mesh.dispose(); |
|||
return; |
|||
} |
|||
|
|||
var layer = this._currentLayer; |
|||
if (convex) { |
|||
layer.draws.Add(CanvasShader.convexFill(layer, p, mesh)); |
|||
} |
|||
else { |
|||
layer.draws.Add(CanvasShader.fill0(layer, mesh)); |
|||
layer.draws.Add(CanvasShader.fill1(layer, p, mesh.boundsMesh)); |
|||
} |
|||
} |
|||
|
|||
void _drawPathDrawMeshCallback2(Paint p, uiMeshMesh mesh, bool convex, float alpha, Texture tex, uiRect textBlobBounds, TextBlobMesh textMesh) { |
|||
if (!this._applyClip(mesh.bounds)) { |
|||
mesh.dispose(); |
|||
return; |
|||
} |
|||
|
|||
var layer = this._currentLayer; |
|||
|
|||
layer.draws.Add(CanvasShader.stroke0(layer, p, alpha, mesh)); |
|||
layer.draws.Add(CanvasShader.stroke1(layer, mesh.duplicate())); |
|||
} |
|||
|
|||
void _drawTextDrawMeshCallback(Paint p, uiMeshMesh mesh, bool convex, float alpha, Texture tex, uiRect textBlobBounds, TextBlobMesh textMesh) { |
|||
if (!this._applyClip(textBlobBounds)) { |
|||
textMesh.dispose(); |
|||
return; |
|||
} |
|||
|
|||
var layer = this._currentLayer; |
|||
layer.draws.Add(CanvasShader.texAlpha(layer, p, textMesh, tex)); |
|||
} |
|||
|
|||
void _drawPathDrawMeshQuit(uiMeshMesh mesh) { |
|||
mesh.dispose(); |
|||
} |
|||
|
|||
void _drawPath(uiPath path, Paint paint) { |
|||
D.assert(path != null); |
|||
D.assert(paint != null); |
|||
|
|||
if (paint.style == PaintingStyle.fill) { |
|||
var state = this._currentLayer.currentState; |
|||
var cache = path.flatten(state.scale * this._devicePixelRatio); |
|||
path.dispose(); |
|||
|
|||
bool convex; |
|||
var fillMesh = cache.getFillMesh(out convex); |
|||
var mesh = fillMesh.transform(state.matrix); |
|||
fillMesh.dispose(); |
|||
cache.dispose(); |
|||
|
|||
if (paint.maskFilter != null && paint.maskFilter.sigma != 0) { |
|||
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter, mesh, convex, 0, null, uiRectHelper.zero, null, this._drawPathDrawMeshCallback); |
|||
return; |
|||
} |
|||
|
|||
this._drawPathDrawMeshCallback(paint, mesh, convex, 0, null, uiRectHelper.zero, null); |
|||
} |
|||
else { |
|||
var state = this._currentLayer.currentState; |
|||
float strokeWidth = (paint.strokeWidth * state.scale).clamp(0, 200.0f); |
|||
float alpha = 1.0f; |
|||
|
|||
if (strokeWidth == 0) { |
|||
strokeWidth = this._fringeWidth; |
|||
} |
|||
else if (strokeWidth < this._fringeWidth) { |
|||
// If the stroke width is less than pixel size, use alpha to emulate coverage.
|
|||
// Since coverage is area, scale by alpha*alpha.
|
|||
alpha = (strokeWidth / this._fringeWidth).clamp(0.0f, 1.0f); |
|||
alpha *= alpha; |
|||
strokeWidth = this._fringeWidth; |
|||
} |
|||
|
|||
var cache = path.flatten(state.scale * this._devicePixelRatio); |
|||
path.dispose(); |
|||
|
|||
var strokenMesh = cache.getStrokeMesh( |
|||
strokeWidth / state.scale * 0.5f, |
|||
paint.strokeCap, |
|||
paint.strokeJoin, |
|||
paint.strokeMiterLimit); |
|||
|
|||
var mesh = strokenMesh.transform(state.matrix); |
|||
strokenMesh.dispose(); |
|||
cache.dispose(); |
|||
|
|||
if (paint.maskFilter != null && paint.maskFilter.sigma != 0) { |
|||
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter, mesh, false, alpha, null, uiRectHelper.zero, null, this._drawPathDrawMeshCallback2); |
|||
return; |
|||
} |
|||
|
|||
this._drawPathDrawMeshCallback2(paint, mesh, false, alpha, null, uiRectHelper.zero, null); |
|||
} |
|||
} |
|||
|
|||
void _drawImage(Image image, uiOffset offset, Paint paint) { |
|||
D.assert(image != null); |
|||
D.assert(paint != null); |
|||
|
|||
this._drawImageRect(image, |
|||
null, |
|||
uiRectHelper.fromLTWH( |
|||
offset.dx, offset.dy, |
|||
image.width / this._devicePixelRatio, |
|||
image.height / this._devicePixelRatio), |
|||
paint); |
|||
} |
|||
|
|||
void _drawImageRect(Image image, uiRect? src, uiRect dst, Paint paint) { |
|||
D.assert(image != null); |
|||
D.assert(paint != null); |
|||
|
|||
if (src == null) { |
|||
src = uiRectHelper.one; |
|||
} |
|||
else { |
|||
src = uiRectHelper.scale(src.Value, 1f / image.width, 1f / image.height); |
|||
} |
|||
|
|||
var layer = this._currentLayer; |
|||
var state = layer.currentState; |
|||
var mesh = ImageMeshGenerator.imageMesh(state.matrix, src.Value, dst); |
|||
if (!this._applyClip(mesh.bounds)) { |
|||
mesh.dispose(); |
|||
return; |
|||
} |
|||
|
|||
layer.draws.Add(CanvasShader.tex(layer, paint, mesh, image)); |
|||
} |
|||
|
|||
void _drawImageNine(Image image, uiRect? src, uiRect center, uiRect dst, Paint paint) { |
|||
D.assert(image != null); |
|||
D.assert(paint != null); |
|||
|
|||
var scaleX = 1f / image.width; |
|||
var scaleY = 1f / image.height; |
|||
if (src == null) { |
|||
src = uiRectHelper.one; |
|||
} |
|||
else { |
|||
src = uiRectHelper.scale(src.Value, scaleX, scaleY); |
|||
} |
|||
|
|||
center = uiRectHelper.scale(center, scaleX, scaleY); |
|||
|
|||
var layer = this._currentLayer; |
|||
var state = layer.currentState; |
|||
|
|||
var mesh = ImageMeshGenerator.imageNineMesh(state.matrix, src.Value, center, image.width, image.height, dst); |
|||
if (!this._applyClip(mesh.bounds)) { |
|||
mesh.dispose(); |
|||
return; |
|||
} |
|||
|
|||
layer.draws.Add(CanvasShader.tex(layer, paint, mesh, image)); |
|||
} |
|||
|
|||
void _drawPicture(Picture picture, bool needsSave = true) { |
|||
if (needsSave) { |
|||
this._save(); |
|||
} |
|||
|
|||
int saveCount = 0; |
|||
|
|||
var drawCmds = picture.drawCmds; |
|||
foreach (var drawCmd in drawCmds) { |
|||
switch (drawCmd) { |
|||
case DrawSave _: |
|||
saveCount++; |
|||
this._save(); |
|||
break; |
|||
case DrawSaveLayer cmd: { |
|||
saveCount++; |
|||
this._saveLayer(uiRectHelper.fromRect(cmd.rect), cmd.paint); |
|||
break; |
|||
} |
|||
case DrawRestore _: { |
|||
saveCount--; |
|||
if (saveCount < 0) { |
|||
throw new Exception("unmatched save/restore in picture"); |
|||
} |
|||
|
|||
this._restore(); |
|||
break; |
|||
} |
|||
case DrawTranslate cmd: { |
|||
this._translate(cmd.dx, cmd.dy); |
|||
break; |
|||
} |
|||
case DrawScale cmd: { |
|||
this._scale(cmd.sx, cmd.sy); |
|||
break; |
|||
} |
|||
case DrawRotate cmd: { |
|||
this._rotate(cmd.radians, uiOffset.fromOffset(cmd.offset)); |
|||
break; |
|||
} |
|||
case DrawSkew cmd: { |
|||
this._skew(cmd.sx, cmd.sy); |
|||
break; |
|||
} |
|||
case DrawConcat cmd: { |
|||
this._concat(uiMatrix3.fromMatrix3(cmd.matrix)); |
|||
break; |
|||
} |
|||
case DrawResetMatrix _: |
|||
this._resetMatrix(); |
|||
break; |
|||
case DrawSetMatrix cmd: { |
|||
this._setMatrix(uiMatrix3.fromMatrix3(cmd.matrix)); |
|||
break; |
|||
} |
|||
case DrawClipRect cmd: { |
|||
this._clipRect(cmd.rect); |
|||
break; |
|||
} |
|||
case DrawClipRRect cmd: { |
|||
this._clipRRect(cmd.rrect); |
|||
break; |
|||
} |
|||
case DrawClipPath cmd: { |
|||
var uipath = uiPath.fromPath(cmd.path); |
|||
this._clipPath(uipath); |
|||
break; |
|||
} |
|||
case DrawPath cmd: { |
|||
var uipath = uiPath.fromPath(cmd.path); |
|||
this._drawPath(uipath, cmd.paint); |
|||
break; |
|||
} |
|||
case DrawImage cmd: { |
|||
this._drawImage(cmd.image, (uiOffset.fromOffset(cmd.offset)).Value, cmd.paint); |
|||
break; |
|||
} |
|||
case DrawImageRect cmd: { |
|||
this._drawImageRect(cmd.image, uiRectHelper.fromRect(cmd.src), uiRectHelper.fromRect(cmd.dst), cmd.paint); |
|||
break; |
|||
} |
|||
case DrawImageNine cmd: { |
|||
this._drawImageNine(cmd.image, uiRectHelper.fromRect(cmd.src), uiRectHelper.fromRect(cmd.center), uiRectHelper.fromRect(cmd.dst), cmd.paint); |
|||
break; |
|||
} |
|||
case DrawPicture cmd: { |
|||
this._drawPicture(cmd.picture); |
|||
break; |
|||
} |
|||
case DrawTextBlob cmd: { |
|||
this._drawTextBlob(cmd.textBlob, (uiOffset.fromOffset(cmd.offset)).Value, cmd.paint); |
|||
break; |
|||
} |
|||
default: |
|||
throw new Exception("unknown drawCmd: " + drawCmd); |
|||
} |
|||
} |
|||
|
|||
if (saveCount != 0) { |
|||
throw new Exception("unmatched save/restore in picture"); |
|||
} |
|||
|
|||
if (needsSave) { |
|||
this._restore(); |
|||
} |
|||
} |
|||
|
|||
void _drawTextBlob(TextBlob textBlob, uiOffset offset, Paint paint) { |
|||
D.assert(textBlob != null); |
|||
D.assert(paint != null); |
|||
|
|||
var state = this._currentLayer.currentState; |
|||
var scale = state.scale * this._devicePixelRatio; |
|||
|
|||
var matrix = new uiMatrix3(state.matrix.Value); |
|||
matrix.preTranslate(offset.dx, offset.dy); |
|||
|
|||
var mesh = TextBlobMesh.create(textBlob, scale, matrix); |
|||
var textBlobBounds = matrix.mapRect(uiRectHelper.fromRect(textBlob.boundsInText)); |
|||
|
|||
// request font texture so text mesh could be generated correctly
|
|||
var style = textBlob.style; |
|||
var font = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle).font; |
|||
var fontSizeToLoad = Mathf.CeilToInt(style.UnityFontSize * scale); |
|||
var subText = textBlob.text.Substring(textBlob.textOffset, textBlob.textSize); |
|||
font.RequestCharactersInTextureSafe(subText, fontSizeToLoad, style.UnityFontStyle); |
|||
|
|||
var tex = font.material.mainTexture; |
|||
|
|||
if (paint.maskFilter != null && paint.maskFilter.sigma != 0) { |
|||
this._drawWithMaskFilter(textBlobBounds, paint, paint.maskFilter, null, false, 0, tex, textBlobBounds, mesh, this._drawTextDrawMeshCallback); |
|||
return; |
|||
} |
|||
|
|||
this._drawTextDrawMeshCallback(paint, null, false, 0, tex, textBlobBounds, mesh); |
|||
} |
|||
|
|||
public void flush(Picture picture) { |
|||
this._reset(); |
|||
|
|||
this._drawPicture(picture, false); |
|||
|
|||
D.assert(this._layers.Count == 1); |
|||
D.assert(this._layers[0].states.Count == 1); |
|||
|
|||
var layer = this._currentLayer; |
|||
using (var cmdBuf = new CommandBuffer()) { |
|||
cmdBuf.name = "CommandBufferCanvas"; |
|||
|
|||
this._lastRtID = -1; |
|||
this._drawLayer(layer, cmdBuf); |
|||
|
|||
// this is necessary for webgl2. not sure why... just to be safe to disable the scissor.
|
|||
cmdBuf.DisableScissorRect(); |
|||
|
|||
Graphics.ExecuteCommandBuffer(cmdBuf); |
|||
} |
|||
} |
|||
|
|||
int _lastRtID; |
|||
|
|||
void _setRenderTarget(CommandBuffer cmdBuf, int rtID, ref bool toClear) { |
|||
if (this._lastRtID == rtID) { |
|||
return; |
|||
} |
|||
|
|||
this._lastRtID = rtID; |
|||
|
|||
if (rtID == 0) { |
|||
cmdBuf.SetRenderTarget(this._renderTexture); |
|||
} |
|||
else { |
|||
cmdBuf.SetRenderTarget(rtID); |
|||
} |
|||
|
|||
if (toClear) { |
|||
cmdBuf.ClearRenderTarget(true, true, UnityEngine.Color.clear); |
|||
toClear = false; |
|||
} |
|||
} |
|||
|
|||
readonly float[] _drawLayer_matArray = new float[9]; |
|||
|
|||
void _drawLayer(RenderLayer layer, CommandBuffer cmdBuf) { |
|||
bool toClear = true; |
|||
|
|||
foreach (var cmdObj in layer.draws) { |
|||
switch (cmdObj) { |
|||
case CmdLayer cmd: |
|||
var subLayer = cmd.layer; |
|||
var desc = new RenderTextureDescriptor( |
|||
subLayer.width, subLayer.height, |
|||
RenderTextureFormat.Default, 24) { |
|||
useMipMap = false, |
|||
autoGenerateMips = false, |
|||
}; |
|||
|
|||
if (this._renderTexture.antiAliasing != 0 && !subLayer.noMSAA) { |
|||
desc.msaaSamples = this._renderTexture.antiAliasing; |
|||
} |
|||
|
|||
cmdBuf.GetTemporaryRT(subLayer.rtID, desc, subLayer.filterMode); |
|||
this._drawLayer(subLayer, cmdBuf); |
|||
|
|||
break; |
|||
case CmdDraw cmd: |
|||
this._setRenderTarget(cmdBuf, layer.rtID, ref toClear); |
|||
|
|||
if (cmd.layerId != null) { |
|||
if (cmd.layerId == 0) { |
|||
cmdBuf.SetGlobalTexture(CmdDraw.texId, this._renderTexture); |
|||
} |
|||
else { |
|||
cmdBuf.SetGlobalTexture(CmdDraw.texId, cmd.layerId.Value); |
|||
} |
|||
} |
|||
|
|||
D.assert(cmd.meshObj == null); |
|||
cmd.meshObj = this._meshPool.getMesh(); |
|||
cmd.meshObjCreated = true; |
|||
|
|||
// clear triangles first in order to bypass validation in SetVertices.
|
|||
cmd.meshObj.SetTriangles((int[]) null, 0, false); |
|||
|
|||
uiMeshMesh mesh = cmd.mesh; |
|||
if (cmd.textMesh != null) { |
|||
mesh = cmd.textMesh.resovleMesh(); |
|||
} |
|||
|
|||
if (mesh == null) { |
|||
continue; |
|||
} |
|||
|
|||
D.assert(mesh.vertices.Count > 0); |
|||
cmd.meshObj.SetVertices(mesh.vertices?.data); |
|||
cmd.meshObj.SetTriangles(mesh.triangles?.data, 0, false); |
|||
cmd.meshObj.SetUVs(0, mesh.uv?.data); |
|||
|
|||
if (mesh.matrix == null) { |
|||
cmd.properties.SetFloatArray(CmdDraw.matId, CmdDraw.idMat3.fMat); |
|||
} |
|||
else { |
|||
var mat = mesh.matrix.Value; |
|||
|
|||
this._drawLayer_matArray[0] = mat.kMScaleX; |
|||
this._drawLayer_matArray[1] = mat.kMSkewX; |
|||
this._drawLayer_matArray[2] = mat.kMTransX; |
|||
this._drawLayer_matArray[3] = mat.kMSkewY; |
|||
this._drawLayer_matArray[4] = mat.kMScaleY; |
|||
this._drawLayer_matArray[5] = mat.kMTransY; |
|||
this._drawLayer_matArray[6] = mat.kMPersp0; |
|||
this._drawLayer_matArray[7] = mat.kMPersp1; |
|||
this._drawLayer_matArray[8] = mat.kMPersp2; |
|||
cmd.properties.SetFloatArray(CmdDraw.matId, this._drawLayer_matArray); |
|||
} |
|||
|
|||
cmdBuf.DrawMesh(cmd.meshObj, CmdDraw.idMat, cmd.material, 0, cmd.pass, cmd.properties.mpb); |
|||
if (cmd.layerId != null) { |
|||
cmdBuf.SetGlobalTexture(CmdDraw.texId, BuiltinRenderTextureType.None); |
|||
} |
|||
|
|||
break; |
|||
case CmdScissor cmd: |
|||
this._setRenderTarget(cmdBuf, layer.rtID, ref toClear); |
|||
|
|||
if (cmd.deviceScissor == null) { |
|||
cmdBuf.DisableScissorRect(); |
|||
} |
|||
else { |
|||
cmdBuf.EnableScissorRect(uiRectHelper.toRect(cmd.deviceScissor.Value)); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (toClear) { |
|||
this._setRenderTarget(cmdBuf, layer.rtID, ref toClear); |
|||
} |
|||
|
|||
D.assert(!toClear); |
|||
|
|||
foreach (var subLayer in layer.layers) { |
|||
cmdBuf.ReleaseTemporaryRT(subLayer.rtID); |
|||
} |
|||
} |
|||
|
|||
void _clearLayer(RenderLayer layer) { |
|||
foreach (var cmdObj in layer.draws) { |
|||
switch (cmdObj) { |
|||
case CmdDraw cmd: |
|||
if (cmd.meshObjCreated) { |
|||
this._meshPool.returnMesh(cmd.meshObj); |
|||
cmd.meshObj = null; |
|||
cmd.meshObjCreated = false; |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
cmdObj.dispose(); |
|||
} |
|||
|
|||
layer.draws.Clear(); |
|||
|
|||
foreach (var subLayer in layer.layers) { |
|||
this._clearLayer(subLayer); |
|||
subLayer.dispose(); |
|||
} |
|||
|
|||
layer.layers.Clear(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: d0406d906bb294e7790f68e3adc0655e |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 11e43dc1dd92e4c7a97e25b3f12a1017 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 9ddd3cd95755643c98042e67ba4714a3 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 9bc23aedd93fe480f989a21cd0128393 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: cddbf990158e841019601291fd04d5f8 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 967dfd4c9146e4933bc96a163a73dd9c |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 2e5b97cbd47ac784790290e5fa696f60 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 3a42c24d7ebd6429cb3147b48bf8736e |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: c97372c9ed12471459d1a3ed41a3b2fe |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 2557784b74abe7142984ee42c406a414 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: dc26305d777344a62b1f9382ec6f0ce3 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: c0cbe18d7f0874d5a9883c5a3d88f917 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 621b1d524a6164601aa043c0411e0a19 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 4116b1938a907416199eb342667c45fe |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue