浏览代码

Filter records with r tree.

/main
Yuncong Zhang 5 年前
当前提交
790015f8
共有 7 个文件被更改,包括 254 次插入116 次删除
  1. 73
      Runtime/external/RTree.cs
  2. 73
      Runtime/ui/painting/draw_cmd.cs
  3. 31
      Runtime/ui/painting/picture.cs
  4. 90
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
  5. 69
      Runtime/ui/renderer/common/draw_cmd.cs
  6. 8
      Runtime/ui/renderer/common/geometry/rect.cs
  7. 26
      Runtime/ui/renderer/common/picture.cs

73
Runtime/external/RTree.cs


{
public interface ISpatialData
{
ref readonly Rect Rect { get; }
uiRect bounds { get; }
public class IndexedRect : ISpatialData
{
private uiRect _bounds;
public uiRect bounds
{
get { return _bounds; }
}
public readonly int index;
public IndexedRect(uiRect bounds, int index)
{
this._bounds = bounds;
this.index = index;
}
}
/// <summary>
/// Non-generic class to produce instances of the generic class,

}
}
public class RTree<T> where T : ISpatialData
public interface BBoxHierarchy<T> where T : ISpatialData
{
IReadOnlyList<T> Search(in uiRect boundingBox);
void BulkLoad(IEnumerable<T> items);
}
public class RTree<T> : BBoxHierarchy<T> where T : ISpatialData
private Rect _Rect;
private uiRect _Rect;
internal RTreeNode(List<ISpatialData> items, int height)
{

public IReadOnlyList<ISpatialData> Children => children;
public int Height { get; }
public bool IsLeaf => Height == 1;
public ref readonly Rect Rect => ref _Rect;
public uiRect bounds => _Rect;
_Rect = Rect.expandToInclude(node.Rect);
_Rect = bounds.expandToInclude(node.bounds);
}
internal void Remove(ISpatialData node)

}
#region Search
private List<T> DoSearch(in Rect boundingBox)
private List<T> DoSearch(in uiRect boundingBox)
if (!Root.Rect.overlaps(boundingBox))
if (!uiRectHelper.overlaps(Root.bounds, boundingBox))
return new List<T>();
var intersections = new List<T>();

if (item.IsLeaf)
{
foreach (var leafChildItem in item.children.Cast<T>())
if (leafChildItem.Rect.overlaps(boundingBox))
if (uiRectHelper.overlaps(leafChildItem.bounds, boundingBox))
if (child.Rect.overlaps(boundingBox))
if (uiRectHelper.overlaps(child.bounds, boundingBox))
queue.Enqueue(child);
}
}

#endregion
private static Rect GetEnclosingRect(IEnumerable<ISpatialData> items)
private static uiRect GetEnclosingRect(IEnumerable<ISpatialData> items)
var rect = Rect.zero;
foreach (var data in items) rect = rect.expandToInclude(data.Rect);
return rect;
var uiRect = uiRectHelper.zero;
foreach (var data in items) uiRect = uiRect.expandToInclude(data.bounds);
return uiRect;
}
private List<T> GetAllChildren(List<T> list, RTreeNode n)

#region Sort Functions
private static readonly IComparer<ISpatialData> CompareMinX =
ProjectionComparer<ISpatialData>.Create(d => d.Rect.left);
ProjectionComparer<ISpatialData>.Create(d => d.bounds.left);
ProjectionComparer<ISpatialData>.Create(d => d.Rect.top);
ProjectionComparer<ISpatialData>.Create(d => d.bounds.top);
private List<RTreeNode> FindCoveringArea(in Rect area, int depth)
private List<RTreeNode> FindCoveringArea(in uiRect area, int depth)
{
var path = new List<RTreeNode>();
var node = Root;

node = node.children
.Select(c => new
{EnlargedArea = c.Rect.expandToInclude(_area).area, c.Rect.area, Node = c as RTreeNode})
{EnlargedArea = c.bounds.expandToInclude(_area).area, c.bounds.area, Node = c as RTreeNode})
.OrderBy(x => x.EnlargedArea)
.ThenBy(x => x.area)
.Select(x => x.Node)

