该项目的目的是同时测试和演示来自 Unity DOTS 技术堆栈的多个新包。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

1171 行
43 KiB

using UnityEngine;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using System.Runtime.InteropServices;
using System.IO;
using System;
using Unity.Burst;
using Unity.Sample.Core;
using UnityEngine.Rendering;
namespace Unity.DebugDisplay
{
public struct Overlay
{
public enum Color
{
Black,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
Gray,
DarkGray,
BrightBlue,
BrightGreen,
BrightCyan,
BrightRed,
BrightMagenta,
Yellow,
White
}
public void Clear()
{
m_Text.ClearCells();
m_TextReservations = m_Text.ReserveAll(); // clear out all the tex boxes
m_GraphReservations = m_Graph.ReserveAll(); // clear out all the graphs
m_LineReservations = m_Line.ReserveAll(); // clear out all the lines
}
public Text.Reservation m_TextReservations;
public Line.Reservation m_LineReservations;
public Graph.Reservation m_GraphReservations;
public Graph.Data.Reservation m_GraphDataReservations;
public struct Unit
{
public int m_begin;
public int m_next;
public int m_end;
public Unit(int me, int writers, int writableBegin, int writableEnd)
{
var writables = writableEnd - writableBegin;
m_begin = writableBegin + (me * writables) / writers;
m_end = writableBegin + ((me + 1) * writables) / writers;
if (m_begin > writableEnd)
m_begin = writableEnd;
if (m_end > writableEnd)
m_end = writableEnd;
m_next = m_begin;
}
public void Fill()
{
m_next = m_end;
}
public int Length => m_end - m_begin;
public int Filled => m_next - m_begin;
public int Remaining => m_end - m_next;
}
public struct Text : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
public struct Cell
{
[FieldOffset(0)] public byte unicodelo;
[FieldOffset(1)] public byte color;
[FieldOffset(2)] public ushort unicodehi;
public uint unicode
{
get
{
uint value = (uint) (unicodelo & 0x7f);
if ((unicodelo & 0x80) == 0x80)
value |= (uint) unicodehi << 7;
return value;
}
set
{
unicodelo = (byte) (value & 0x7f);
if (value > 0x7f)
unicodelo |= 0x80;
unicodehi = (ushort) (value >> 7);
}
}
public Color fg
{
get => (Color) ((color >> 0) & 0xf);
set => color = (byte) ((color & 0xF0) | (((int) value & 0xF) << 0));
}
public Color bg
{
get => (Color) ((color >> 4) & 0x7);
set => color = (byte) ((color & 0x8F) | (((int) value & 0x7) << 4));
}
public bool side
{
get => (color & 0x80) == 0x80;
set
{
color &= 0x7F;
color = (byte) (color | (value ? 0x80 : 0x00));
}
}
}
public struct Instance
{
public Vector3 worldPosition;
public Vector2 firstCell;
public Vector2 cellSize;
public uint useWorldMatrix;
}
public const int kMaxInstances = 128;
public const int kMaxColors = 16;
public const int kMaxDisplayPixelsWide = 3840; // no support for 8K or 16K, yet
public const int kMaxDisplayPixelsTall = 2160;
public const int kCellPixelsWide = 8;
public const int kCellPixelsTall = 16;
public const int kMaxCellsWide = (kMaxDisplayPixelsWide + kCellPixelsWide - 1) / kCellPixelsWide;
public const int kMaxCellsTall = (kMaxDisplayPixelsTall + kCellPixelsTall - 1) / kCellPixelsTall;
public const int kMaxCells = kMaxCellsWide * kMaxCellsTall;
[BurstDiscard] public int CellsWide => m_CellsWide;
[BurstDiscard] public int CellsTall => m_CellsTall;
public int m_CellsWide;
public int m_CellsTall;
public NativeArray<Instance> m_Instance;
public NativeArray<Cell> m_Cell;
public NativeArray<byte> m_Wide; // 1 bit for each UNICODE code point: am I wide (Chinese) or not (Roman)
public unsafe void ClearCells()
{
UnsafeUtility.MemClear(m_Cell.GetUnsafePtr(), m_Cell.Length * sizeof(Cell));
}
public void Initialize(int cellsWide, int cellsTall)
{
m_CellsWide = cellsWide;
m_CellsTall = cellsTall;
m_Instance = new NativeArray<Instance>(kMaxInstances, Allocator.Persistent);
m_Cell = new NativeArray<Cell>(kMaxCells, Allocator.Persistent);
m_Wide = new NativeArray<byte>(8192, Allocator.Persistent);
}
public void Initialize()
{
Initialize(Screen.width / kCellPixelsWide, Screen.height / kCellPixelsTall);
}
public void ClearTextBox(int index)
{
m_Instance[index] = new Instance();
}
public unsafe void SetTextBox(int cellX, int cellY, int cellW, int cellH, int index)
{
m_Instance[index] = new Instance
{
worldPosition = new Vector2(cellX * kCellPixelsWide, cellY * kCellPixelsTall),
firstCell = new Vector2(cellX, cellY),
cellSize = new Vector2(cellW, cellH),
useWorldMatrix = 0
};
}
public unsafe void SetTextBoxSmooth(Vector3 position, int cellX, int cellY, int cellW, int cellH, int index)
{
m_Instance[index] = new Instance
{
worldPosition = position,
firstCell = new Vector2(cellX, cellY),
cellSize = new Vector2(cellW, cellH),
useWorldMatrix = 1
};
}
public bool isWide(uint c)
{
var bits = m_Wide[(int) c >> 3];
var mask = 1 << (int) (c & 7);
return (bits & mask) != 0;
}
public void PutChar(int x, int y, Cell t)
{
if (x < 0 || x >= kMaxCellsWide || y < 0 || y >= kMaxCellsTall)
return;
var offset = y * kMaxCellsWide + x;
m_Cell[offset] = t;
}
public unsafe void PutChars(int x, int y, Cell t, int count)
{
while (count-- != 0)
PutChar(x++, y, t);
}
public void PutChar(ref int x, int y, uint utf32, Color fg, Color bg)
{
Cell t = new Cell {unicode = utf32, fg = fg, bg = bg};
PutChar(x++, y, t);
if (isWide(t.unicode))
{
t.side = true;
PutChar(x++, y, t);
}
}
public void PutChar(ref int x, int y, char utf16, Color fg, Color bg)
{
PutChar(ref x, y, (uint) utf16, fg, bg);
}
unsafe bool IsSurrogatePair(char* c, int index)
{
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF)
return true;
return false;
}
unsafe uint ConvertToUtf32(char* c, int index)
{
if (!IsSurrogatePair(c, index))
return c[index];
uint hi = (uint) c[index] - 0xD800;
uint lo = (uint) c[index] - 0xDC00;
uint offset = (hi << 10) | lo;
return 0x10000 + offset;
}
unsafe public void PutChars(ref int x, int y, char* c, int length, Color fg, Color bg)
{
for (var i = 0; i < length; i += IsSurrogatePair(c, i) ? 2 : 1)
{
uint utf32 = ConvertToUtf32(c, i);
PutChar(ref x, y, utf32, fg, bg);
}
}
public unsafe void SetLabel(Vector3 position, int cellX, int cellY, char* c, int length, Color fg, Color bg,
int index)
{
SetTextBoxSmooth(position, cellX, cellY, length, 1, index);
PutChars(ref cellX, cellY, c, length, fg, bg);
}
public void Dispose()
{
m_Instance.Dispose();
m_Cell.Dispose();
m_Wide.Dispose();
}
public Reservation ReserveAll()
{
return new Reservation
{
m_text = this,
m_unit = new Unit(0, 1, 0, m_Instance.Length)
};
}
public struct Reservation : IDisposable
{
public Text m_text;
public Unit m_unit;
public Reservation Reserve(int count)
{
if (m_unit.m_next + count > m_unit.m_end)
count = m_unit.m_end - m_unit.m_next;
var result = new Reservation
{
m_text = m_text,
m_unit = new Unit(0, 1, m_unit.m_next, m_unit.m_next + count)
};
m_unit.m_next += count;
return result;
}
public Reservation PartitionForJob(int me, int writers)
{
return new Reservation
{
m_text = m_text,
m_unit = new Unit(me, writers, m_unit.m_begin, m_unit.m_end)
};
}
public void AddTextBox(int x, int y, int w, int h)
{
if (m_unit.m_next < m_unit.m_end)
m_text.SetTextBox(x, y, w, h, m_unit.m_next++);
}
public unsafe void AddLabel(Vector3 position, char* c, int length, Color fg, Color bg)
{
if (m_unit.m_next < m_unit.m_end)
m_text.SetLabel(position, 0, m_text.m_CellsTall + m_unit.m_next, c, length, fg, bg,
m_unit.m_next++);
}
[BurstDiscard]
public unsafe void AddLabel(Vector3 position, string s, Color fg, Color bg)
{
fixed (char* c = s)
AddLabel(position, c, s.Length, fg, bg);
}
public void Dispose()
{
while (m_unit.m_next < m_unit.m_end)
m_text.ClearTextBox(m_unit.m_next++);
}
}
}
public struct Graph : IDisposable
{
public struct Data
{
public int offset;
public int length;
public void Validate()
{
if ((length & (length - 1)) != 0)
throw new ArgumentException(
$"Length of data in graph is {length} which must be a power of two.");
}
public struct Reservation
{
public Graph m_graph;
public Unit m_unit;
public Reservation Reserve(int count)
{
if (m_unit.m_next + count > m_unit.m_end)
count = m_unit.m_end - m_unit.m_next;
var result = new Reservation
{
m_graph = m_graph,
m_unit = new Unit(0, 1, m_unit.m_next, m_unit.m_next + count)
};
m_unit.m_next += count;
return result;
}
public Reservation PartitionForJob(int me, int writers)
{
return new Reservation
{
m_graph = m_graph,
m_unit = new Unit(me, writers, m_unit.m_begin, m_unit.m_end)
};
}
public float GetValue(int offset)
{
return m_graph.m_Data[m_unit.m_begin + (offset & (m_unit.Length - 1))];
}
public void SetValue(int offset, float value)
{
m_graph.m_Data[m_unit.m_begin + (offset & (m_unit.Length - 1))] = value;
}
public void AddValue(float value)
{
if (m_unit.m_next >= m_unit.m_end)
m_unit.m_next = m_unit.m_begin;
m_graph.m_Data[m_unit.m_next++] = value;
}
public Data GetData()
{
return new Data {offset = m_unit.m_begin, length = m_unit.Length};
}
public unsafe void CalcMinMaxMean(out float minValue, out float maxValue, out float mean)
{
float* f = (float*) m_graph.m_Data.GetUnsafePtr();
minValue = f[m_unit.m_begin];
maxValue = f[m_unit.m_begin];
float sum = f[m_unit.m_begin];
for (var i = m_unit.m_begin + 1; i < m_unit.m_end; i++)
{
var x = f[i];
sum += x;
if (x < minValue) minValue = x;
if (x > maxValue) maxValue = x;
}
mean = sum / m_unit.Length;
}
public unsafe void CalcStatistics(out float mean, out float variance, out float minValue,
out float maxValue)
{
CalcMinMaxMean(out minValue, out maxValue, out mean);
float* f = (float*) m_graph.m_Data.GetUnsafePtr();
float sum2 = 0;
for (var i = m_unit.m_begin; i < m_unit.m_end; i++)
{
float d = f[i] - mean;
sum2 += d * d;
}
variance = sum2 / m_unit.Length;
}
}
}
public Data.Reservation ReserveAllData()
{
return new Data.Reservation
{
m_graph = this,
m_unit = new Unit(0, 1, 0, m_Data.Length)
};
}
public struct Sample
{
public Data data; // offset of first datum, count of data
public Color color; // color of data
public float xMin; // first data to display
public float xMax; // last data to display
public float yMin; // first Y value to display
public float yMax; // last Y value to display
}
public struct InstanceSample
{
public int color; // color of the sample
public int firstIndex; // first sample index in range to display
public int indexMask; // AND sample index with this to make it wrap around
public float indexMul; // multiply the pixel.x by this,
public float indexAdd; // and then by this to get the sample index.
public float sampleMul; // multiply the sample by this,
public float sampleAdd; // and then add this to get the pixel.y
}
public struct Instance
{
public Vector2 screenPosition;
public Vector2 cellSize;
public int frameColor;
public int samples;
public InstanceSample sample0;
public InstanceSample sample1;
};
public const int kMaxDisplayPixelsWide = 3840; // no support for 8K or 16K, yet
public const int kMaxDisplayPixelsTall = 2160;
public const int kCellPixelsWide = 8;
public const int kCellPixelsTall = 16;
public const int kMaxCellsWide = (kMaxDisplayPixelsWide + kCellPixelsWide - 1) / kCellPixelsWide;
public const int kMaxCellsTall = (kMaxDisplayPixelsTall + kCellPixelsTall - 1) / kCellPixelsTall;
public const int kMaxCells = kMaxCellsWide * kMaxCellsTall;
public const int kMaxInstances = 16;
public const int kMaxValues = 4096;
public const int kMaxColors = 16;
public NativeArray<Instance> m_Instance;
public NativeArray<float> m_Data;
[BurstDiscard] public static int CellsWide => Screen.width / kCellPixelsWide;
[BurstDiscard] public static int CellsTall => Screen.height / kCellPixelsTall;
public void Initialize()
{
m_Instance = new NativeArray<Instance>(kMaxInstances, Allocator.Persistent);
m_Data = new NativeArray<float>(kMaxValues, Allocator.Persistent);
}
float recip(float f)
{
return (f == 0.0f) ? 1 : 1.0f / f;
}
public void ClearGraph(int index)
{
m_Instance[index] = new Instance();
}
public void SetGraph(int x, int y, int w, int h, Sample a, int index)
{
if (index >= m_Instance.Length)
return;
a.data.Validate();
a.xMax += 1;
float axScale = (a.xMax - a.xMin) / (w * 8 - 1);
float ayScale = (h * 16 - 2) * recip(a.yMin - a.yMax);
m_Instance[index] = new Instance
{
screenPosition = new Vector2(x * Graph.kCellPixelsWide, y * Graph.kCellPixelsTall),
cellSize = new Vector2(w, h),
frameColor = (int) Color.White,
samples = 1,
sample0 = new InstanceSample
{
color = (int) a.color,
firstIndex = a.data.offset,
indexMask = a.data.length - 1,
indexMul = axScale,
indexAdd = a.xMin,
sampleMul = ayScale,
sampleAdd = ayScale * -a.yMax + 1,
}
};
}
public unsafe void SetGraph(int x, int y, int w, int h, Sample a, Sample b, int index)
{
if (index >= m_Instance.Length)
return;
a.data.Validate();
b.data.Validate();
a.xMax += 1;
b.xMax += 1;
float axScale = (a.xMax - a.xMin) / (w * 8 - 1);
float ayScale = (h * 16 - 2) * recip(a.yMin - a.yMax);
float bxScale = (b.xMax - b.xMin) / (w * 8 - 1);
float byScale = (h * 16 - 2) * recip(b.yMin - b.yMax);
m_Instance[index] = new Instance
{
screenPosition = new Vector2(x * Graph.kCellPixelsWide, y * Graph.kCellPixelsTall),
cellSize = new Vector2(w, h),
frameColor = (int) Color.White,
samples = 2,
sample0 = new InstanceSample
{
color = (int) a.color,
firstIndex = a.data.offset,
indexMask = a.data.length - 1,
indexMul = axScale,
indexAdd = a.xMin,
sampleMul = ayScale,
sampleAdd = ayScale * -a.yMax + 1,
},
sample1 = new InstanceSample
{
color = (int) b.color,
firstIndex = b.data.offset,
indexMask = b.data.length - 1,
indexMul = bxScale,
indexAdd = b.xMin,
sampleMul = byScale,
sampleAdd = byScale * -b.yMax + 1,
}
};
}
public void Dispose()
{
m_Instance.Dispose();
m_Data.Dispose();
}
public Reservation ReserveAll()
{
return new Reservation
{
m_graph = this,
m_unit = new Unit(0, 1, 0, m_Instance.Length)
};
}
public struct Reservation : IDisposable
{
public Graph m_graph;
public Unit m_unit;
public Reservation Reserve(int count)
{
if (m_unit.m_next + count > m_unit.m_end)
count = m_unit.m_end - m_unit.m_next;
var result = new Reservation
{
m_graph = m_graph,
m_unit = new Unit(0, 1, m_unit.m_next, m_unit.m_next + count)
};
m_unit.m_next += count;
return result;
}
public Reservation PartitionForJob(int me, int writers)
{
return new Reservation
{
m_graph = m_graph,
m_unit = new Unit(me, writers, m_unit.m_begin, m_unit.m_end)
};
}
public void AddGraph(int x, int y, int w, int h, Graph.Sample a)
{
if (m_unit.m_next < m_unit.m_end)
m_graph.SetGraph(x, y, w, h, a, m_unit.m_next++);
}
public void AddGraph(int x, int y, int w, int h, Graph.Sample a, Graph.Sample b)
{
if (m_unit.m_next < m_unit.m_end)
m_graph.SetGraph(x, y, w, h, a, b, m_unit.m_next++);
}
public void Dispose()
{
while (m_unit.m_next < m_unit.m_end)
m_graph.ClearGraph(m_unit.m_next++);
}
}
}
public struct Line : IDisposable
{
const int kMaxLines = 500;
public struct Instance
{
public Vector4 m_begin;
public Vector4 m_end;
}
public NativeArray<Instance> m_Instance;
public void Initialize()
{
m_Instance = new NativeArray<Instance>(kMaxLines, Allocator.Persistent);
}
public void SetLine(Vector3 begin, Vector3 end, Color color, int index)
{
m_Instance[index] = new Instance
{
m_begin = new Vector4(begin.x, begin.y, begin.z, (uint) color),
m_end = new Vector4(end.x, end.y, end.z, (uint) color)
};
}
public void ClearLine(int index)
{
m_Instance[index] = new Instance { };
}
public void Dispose()
{
m_Instance.Dispose();
}
public Reservation ReserveAll()
{
return new Reservation
{
m_line = this,
m_unit = new Unit(0, 1, 0, m_Instance.Length)
};
}
public struct Reservation : IDisposable
{
public Line m_line;
public Unit m_unit;
public Reservation Reserve(int count)
{
if (m_unit.m_next + count > m_unit.m_end)
count = m_unit.m_end - m_unit.m_next;
var result = new Reservation
{
m_line = m_line,
m_unit = new Unit(0, 1, m_unit.m_next, m_unit.m_next + count)
};
m_unit.m_next += count;
return result;
}
public Reservation PartitionForJob(int me, int writers)
{
return new Reservation
{
m_line = m_line,
m_unit = new Unit(me, writers, m_unit.m_begin, m_unit.m_end)
};
}
public void AddLine(Vector3 begin, Vector3 end, Color color)
{
if (m_unit.m_next < m_unit.m_end)
m_line.SetLine(begin, end, color, m_unit.m_next++);
}
public void Dispose()
{
while (m_unit.m_next < m_unit.m_end)
m_line.ClearLine(m_unit.m_next++);
}
}
}
public Text m_Text;
public Graph m_Graph;
public Line m_Line;
public const int kMaxColors = 16;
public NativeArray<Vector4> m_ColorData;
public void Initialize()
{
m_ColorData = new NativeArray<Vector4>(kMaxColors, Allocator.Persistent);
m_Text.Initialize();
m_Graph.Initialize();
m_Line.Initialize();
m_TextReservations = m_Text.ReserveAll();
m_GraphReservations = m_Graph.ReserveAll();
m_GraphDataReservations = m_Graph.ReserveAllData();
m_LineReservations = m_Line.ReserveAll();
}
public Color Quantize(Vector4 color)
{
int index = 0;
float best = (color - m_ColorData[0]).SqrMagnitude();
for (int i = 1; i < m_ColorData.Length; ++i)
{
float distance = (color - m_ColorData[i]).SqrMagnitude();
if (distance < best)
{
best = distance;
index = i;
}
}
return (Color) index;
}
public void Dispose()
{
m_Graph.Dispose();
m_Text.Dispose();
m_Line.Dispose();
m_ColorData.Dispose();
}
public class Managed
{
[ConfigVar(Name = "show.overlay", DefaultValue = "1", Description = "Show the debug overlay")]
public static ConfigVar showOverlay;
public Overlay m_Unmanaged;
Color m_ForegroundColor = Color.White;
Color m_BackgroundColor = Color.Black;
public int visibleLinesOfText = 40;
static DebugDisplayResources resources;
public static int PixelsWide => Screen.width;
public static int PixelsTall => Screen.height;
public static int CellsWide =>
(PixelsWide + Overlay.Text.kCellPixelsWide - 1) / Overlay.Text.kCellPixelsWide;
public static int CellsTall =>
(PixelsTall + Overlay.Text.kCellPixelsTall - 1) / Overlay.Text.kCellPixelsTall;
public void Init()
{
m_Unmanaged.Initialize();
if (resources == null)
{
resources = Resources.Load<DebugDisplayResources>("DebugDisplayResources");
Debug.Assert(resources != null, "Unable to load DebugDisplayResources");
Stream s = new MemoryStream(resources.wide.bytes);
BinaryReader br = new BinaryReader(s);
var wide = new byte[s.Length];
br.Read(wide, 0, (int) s.Length);
for (var i = 0; i < s.Length; ++i)
m_Unmanaged.m_Text.m_Wide[i] = wide[i];
}
SetPalette(windows);
}
public void Shutdown()
{
if (m_GraphSampleBuffer != null)
m_GraphSampleBuffer.Release();
m_GraphSampleBuffer = null;
if (m_GraphInstanceBuffer != null)
m_GraphInstanceBuffer.Release();
m_GraphInstanceBuffer = null;
if (m_TextCellBuffer != null)
m_TextCellBuffer.Release();
m_TextCellBuffer = null;
if (m_TextInstanceBuffer != null)
m_TextInstanceBuffer.Release();
m_TextInstanceBuffer = null;
if (m_LineVertexBuffer != null)
m_LineVertexBuffer.Release();
m_LineVertexBuffer = null;
if (m_ColorBuffer != null)
m_ColorBuffer.Release();
m_ColorBuffer = null;
m_Unmanaged.Dispose();
}
public void TickLateUpdate()
{
// Recreate compute buffer if needed.
if (m_ColorBuffer == null || m_ColorBuffer.count != m_Unmanaged.m_ColorData.Length)
{
if (m_ColorBuffer != null)
{
m_ColorBuffer.Release();
m_ColorBuffer = null;
}
m_ColorBuffer = new ComputeBuffer(m_Unmanaged.m_ColorData.Length, UnsafeUtility.SizeOf<Vector4>());
resources.textMaterial.SetBuffer("colorBuffer", m_ColorBuffer);
resources.graphMaterial.SetBuffer("colorBuffer", m_ColorBuffer);
resources.lineMaterial.SetBuffer("colorBuffer", m_ColorBuffer);
}
if (m_TextCellBuffer == null || m_TextCellBuffer.count != m_Unmanaged.m_Text.m_Cell.Length)
{
if (m_TextCellBuffer != null)
{
m_TextCellBuffer.Release();
m_TextCellBuffer = null;
}
m_TextCellBuffer = new ComputeBuffer(m_Unmanaged.m_Text.m_Cell.Length,
UnsafeUtility.SizeOf<Overlay.Text.Cell>());
resources.textMaterial.SetBuffer("textBuffer", m_TextCellBuffer);
}
if (m_TextInstanceBuffer == null || m_TextInstanceBuffer.count != m_Unmanaged.m_Text.m_Instance.Length)
{
if (m_TextInstanceBuffer != null)
{
m_TextInstanceBuffer.Release();
m_TextInstanceBuffer = null;
}
m_TextInstanceBuffer = new ComputeBuffer(m_Unmanaged.m_Text.m_Instance.Length,
UnsafeUtility.SizeOf<Overlay.Text.Instance>());
resources.textMaterial.SetBuffer("positionBuffer", m_TextInstanceBuffer);
}
if (m_LineVertexBuffer == null || m_LineVertexBuffer.count != m_Unmanaged.m_Line.m_Instance.Length)
{
if (m_LineVertexBuffer != null)
{
m_LineVertexBuffer.Release();
m_LineVertexBuffer = null;
}
m_LineVertexBuffer = new ComputeBuffer(m_Unmanaged.m_Line.m_Instance.Length,
UnsafeUtility.SizeOf<Overlay.Line.Instance>());
resources.lineMaterial.SetBuffer("positionBuffer", m_LineVertexBuffer);
}
if (m_GraphSampleBuffer == null || m_GraphSampleBuffer.count != m_Unmanaged.m_Graph.m_Data.Length)
{
if (m_GraphSampleBuffer != null)
{
m_GraphSampleBuffer.Release();
m_GraphSampleBuffer = null;
}
m_GraphSampleBuffer =
new ComputeBuffer(m_Unmanaged.m_Graph.m_Data.Length, UnsafeUtility.SizeOf<float>());
resources.graphMaterial.SetBuffer("sampleBuffer", m_GraphSampleBuffer);
}
if (m_GraphInstanceBuffer == null ||
m_GraphInstanceBuffer.count != m_Unmanaged.m_Graph.m_Instance.Length)
{
if (m_GraphInstanceBuffer != null)
{
m_GraphInstanceBuffer.Release();
m_GraphInstanceBuffer = null;
}
m_GraphInstanceBuffer = new ComputeBuffer(m_Unmanaged.m_Graph.m_Instance.Length,
UnsafeUtility.SizeOf<Overlay.Graph.Instance>());
resources.graphMaterial.SetBuffer("instanceBuffer", m_GraphInstanceBuffer);
}
m_ColorBuffer.SetData(m_Unmanaged.m_ColorData);
m_TextCellBuffer.SetData(m_Unmanaged.m_Text.m_Cell);
m_GraphSampleBuffer.SetData(m_Unmanaged.m_Graph.m_Data);
m_NumGraphsToDraw = m_Unmanaged.m_GraphReservations.m_unit.Filled;
m_NumTextBoxesToDraw = m_Unmanaged.m_TextReservations.m_unit.Filled;
m_NumLinesToDraw = m_Unmanaged.m_LineReservations.m_unit.Filled;
m_GraphInstanceBuffer.SetData(m_Unmanaged.m_Graph.m_Instance, 0, 0, m_NumGraphsToDraw);
m_TextInstanceBuffer.SetData(m_Unmanaged.m_Text.m_Instance, 0, 0, m_NumTextBoxesToDraw);
m_LineVertexBuffer.SetData(m_Unmanaged.m_Line.m_Instance, 0, 0, m_NumLinesToDraw);
var scales = new Vector4(1.0f / CellsWide, 1.0f / CellsTall, 1.0f / PixelsWide, 1.0f / PixelsTall);
resources.textMaterial.SetVector("scales", scales);
resources.graphMaterial.SetVector("scales", scales);
resources.lineMaterial.SetVector("scales", scales);
_Clear();
}
public static void SetColor(Color col)
{
if (instance == null)
return;
instance.m_ForegroundColor = col;
}
public unsafe static void Write(int x, int y, char[] buf, int count)
{
if (instance == null)
return;
for (var i = 0; i < count; i++)
instance.m_Unmanaged.m_Text.PutChar(ref x, y, buf[i], instance.m_ForegroundColor,
instance.m_BackgroundColor);
}
public static void Write(int x, int y, string format)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write<T>(int x, int y, string format, T arg)
{
if (instance == null)
return;
var l = StringFormatter.Write<T>(ref _buf, 0, format, arg);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write(Color col, int x, int y, string format)
{
if (instance == null)
return;
var c = instance.m_ForegroundColor;
instance.m_ForegroundColor = col;
var l = StringFormatter.Write(ref _buf, 0, format);
instance._DrawText(x, y, ref _buf, l);
instance.m_ForegroundColor = c;
}
public static void Write<T>(Color col, int x, int y, string format, T arg)
{
if (instance == null)
return;
var c = instance.m_ForegroundColor;
instance.m_ForegroundColor = col;
var l = StringFormatter.Write(ref _buf, 0, format, arg);
instance._DrawText(x, y, ref _buf, l);
instance.m_ForegroundColor = c;
}
public static void Write<T0, T1>(Color col, int x, int y, string format, T0 arg0, T1 arg1)
{
if (instance == null)
return;
var c = instance.m_ForegroundColor;
instance.m_ForegroundColor = col;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1);
instance._DrawText(x, y, ref _buf, l);
instance.m_ForegroundColor = c;
}
public static void Write<T0, T1>(int x, int y, string format, T0 arg0, T1 arg1)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write<T0, T1, T2>(int x, int y, string format, T0 arg0, T1 arg1, T2 arg2)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1, arg2);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write<T0, T1, T2, T3>(int x, int y, string format, T0 arg0, T1 arg1, T2 arg2, T3 arg3)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1, arg2, arg3);
instance._DrawText(x, y, ref _buf, l);
}
void _DrawText(int x, int y, ref char[] text, int length)
{
const string hexes = "0123456789ABCDEF";
var col = m_ForegroundColor;
for (var i = 0; i < length; i++)
{
if (text[i] == '^' && i < length - 3)
{
var r = hexes.IndexOf(text[i + 1]);
var g = hexes.IndexOf(text[i + 2]);
var b = hexes.IndexOf(text[i + 3]);
var rgba = new Vector4(r, g, b, 15) / 15.0f;
col = m_Unmanaged.Quantize(rgba);
i += 3;
continue;
}
m_Unmanaged.m_Text.PutChar(ref x, y, text[i], col, 0);
}
}
void _Clear()
{
m_Unmanaged.Clear();
m_Unmanaged.m_TextReservations.AddTextBox(0, 0, Overlay.Text.kMaxCellsWide,
visibleLinesOfText); // steal one text box for the full-screen thing
}
static char[] _buf = new char[1024];
public void Render()
{
resources.lineMaterial.SetPass(0);
Graphics.DrawProceduralNow(MeshTopology.Lines, m_NumLinesToDraw, 1);
resources.textMaterial.SetPass(0);
Graphics.DrawProceduralNow(MeshTopology.Triangles, m_NumTextBoxesToDraw * 6, 1);
resources.graphMaterial.SetPass(0);
Graphics.DrawProceduralNow(MeshTopology.Triangles, m_NumGraphsToDraw * 6, 1);
}
int m_NumTextBoxesToDraw = 0;
int m_NumGraphsToDraw = 0;
int m_NumLinesToDraw = 0;
ComputeBuffer m_GraphSampleBuffer; // one big 1D array of floats
ComputeBuffer m_GraphInstanceBuffer; // one thing for each graph to display
ComputeBuffer m_TextCellBuffer; // one big 2D array of character cells
ComputeBuffer m_TextInstanceBuffer; // one thing for each text box to display
ComputeBuffer m_LineVertexBuffer; // one big 1D array of line vertex positions.
ComputeBuffer m_ColorBuffer;
public uint[] molokai = new uint[16]
{
0x181915, 0x7a0137, 0x498702, 0xc5bb63,
0x3465a4, 0x75507b, 0x4194b0, 0xd3d7cf,
0x45473c, 0xe00265, 0x6dca04, 0xe6db74,
0x1d71ca, 0xaf5fff, 0x5cd1f8, 0xffffff,
};
public uint[] windows = new uint[16]
{
0x000000, 0x800000, 0x008000, 0x808000,
0x000080, 0x800080, 0x008080, 0xc0c0c0,
0x808080, 0xff0000, 0x00ff00, 0xffff00,
0x0000ff, 0xff00ff, 0x00ffff, 0xffffff,
};
public void SetPalette(uint[] source)
{
for (int i = 0; i < m_Unmanaged.m_ColorData.Length; ++i)
{
uint r = (source[i] >> 0) & 0xff;
uint g = (source[i] >> 8) & 0xff;
uint b = (source[i] >> 16) & 0xff;
m_Unmanaged.m_ColorData[i] = new Vector4(r, g, b, 255) / 255.0f;
}
}
private static Managed _instance;
public static void Initialize()
{
_instance = new Managed();
_instance.Init();
}
public static void DoShutdown()
{
if (_instance != null)
_instance.Shutdown();
}
public static Managed instance { get { return _instance; } }
void _Render(CameraType cameraType, CommandBuffer cmd)
{
if (cameraType != CameraType.Game)
return;
cmd.DrawProcedural(Matrix4x4.identity, resources.textMaterial, 0, MeshTopology.Triangles, m_NumTextBoxesToDraw * 6, 1);
cmd.DrawProcedural(Matrix4x4.identity, resources.graphMaterial, 0, MeshTopology.Triangles, m_NumGraphsToDraw * 6, 1);
}
void _Render3D(CameraType cameraType, CommandBuffer cmd)
{
cmd.DrawProcedural(Matrix4x4.identity, resources.lineMaterial, 0, MeshTopology.Lines, m_NumLinesToDraw, 1);
}
public static bool ShouldShow()
{
if (showOverlay == null)
return false;
return showOverlay.IntValue != 0;
}
public static void Render(CameraType cameraType, CommandBuffer cmd)
{
if(!ShouldShow())
return;
instance?._Render(cameraType, cmd);
}
public static void Render3D(CameraType cameraType, CommandBuffer cmd)
{
if(!ShouldShow())
return;
instance?._Render3D(cameraType, cmd);
}
}
}
}