|
|
|
|
|
|
|
|
|
|
readonly List<RenderLayer> _layers = new List<RenderLayer>(); |
|
|
|
RenderLayer _currentLayer; |
|
|
|
Rect _lastScissor; |
|
|
|
uiRect? _lastScissor; |
|
|
|
|
|
|
|
public void dispose() { |
|
|
|
if (this._currentLayer != null) { |
|
|
|
|
|
|
var width = this._renderTexture.width; |
|
|
|
var height = this._renderTexture.height; |
|
|
|
|
|
|
|
var bounds = Rect.fromLTWH(0, 0, |
|
|
|
var bounds = uiRectHelper.fromLTWH(0, 0, |
|
|
|
width * this._fringeWidth, |
|
|
|
height * this._fringeWidth); |
|
|
|
|
|
|
|
|
|
|
layer.clipStack.save(); |
|
|
|
} |
|
|
|
|
|
|
|
void _saveLayer(Rect bounds, Paint paint) { |
|
|
|
D.assert(bounds != null); |
|
|
|
void _saveLayer(uiRect bounds, Paint paint) { |
|
|
|
D.assert(bounds.width > 0); |
|
|
|
D.assert(bounds.height > 0); |
|
|
|
D.assert(paint != null); |
|
|
|
|
|
|
layer.draws.Add(renderDraw); |
|
|
|
|
|
|
|
var blurLayer = this._createBlurLayer(layer, filter.sigmaX, filter.sigmaY, layer); |
|
|
|
var blurMesh = ImageMeshGenerator.imageMesh(null, Rect.one, bounds); |
|
|
|
var blurMesh = ImageMeshGenerator.imageMesh(null, uiRectHelper.one, bounds); |
|
|
|
layer.draws.Add(CanvasShader.texRT(layer, paint, blurMesh, blurLayer)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
var currentLayer = this._currentLayer = this._layers[this._layers.Count - 1]; |
|
|
|
var state = currentLayer.currentState; |
|
|
|
|
|
|
|
var mesh = ImageMeshGenerator.imageMesh(state.matrix, Rect.one, layer.layerBounds); |
|
|
|
var mesh = ImageMeshGenerator.imageMesh(state.matrix, uiRectHelper.one, layer.layerBounds); |
|
|
|
|
|
|
|
if (!this._applyClip(mesh.bounds)) { |
|
|
|
mesh.dispose(); |
|
|
|
|
|
|
path.dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
void _tryAddScissor(RenderLayer layer, Rect scissor) { |
|
|
|
if (scissor == this._lastScissor) { |
|
|
|
void _tryAddScissor(RenderLayer layer, uiRect? scissor) { |
|
|
|
if (uiRectHelper.equals(scissor, this._lastScissor)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
this._lastScissor = scissor; |
|
|
|
} |
|
|
|
|
|
|
|
bool _applyClip(Rect queryBounds) { |
|
|
|
if (queryBounds == null || queryBounds.isEmpty) { |
|
|
|
bool _applyClip(uiRect? queryBounds) { |
|
|
|
if (queryBounds == null || queryBounds.Value.isEmpty) { |
|
|
|
ReducedClip reducedClip = ReducedClip.create(layer.clipStack, layerBounds, queryBounds); |
|
|
|
ReducedClip reducedClip = ReducedClip.create(layer.clipStack, layerBounds, queryBounds.Value); |
|
|
|
if (reducedClip.isEmpty()) { |
|
|
|
reducedClip.dispose(); |
|
|
|
return false; |
|
|
|
|
|
|
var physicalRect = Rect.fromLTRB(0, 0, layer.width, layer.height); |
|
|
|
var physicalRect = uiRectHelper.fromLTRB(0, 0, layer.width, layer.height); |
|
|
|
if (scissor == layerBounds) { |
|
|
|
if (uiRectHelper.equals(scissor,layerBounds)) { |
|
|
|
var deviceScissor = Rect.fromLTRB( |
|
|
|
scissor.left - layerBounds.left, layerBounds.bottom - scissor.bottom, |
|
|
|
scissor.right - layerBounds.left, layerBounds.bottom - scissor.top |
|
|
|
).scale(layer.width / layerBounds.width, layer.height / layerBounds.height); |
|
|
|
deviceScissor = deviceScissor.roundOut(); |
|
|
|
deviceScissor = deviceScissor.intersect(physicalRect); |
|
|
|
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(); |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var maskGenID = reducedClip.maskGenID(); |
|
|
|
if (this._mustRenderClip(maskGenID, reducedClip.scissor)) { |
|
|
|
if (this._mustRenderClip(maskGenID, reducedClip.scissor.Value)) { |
|
|
|
if (maskGenID == ClipStack.wideOpenGenID) { |
|
|
|
layer.ignoreClip = true; |
|
|
|
} |
|
|
|
|
|
|
// need to inflate a bit to make sure all area is cleared.
|
|
|
|
var inflatedScissor = reducedClip.scissor.inflate(this._fringeWidth); |
|
|
|
var inflatedScissor = uiRectHelper.inflate(reducedClip.scissor.Value, this._fringeWidth); |
|
|
|
var boundsMesh = uiMeshMesh.create(inflatedScissor); |
|
|
|
layer.draws.Add(CanvasShader.stencilClear(layer, boundsMesh)); |
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this._setLastClipGenId(maskGenID, reducedClip.scissor); |
|
|
|
this._setLastClipGenId(maskGenID, reducedClip.scissor.Value); |
|
|
|
} |
|
|
|
|
|
|
|
reducedClip.dispose(); |
|
|
|
|
|
|
|
|
|
|
void _setLastClipGenId(uint clipGenId, Rect clipBounds) { |
|
|
|
void _setLastClipGenId(uint clipGenId, uiRect clipBounds) { |
|
|
|
bool _mustRenderClip(uint clipGenId, Rect clipBounds) { |
|
|
|
bool _mustRenderClip(uint clipGenId, uiRect clipBounds) { |
|
|
|
return layer.lastClipGenId != clipGenId || layer.lastClipBounds != clipBounds; |
|
|
|
return layer.lastClipGenId != clipGenId || !uiRectHelper.equals(layer.lastClipBounds, clipBounds); |
|
|
|
RenderLayer _createMaskLayer(RenderLayer parentLayer, Rect maskBounds, Action<Paint> drawCallback, |
|
|
|
RenderLayer _createMaskLayer(RenderLayer parentLayer, uiRect maskBounds, Action<Paint> drawCallback, |
|
|
|
Paint paint) { |
|
|
|
var textureWidth = Mathf.CeilToInt(maskBounds.width * this._devicePixelRatio); |
|
|
|
if (textureWidth < 1) { |
|
|
|
|
|
|
|
|
|
|
parentLayer.addLayer(blurYLayer); |
|
|
|
|
|
|
|
var blurMesh = ImageMeshGenerator.imageMesh(null, Rect.one, maskLayer.layerBounds); |
|
|
|
var blurMesh = ImageMeshGenerator.imageMesh(null, uiRectHelper.one, maskLayer.layerBounds); |
|
|
|
|
|
|
|
var kernelX = BlurUtils.get1DGaussianKernel(sigmaX, radiusX); |
|
|
|
var kernelY = BlurUtils.get1DGaussianKernel(sigmaY, radiusY); |
|
|
|
|
|
|
return blurYLayer; |
|
|
|
} |
|
|
|
|
|
|
|
void _drawWithMaskFilter(Rect meshBounds, Action<Paint> drawAction, Paint paint, MaskFilter maskFilter, |
|
|
|
void _drawWithMaskFilter(uiRect meshBounds, Action<Paint> drawAction, Paint paint, MaskFilter maskFilter, |
|
|
|
Rect stackBounds; |
|
|
|
uiRect? stackBounds; |
|
|
|
clipBounds = clipBounds.intersect(stackBounds); |
|
|
|
clipBounds = uiRectHelper.intersect(clipBounds,stackBounds.Value); |
|
|
|
} |
|
|
|
|
|
|
|
if (clipBounds.isEmpty) { |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
float sigma3 = 3 * sigma; |
|
|
|
var maskBounds = meshBounds.inflate(sigma3); |
|
|
|
maskBounds = maskBounds.intersect(clipBounds.inflate(sigma3)); |
|
|
|
var maskBounds = uiRectHelper.inflate(meshBounds, sigma3); |
|
|
|
maskBounds = uiRectHelper.intersect(maskBounds, uiRectHelper.inflate(clipBounds,sigma3)); |
|
|
|
if (maskBounds.isEmpty) { |
|
|
|
onQuit?.Invoke(); |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
var blurLayer = this._createBlurLayer(maskLayer, sigma, sigma, layer); |
|
|
|
|
|
|
|
var blurMesh = ImageMeshGenerator.imageMesh(null, Rect.one, maskBounds); |
|
|
|
var blurMesh = ImageMeshGenerator.imageMesh(null, uiRectHelper.one, maskBounds); |
|
|
|
if (!this._applyClip(blurMesh.bounds)) { |
|
|
|
blurMesh.dispose(); |
|
|
|
onQuit?.Invoke(); |
|
|
|
|
|
|
|
|
|
|
this._drawImageRect(image, |
|
|
|
null, |
|
|
|
Rect.fromLTWH( |
|
|
|
uiRectHelper.fromLTWH( |
|
|
|
offset.dx, offset.dy, |
|
|
|
image.width / this._devicePixelRatio, |
|
|
|
image.height / this._devicePixelRatio), |
|
|
|
|
|
|
void _drawImageRect(Image image, Rect src, Rect dst, Paint paint) { |
|
|
|
void _drawImageRect(Image image, uiRect? src, uiRect dst, Paint paint) { |
|
|
|
D.assert(dst != null); |
|
|
|
src = Rect.one; |
|
|
|
src = uiRectHelper.one; |
|
|
|
src = src.scale(1f / image.width, 1f / image.height); |
|
|
|
src = uiRectHelper.scale(src.Value, 1f / image.width, 1f / image.height); |
|
|
|
var mesh = ImageMeshGenerator.imageMesh(state.matrix, src, dst); |
|
|
|
var mesh = ImageMeshGenerator.imageMesh(state.matrix, src.Value, dst); |
|
|
|
if (!this._applyClip(mesh.bounds)) { |
|
|
|
mesh.dispose(); |
|
|
|
return; |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void _drawImageNine(Image image, Rect src, Rect center, Rect dst, Paint paint) { |
|
|
|
void _drawImageNine(Image image, uiRect? src, uiRect center, uiRect dst, Paint paint) { |
|
|
|
D.assert(center != null); |
|
|
|
D.assert(dst != null); |
|
|
|
src = Rect.one; |
|
|
|
src = uiRectHelper.one; |
|
|
|
src = src.scale(scaleX, scaleY); |
|
|
|
src = uiRectHelper.scale(src.Value, scaleX, scaleY); |
|
|
|
center = center.scale(scaleX, scaleY); |
|
|
|
center = uiRectHelper.scale(center, scaleX, scaleY); |
|
|
|
var mesh = ImageMeshGenerator.imageNineMesh(state.matrix, src, center, image.width, image.height, dst); |
|
|
|
var mesh = ImageMeshGenerator.imageNineMesh(state.matrix, src.Value, center, image.width, image.height, dst); |
|
|
|
if (!this._applyClip(mesh.bounds)) { |
|
|
|
mesh.dispose(); |
|
|
|
return; |
|
|
|
|
|
|
break; |
|
|
|
case DrawSaveLayer cmd: { |
|
|
|
saveCount++; |
|
|
|
this._saveLayer(cmd.rect, cmd.paint); |
|
|
|
this._saveLayer(uiRectHelper.fromRect(cmd.rect), cmd.paint); |
|
|
|
break; |
|
|
|
} |
|
|
|
case DrawRestore _: { |
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
case DrawImageRect cmd: { |
|
|
|
this._drawImageRect(cmd.image, cmd.src, cmd.dst, cmd.paint); |
|
|
|
this._drawImageRect(cmd.image, uiRectHelper.fromRect(cmd.src), uiRectHelper.fromRect(cmd.dst), cmd.paint); |
|
|
|
this._drawImageNine(cmd.image, cmd.src, cmd.center, cmd.dst, cmd.paint); |
|
|
|
this._drawImageNine(cmd.image, uiRectHelper.fromRect(cmd.src), uiRectHelper.fromRect(cmd.center), uiRectHelper.fromRect(cmd.dst), cmd.paint); |
|
|
|
break; |
|
|
|
} |
|
|
|
case DrawPicture cmd: { |
|
|
|
|
|
|
matrix.preTranslate(offset.dx, offset.dy); |
|
|
|
|
|
|
|
var mesh = TextBlobMesh.create(textBlob, scale, matrix); |
|
|
|
var textBlobBounds = matrix.mapRect(textBlob.boundsInText); |
|
|
|
var textBlobBounds = matrix.mapRect(uiRectHelper.fromRect(textBlob.boundsInText)); |
|
|
|
|
|
|
|
// request font texture so text mesh could be generated correctly
|
|
|
|
var style = textBlob.style; |
|
|
|
|
|
|
cmdBuf.DisableScissorRect(); |
|
|
|
} |
|
|
|
else { |
|
|
|
cmdBuf.EnableScissorRect(cmd.deviceScissor.toRect()); |
|
|
|
cmdBuf.EnableScissorRect(uiRectHelper.toRect(cmd.deviceScissor.Value)); |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|