private void Insert(ISpatialData data, int depth)
{
var path = FindCoveringArea(data.Rect, depth);
var path = FindCoveringArea(data.bounds, depth);
var insertNode = path.Last();
insertNode.Add(data);

private float GetPotentialEnclosingMargins(List<ISpatialData> children)
{
var rect = Rect.zero;
var uiRect = uiRectHelper.zero;
for (; i < minEntries; i++) rect = rect.expandToInclude(children[i].Rect);
for (; i < minEntries; i++) uiRect = uiRect.expandToInclude(children[i].bounds);
var totalMargin = rect.margin;
var totalMargin = uiRect.margin;
rect = rect.expandToInclude(children[i].Rect);
totalMargin += rect.margin;
uiRect = uiRect.expandToInclude(children[i].bounds);
totalMargin += uiRect.margin;
}
return totalMargin;

}
public RTreeNode Root { get; private set; }
public ref readonly Rect Rect => ref Root.Rect;
public uiRect uiRect => Root.bounds;
public int Count { get; private set; }

return GetAllChildren(new List<T>(), Root);
}
public IReadOnlyList<T> Search(in Rect boundingBox)
public IReadOnlyList<T> Search(in uiRect boundingBox)
{
return DoSearch(boundingBox);
}

73
Runtime/ui/painting/draw_cmd.cs


namespace Unity.UIWidgets.ui {
using UnityEngine;
namespace Unity.UIWidgets.ui {
public abstract uiRect bounds(float margin);
public class DrawSave : DrawCmd {
public abstract class StateUpdateDrawCmd : DrawCmd {
public override uiRect bounds(float margin) {
return uiRectHelper.zero;
}
}
public class DrawSave : StateUpdateDrawCmd {
public class DrawSaveLayer : DrawCmd {
public class DrawSaveLayer : StateUpdateDrawCmd {
public class DrawRestore : DrawCmd {
public class DrawRestore : StateUpdateDrawCmd {
public class DrawTranslate : DrawCmd {
public class DrawTranslate : StateUpdateDrawCmd {
public class DrawScale : DrawCmd {
public class DrawScale : StateUpdateDrawCmd {
public class DrawRotate : DrawCmd {
public class DrawRotate : StateUpdateDrawCmd {
public class DrawSkew : DrawCmd {
public class DrawSkew : StateUpdateDrawCmd {
public class DrawConcat : DrawCmd {
public class DrawConcat : StateUpdateDrawCmd {
public class DrawResetMatrix : DrawCmd {
public class DrawResetMatrix : StateUpdateDrawCmd {
public class DrawSetMatrix : DrawCmd {
public class DrawSetMatrix : StateUpdateDrawCmd {
public class DrawClipRect : DrawCmd {
public class DrawClipRect : StateUpdateDrawCmd {
public class DrawClipRRect : DrawCmd {
public class DrawClipRRect : StateUpdateDrawCmd {
public class DrawClipPath : DrawCmd {
public class DrawClipPath : StateUpdateDrawCmd {
public Path path;
}

public override uiRect bounds(float margin) {
return uiRectHelper.fromRect(this.path.getBoundsWithMargin(margin)).Value;
}
}
public class DrawImage : DrawCmd {

// TODO: Should divide by device pixel ratio here, which is not available as
// this DrawCmd is created. This bounds should only used as an upper bound,
// assuming that device pixel ratio is always >= 1
public override uiRect bounds(float margin) {
return uiRectHelper.fromLTWH(
this.offset.dx - margin, this.offset.dy - margin,
this.image.width + 2 * margin,
this.image.height + 2 * margin);
}
}
public class DrawImageRect : DrawCmd {

public Paint paint;
public override uiRect bounds(float margin) {
return uiRectHelper.fromRect(this.dst.inflate(margin)).Value;
}
}
public class DrawImageNine : DrawCmd {

public Rect dst;
public Paint paint;
public override uiRect bounds(float margin) {
return uiRectHelper.fromLTRB(
this.dst.left + ((this.center.left - this.src.left) * this.src.width) - margin,
this.dst.top + ((this.center.top - this.src.top) * this.src.height) - margin,
this.dst.right - ((this.src.right - this.center.right) * this.src.width) + margin,
this.dst.bottom - ((this.src.bottom - this.center.bottom) * this.src.height) + margin
);
}
public override uiRect bounds(float margin) {
return uiRectHelper.fromRect(this.picture.paintBounds.inflate(margin)).Value;
}
}
public class DrawTextBlob : DrawCmd {

public override uiRect bounds(float margin) {
return uiRectHelper.fromRect(this.textBlob.Value.boundsInText
.translate(this.offset.dx, this.offset.dy)
.inflate(margin)).Value;
}
}
}

31
Runtime/ui/painting/picture.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.Runtime.external;
public Picture(List<DrawCmd> drawCmds, Rect paintBounds, bool isDynamic = false) {
public Picture(List<DrawCmd> drawCmds,
Rect paintBounds,
bool isDynamic = false,
BBoxHierarchy<IndexedRect> bbh = null,
List<int> stateUpdatesIndices = null) {
this.bbh = bbh;
this.stateUpdatesIndices = stateUpdatesIndices;
public readonly BBoxHierarchy<IndexedRect> bbh;
public readonly List<int> stateUpdatesIndices;
public bool isDynamic {
get { return this._isDynamic; }

throw new Exception("unmatched save/restore commands");
}
int index = 0;
RTree<IndexedRect> bbh = new RTree<IndexedRect>();
List<int> stateUpdateIndices = new List<int>();
foreach (var cmd in this._drawCmds) {
if (cmd is StateUpdateDrawCmd) {
stateUpdateIndices.Add(index);
}
else {
bbh.Insert(new IndexedRect(cmd.bounds(5), index));
}
index++;
}
return new Picture(new List<DrawCmd>(this._drawCmds), state.paintBounds, this._isDynamic);
return new Picture(
new List<DrawCmd>(this._drawCmds),
state.paintBounds,
this._isDynamic,
bbh,
stateUpdateIndices);
}
public void addDrawCmd(DrawCmd drawCmd) {

90
Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.Runtime.external;
using UnityEngine;
using UnityEngine.Rendering;

var queryBound = this._currentLayer.currentState.matrix?.invert().Value
.mapRect(this._currentLayer.layerBounds) ??
this._currentLayer.layerBounds;
if (!uiRectHelper.contains(queryBound, uiRectHelper.fromRect(picture.paintBounds).Value)) {
var indices = picture.bbh.Search(queryBound).Select(bound => bound.index);
List<int> cmdIndices = indices.ToList();
cmdIndices.AddRange(picture.stateUpdatesIndices);
cmdIndices.Sort();
drawCmds = new List<DrawCmd>();
for (int i = 0; i < cmdIndices.Count; i++) {
drawCmds.Add(picture.drawCmds[cmdIndices[i]]);
}
}
foreach (var drawCmd in drawCmds) {
switch (drawCmd) {
case DrawSave _:

}
case DrawPath cmd: {
if (uiRectHelper.intersect(uiRectHelper.fromRect(
cmd.path.getBoundsWithMargin(5)).Value, queryBound).isEmpty) {
continue;
}
var uipath = uiPath.fromPath(cmd.path);
this._drawPath(uipath, uiPaint.fromPaint(cmd.paint));
uiPathCacheManager.putToCache(uipath);

case DrawImage cmd: {
if (uiRectHelper.intersect(uiRectHelper.fromLTWH(
cmd.offset.dx, cmd.offset.dy,
cmd.image.width / this._devicePixelRatio,
cmd.image.height / this._devicePixelRatio), queryBound).isEmpty) {
continue;
}
this._drawImage(cmd.image, (uiOffset.fromOffset(cmd.offset)).Value,
case DrawImage cmd: {_drawImage(cmd.image, (uiOffset.fromOffset(cmd.offset)).Value,
if (uiRectHelper.intersect(uiRectHelper.fromRect(cmd.dst).Value, queryBound).isEmpty) {
continue;
}
this._drawImageRect(cmd.image, uiRectHelper.fromRect(cmd.src), uiRectHelper.fromRect(cmd.dst).Value,
uiPaint.fromPaint(cmd.paint));
break;

if (uiRectHelper.intersect(uiRectHelper.fromLTRB(
cmd.dst.left + ((cmd.center.left - cmd.src.left) * cmd.src.width),
cmd.dst.top + ((cmd.center.top - cmd.src.top) * cmd.src.height),
cmd.dst.right - ((cmd.src.right - cmd.center.right) * cmd.src.width),
cmd.dst.bottom - ((cmd.src.bottom - cmd.center.bottom) * cmd.src.height)
), queryBound).isEmpty) {
continue;
}
this._drawImageNine(cmd.image, uiRectHelper.fromRect(cmd.src),
uiRectHelper.fromRect(cmd.center).Value, uiRectHelper.fromRect(cmd.dst).Value,
uiPaint.fromPaint(cmd.paint));

case DrawPicture cmd: {
if (uiRectHelper.intersect(uiRectHelper.fromRect(
cmd.picture.paintBounds).Value, queryBound).isEmpty) {
continue;
}
if (uiRectHelper.intersect(uiRectHelper.fromRect(
cmd.textBlob.Value.boundsInText.translate(cmd.offset.dx, cmd.offset.dy)).Value, queryBound).isEmpty) {
continue;
}
this._paintTextShadow(cmd.textBlob, cmd.offset);
this._drawTextBlob(cmd.textBlob, (uiOffset.fromOffset(cmd.offset)).Value,
uiPaint.fromPaint(cmd.paint));

var queryBound = this._currentLayer.currentState.matrix?.invert().Value
.mapRect(this._currentLayer.layerBounds) ??
this._currentLayer.layerBounds;
if (!uiRectHelper.contains(queryBound, picture.paintBounds)) {
var indices = picture.bbh.Search(queryBound).Select(bound => bound.index);
List<int> cmdIndices = indices.ToList();
cmdIndices.Capacity += picture.stateUpdatesIndices.Count;
for (int i = 0; i < picture.stateUpdatesIndices.Count; i++) {
cmdIndices.Add(picture.stateUpdatesIndices[i]);
}
cmdIndices.Sort();
drawCmds = new List<uiDrawCmd>();
for (int i = 0; i < cmdIndices.Count; i++) {
drawCmds.Add(picture.drawCmds[cmdIndices[i]]);
}
}
foreach (var drawCmd in drawCmds) {
switch (drawCmd) {
case uiDrawSave _:

}
case uiDrawPath cmd: {
if (uiRectHelper.intersect(cmd.path.getBoundsWithMargin(5), queryBound).isEmpty) {
continue;
}
if (uiRectHelper.intersect(uiRectHelper.fromLTWH(
cmd.offset.Value.dx, cmd.offset.Value.dy,
cmd.image.width / this._devicePixelRatio,
cmd.image.height / this._devicePixelRatio), queryBound).isEmpty) {
continue;
}
if (uiRectHelper.intersect(cmd.dst.Value, queryBound).isEmpty) {
continue;
}
if (uiRectHelper.intersect(uiRectHelper.fromLTRB(
cmd.dst.Value.left + ((cmd.center.Value.left - cmd.src.Value.left) * cmd.src.Value.width),
cmd.dst.Value.top + ((cmd.center.Value.top - cmd.src.Value.top) * cmd.src.Value.height),
cmd.dst.Value.right - ((cmd.src.Value.right - cmd.center.Value.right) * cmd.src.Value.width),
cmd.dst.Value.bottom - ((cmd.src.Value.bottom - cmd.center.Value.bottom) * cmd.src.Value.height)
), queryBound).isEmpty) {
continue;
}
if (uiRectHelper.intersect(uiRectHelper.fromRect(
cmd.picture.paintBounds).Value, queryBound).isEmpty) {
continue;
}
if (uiRectHelper.intersect(uiRectHelper.fromRect(
cmd.textBlob.Value.boundsInText.translate(cmd.offset.Value.dx, cmd.offset.Value.dy)).Value,
queryBound).isEmpty) {
continue;
}
this._paintTextShadow(cmd.textBlob, new Offset(cmd.offset.Value.dx, cmd.offset.Value.dy));
this._drawTextBlob(cmd.textBlob, cmd.offset.Value, cmd.paint);
break;

69
Runtime/ui/renderer/common/draw_cmd.cs


namespace Unity.UIWidgets.ui {
public abstract class uiDrawCmd : PoolObject {
public abstract void release();
public abstract uiRect bounds(float margin);
public class uiDrawSave : uiDrawCmd {
public abstract class uiStateUpdateDrawCmd : uiDrawCmd {
public override uiRect bounds(float margin) {
return uiRectHelper.zero;
}
}
public class uiDrawSave : uiStateUpdateDrawCmd {
public uiDrawSave() {
}

}
}
public class uiDrawSaveLayer : uiDrawCmd {
public class uiDrawSaveLayer : uiStateUpdateDrawCmd {
public uiDrawSaveLayer() {
}

public uiPaint paint;
}
public class uiDrawRestore : uiDrawCmd {
public class uiDrawRestore : uiStateUpdateDrawCmd {
public uiDrawRestore() {
}

}
}
public class uiDrawTranslate : uiDrawCmd {
public class uiDrawTranslate : uiStateUpdateDrawCmd {
public uiDrawTranslate() {
}

public float dy;
}
public class uiDrawScale : uiDrawCmd {
public class uiDrawScale : uiStateUpdateDrawCmd {
public uiDrawScale() {
}

public float? sy;
}
public class uiDrawRotate : uiDrawCmd {
public class uiDrawRotate : uiStateUpdateDrawCmd {
public uiDrawRotate() {
}

public uiOffset? offset;
}
public class uiDrawSkew : uiDrawCmd {
public class uiDrawSkew : uiStateUpdateDrawCmd {
public uiDrawSkew() {
}

public float sy;
}
public class uiDrawConcat : uiDrawCmd {
public class uiDrawConcat : uiStateUpdateDrawCmd {
public uiDrawConcat() {
}

public uiMatrix3? matrix;
}
public class uiDrawResetMatrix : uiDrawCmd {
public class uiDrawResetMatrix : uiStateUpdateDrawCmd {
public uiDrawResetMatrix() {
}

}
}
public class uiDrawSetMatrix : uiDrawCmd {
public class uiDrawSetMatrix : uiStateUpdateDrawCmd {
public uiDrawSetMatrix() {
}

public uiMatrix3? matrix;
}
public class uiDrawClipRect : uiDrawCmd {
public class uiDrawClipRect : uiStateUpdateDrawCmd {
public uiDrawClipRect() {
}

public uiRect? rect;
}
public class uiDrawClipRRect : uiDrawCmd {
public class uiDrawClipRRect : uiStateUpdateDrawCmd {
public uiDrawClipRRect() {
}

public RRect rrect;
}
public class uiDrawClipPath : uiDrawCmd {
public class uiDrawClipPath : uiStateUpdateDrawCmd {
public uiDrawClipPath() {
}

public uiPath path;
public uiPaint paint;
public override uiRect bounds(float margin) {
return this.path.getBoundsWithMargin(margin);
}
}
public class uiDrawImage : uiDrawCmd {

public Image image;
public uiOffset? offset;
public uiPaint paint;
// TODO: Should divide by device pixel ratio here, which is not available as
// this DrawCmd is created. This bounds should only used as an upper bound,
// assuming that device pixel ratio is always >= 1
public override uiRect bounds(float margin) {
return uiRectHelper.fromLTWH(
this.offset.Value.dx - margin, this.offset.Value.dy - margin,
this.image.width + 2 * margin,
this.image.height + 2 * margin);
}
}
public class uiDrawImageRect : uiDrawCmd {

public uiRect? src;
public uiRect? dst;
public uiPaint paint;
public override uiRect bounds(float margin) {
return uiRectHelper.inflate(this.dst.Value, margin);
}
}
public class uiDrawImageNine : uiDrawCmd {

public uiRect? center;
public uiRect? dst;
public uiPaint paint;
public override uiRect bounds(float margin) {
return uiRectHelper.fromLTRB(
this.dst.Value.left + ((this.center.Value.left - this.src.Value.left) * this.src.Value.width) - margin,
this.dst.Value.top + ((this.center.Value.top - this.src.Value.top) * this.src.Value.height) - margin,
this.dst.Value.right - ((this.src.Value.right - this.center.Value.right) * this.src.Value.width) + margin,
this.dst.Value.bottom - ((this.src.Value.bottom - this.center.Value.bottom) * this.src.Value.height) + margin
);
}
}
public class uiDrawPicture : uiDrawCmd {

}
public Picture picture;
public override uiRect bounds(float margin) {
return uiRectHelper.fromRect(this.picture.paintBounds.inflate(margin)).Value;
}
}
public class uiDrawTextBlob : uiDrawCmd {

public TextBlob? textBlob;
public uiOffset? offset;
public uiPaint paint;
public override uiRect bounds(float margin) {
return uiRectHelper.fromRect(this.textBlob.Value.boundsInText.translate(
this.offset.Value.dx, this.offset.Value.dy).inflate(margin)).Value;
}
}
}

8
Runtime/ui/renderer/common/geometry/rect.cs


get { return this.bottom - this.top; }
}
public float area {
get { return this.width * this.height; }
}
public float margin {
get { return this.width + this.height; }
}
public uiOffset topLeft {
get { return new uiOffset(this.left, this.top); }
}

26
Runtime/ui/renderer/common/picture.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.Runtime.external;
namespace Unity.UIWidgets.ui {
public class uiPicture : PoolObject {

public static uiPicture create(List<uiDrawCmd> drawCmds, uiRect paintBounds) {
public static uiPicture create(List<uiDrawCmd> drawCmds,
uiRect paintBounds,
BBoxHierarchy<IndexedRect> bbh = null,
uiList<int> stateUpdateIndices = null) {
picture.bbh = bbh;
picture.stateUpdatesIndices = stateUpdateIndices;
public BBoxHierarchy<IndexedRect> bbh;
public uiList<int> stateUpdatesIndices;
ObjectPool<uiList<int>>.release(this.stateUpdatesIndices);
}
}

if (this._states.Count > 1) {
throw new Exception("unmatched save/restore commands");
}
int index = 0;
RTree<IndexedRect> bbh = new RTree<IndexedRect>();
uiList<int> stateUpdateIndices = ObjectPool<uiList<int>>.alloc();
foreach (var cmd in this._drawCmds) {
if (cmd is uiStateUpdateDrawCmd) {
stateUpdateIndices.Add(index);
}
else {
bbh.Insert(new IndexedRect(cmd.bounds(5), index));
}
index++;
}
return uiPicture.create(this._drawCmds, state.paintBounds);
return uiPicture.create(this._drawCmds, state.paintBounds, bbh: bbh, stateUpdateIndices: stateUpdateIndices);
}
public void addDrawCmd(uiDrawCmd drawCmd) {

正在加载...
取消
保存