|
// src* https://gist.github.com/andrew-raphael-lukasik/1202f94b853795bb6f78e2fabc824011 |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
using UnityEngine.Rendering; |
|
|
|
public static class GLDraw |
|
{ |
|
|
|
public static System.Func<Camera,bool> cameraSelector = (camera) => camera.name=="SceneCamera";// Scene view only |
|
static Dictionary<string,FDrawCall> externalBuffers = new Dictionary<string,FDrawCall>(); |
|
|
|
static List<FLine> lineBuffer = new List<FLine>(); |
|
static List<FDrawCallTemp> generalBuffer = new List<FDrawCallTemp>(); |
|
static List<FDrawCallTempSingleColor> generalBufferSingleColor = new List<FDrawCallTempSingleColor>(); |
|
static Material material; |
|
static long systemTick, ticksPerSecond; |
|
|
|
static GLDraw () |
|
{ |
|
ticksPerSecond = System.TimeSpan.TicksPerSecond; |
|
material = new Material(Shader.Find("Sprites/Default")); |
|
RenderPipelineManager.endFrameRendering += EndCameraRendering; |
|
} |
|
|
|
static void EndCameraRendering ( ScriptableRenderContext context , Camera[] cameras ) |
|
{ |
|
int totalDrawCalls = externalBuffers.Count + lineBuffer.Count + generalBuffer.Count + generalBufferSingleColor.Count; |
|
if( totalDrawCalls==0 ) return;// nothing to draw |
|
|
|
material.SetPass(0); |
|
|
|
GL.PushMatrix(); |
|
foreach( Camera camera in cameras ) |
|
{ |
|
if( !cameraSelector(camera) ) continue; |
|
|
|
// draw from external buffers: |
|
foreach( var kv in externalBuffers ) |
|
{ |
|
string id = kv.Key; |
|
FDrawCall drawCall = kv.Value; |
|
|
|
GL.Begin( (int) drawCall.mode ); |
|
{ |
|
int numVertices = Mathf.Min( drawCall.vertices.Length , drawCall.colors.Length ); |
|
for( int i=0 ; i<numVertices ; i++ ) |
|
{ |
|
GL.Color( drawCall.colors[i] ); |
|
GL.Vertex( drawCall.vertices[i] ); |
|
} |
|
} |
|
GL.End(); |
|
} |
|
|
|
// update system time: |
|
systemTick = System.DateTime.Now.Ticks; |
|
|
|
// draw form lines-only buffer: |
|
int lineBufferLength = lineBuffer.Count; |
|
if( lineBufferLength!=0 ) |
|
{ |
|
GL.Begin( GL.LINES ); |
|
{ |
|
for( int i=lineBufferLength-1 ; i!=-1 ; i-- ) |
|
{ |
|
FLine line = lineBuffer[i]; |
|
|
|
GL.Color( line.startColor ); |
|
GL.Vertex( line.start ); |
|
GL.Color( line.endColor ); |
|
GL.Vertex( line.end ); |
|
|
|
if( systemTick > line.expiration ) |
|
lineBuffer.RemoveAt(i); |
|
} |
|
} |
|
GL.End(); |
|
} |
|
|
|
// draw from a general-use buffer: |
|
int generalBufferLength = generalBuffer.Count; |
|
if( generalBufferLength!=0 ) |
|
{ |
|
for( int idc=generalBufferLength-1 ; idc!=-1 ; idc-- ) |
|
{ |
|
FDrawCallTemp drawcall = generalBuffer[idc]; |
|
GL.Begin( (int) drawcall.mode ); |
|
{ |
|
var vertexBuffer = drawcall.vertices; |
|
var colorBuffer = drawcall.colors; |
|
int numVertices = vertexBuffer.Length; |
|
for( int iv=numVertices-1 ; iv!=-1 ; iv-- ) |
|
{ |
|
GL.Color( colorBuffer[iv] ); |
|
GL.Vertex( vertexBuffer[iv] ); |
|
} |
|
} |
|
GL.End(); |
|
|
|
if( systemTick > drawcall.expiration ) |
|
generalBuffer.RemoveAt(idc); |
|
} |
|
} |
|
|
|
// draw from a general-use single color buffer: |
|
int generalBufferSingleColorLength = generalBufferSingleColor.Count; |
|
{ |
|
for( int idc=generalBufferSingleColorLength-1 ; idc!=-1 ; idc-- ) |
|
{ |
|
FDrawCallTempSingleColor drawcall = generalBufferSingleColor[idc]; |
|
GL.Begin( (int) drawcall.mode ); |
|
GL.Color( drawcall.color ); |
|
{ |
|
var vertexBuffer = drawcall.vertices; |
|
int numVertices = vertexBuffer.Length; |
|
for( int iv=numVertices-1 ; iv!=-1 ; iv-- ) |
|
GL.Vertex( vertexBuffer[iv] ); |
|
} |
|
GL.End(); |
|
|
|
if( systemTick > drawcall.expiration ) |
|
generalBufferSingleColor.RemoveAt(idc); |
|
} |
|
} |
|
} |
|
GL.PopMatrix(); |
|
} |
|
|
|
public static void Line ( Vector3 start , Vector3 end ) |
|
=> Line( start:start , end:end , color:Color.white , duration:0 ); |
|
public static void Line ( Vector3 start , Vector3 end , Color32 color ) |
|
=> Line( start:start , startColor:color , end:end , endColor:color , duration:0 ); |
|
public static void Line ( Vector3 start , Vector3 end , float duration ) |
|
=> Line( start:start , end:end , color:Color.white , duration:duration ); |
|
public static void Line ( Vector3 start , Vector3 end , Color32 color , float duration ) |
|
=> Line( start:start , startColor:color , end:end , endColor:color , duration:duration ); |
|
public static void Line ( Vector3 start , Color32 startColor , Vector3 end , Color32 endColor , float duration ) |
|
{ |
|
lineBuffer.Add( new FLine{ start=start , end=end , startColor=startColor , endColor=endColor , expiration=systemTick+(long)(duration*ticksPerSecond) } ); |
|
} |
|
|
|
public static void Circle ( Vector3 center , Vector3 normal , float r , int numVertices = 32 ) |
|
=> Circle( center:center , normal:normal , r:r , color:Color.white , duration:0 , numVertices:numVertices ); |
|
public static void Circle ( Vector3 center , Vector3 normal , float r , Color32 color , int numVertices = 32 ) |
|
=> Circle( center:center , normal:normal , r:r , color:color , duration:0 , numVertices:numVertices ); |
|
public static void Circle ( Vector3 center , Vector3 normal , float r , Color32 color , float duration , int numVertices = 32 ) |
|
{ |
|
numVertices = Mathf.Max( numVertices , 3 ) + 1;// "+1" because first and last vertex occupy the same spot |
|
var rot = Quaternion.FromToRotation( Vector3.up , normal ); |
|
const float tau = Mathf.PI * 2f; |
|
Vector3[] vertices = new Vector3[ numVertices ]; |
|
for( int i=0 ; i<numVertices ; i++ ) |
|
{ |
|
float angle = tau * ( i / ( numVertices - 1f ) ); |
|
float cos = Mathf.Cos(angle); |
|
float sin = Mathf.Sin(angle); |
|
vertices[i] = center + rot * new Vector3(cos*r,0,sin*r); |
|
} |
|
generalBufferSingleColor.Add( new FDrawCallTempSingleColor{ mode=GLDraw.EMode.LINE_STRIP , vertices=vertices , color=color , expiration=systemTick+(long)(duration*ticksPerSecond) } ); |
|
} |
|
|
|
public static void WireSphere ( Vector3 center , float r , Color32 color , int numVertices = 32 ) |
|
=> WireSphere( center:center , r:r , color:color , duration:0 , numVertices:numVertices ); |
|
public static void WireSphere ( Vector3 center , float r , Color32 color , float duration , int numVertices = 32 ) |
|
{ |
|
numVertices = Mathf.Max( numVertices , 3 ); |
|
const float tau = Mathf.PI * 2f; |
|
Vector3[] vertices = new Vector3[ numVertices * 3 ]; |
|
for( int i=0 ; i<numVertices ; i++ ) |
|
{ |
|
float angle = tau * ( i / ( numVertices - 1f ) ); |
|
float cos = Mathf.Cos(angle); |
|
float sin = Mathf.Sin(angle); |
|
vertices[i] = center + new Vector3(cos*r,0,sin*r); |
|
} |
|
var rot2 = Quaternion.Euler(90,0,0); |
|
for( int i=numVertices ; i<numVertices*2 ; i++ ) |
|
{ |
|
float angle = tau * ( i / ( numVertices - 1f ) ); |
|
float cos = Mathf.Cos(angle); |
|
float sin = Mathf.Sin(angle); |
|
vertices[i] = center + rot2 * new Vector3(cos*r,0,sin*r); |
|
} |
|
var rot3 = Quaternion.Euler(0,0,90); |
|
for( int i=numVertices*2 ; i<numVertices*3 ; i++ ) |
|
{ |
|
float angle = tau * ( i / ( numVertices - 1f ) ); |
|
float cos = Mathf.Cos(angle); |
|
float sin = Mathf.Sin(angle); |
|
vertices[i] = center + rot3 * new Vector3(cos*r,0,sin*r); |
|
} |
|
|
|
generalBufferSingleColor.Add( new FDrawCallTempSingleColor{ mode=GLDraw.EMode.LINE_STRIP , vertices=vertices , color=color , expiration=systemTick+(long)(duration*ticksPerSecond) } ); |
|
} |
|
|
|
public static void Call ( EMode mode , Vector3[] vertices ) |
|
=> Call( mode:mode , duration:0 , color:Color.white , vertices:vertices ); |
|
public static void Call ( EMode mode , Vector3[] vertices , Color32 color ) |
|
=> Call( mode:mode , duration:0 , color:color , vertices:vertices ); |
|
public static void Call ( EMode mode , Vector3[] vertices , Color32 color , float duration ) |
|
{ |
|
generalBufferSingleColor.Add( new FDrawCallTempSingleColor{ mode=mode , color=color , vertices=vertices , expiration=systemTick+(long)(duration*ticksPerSecond) } ); |
|
} |
|
|
|
public static void Call ( EMode mode , Vector3[] vertices , Color32[] colors ) |
|
=> Call( mode:mode , duration:0 , colors:colors , vertices:vertices ); |
|
public static void Call ( EMode mode , Vector3[] vertices , Color32[] colors , float duration ) |
|
{ |
|
generalBuffer.Add( new FDrawCallTemp{ mode=mode , colors=colors , vertices=vertices , expiration=systemTick+(long)(duration*ticksPerSecond) } ); |
|
} |
|
|
|
public static void AddBuffer ( string id , EMode mode , Vector3[] vertexBuffer , Color32[] colorBuffer ) |
|
{ |
|
if( vertexBuffer==null || vertexBuffer.Length==0 || colorBuffer==null || colorBuffer.Length==0 ) |
|
{ |
|
Debug.LogError($"invalid draw call {{ \"{id}\" , mode:{mode} , vertexBuffer:{vertexBuffer?.Length} , colorBuffer:{colorBuffer?.Length} }}"); |
|
return; |
|
} |
|
|
|
externalBuffers.Add( id , new FDrawCall{ mode=mode , vertices=vertexBuffer , colors=colorBuffer } ); |
|
} |
|
|
|
public static void RemoveBuffer ( string id ) |
|
=> externalBuffers.Remove( id ); |
|
|
|
struct FLine |
|
{ |
|
public Vector3 start, end; |
|
public Color32 startColor, endColor; |
|
public long expiration; |
|
} |
|
|
|
struct FDrawCall |
|
{ |
|
public EMode mode; |
|
public Vector3[] vertices; |
|
public Color32[] colors; |
|
} |
|
struct FDrawCallTemp |
|
{ |
|
public EMode mode; |
|
public Vector3[] vertices; |
|
public Color32[] colors; |
|
// public Matrix4x4[] matrix; |
|
public long expiration; |
|
} |
|
|
|
struct FDrawCallTempSingleColor |
|
{ |
|
public EMode mode; |
|
public Vector3[] vertices; |
|
public Color32 color; |
|
// public Matrix4x4[] matrix; |
|
public long expiration; |
|
} |
|
|
|
public enum EMode : byte |
|
{ |
|
LINES = GL.LINES, |
|
LINE_STRIP = GL.LINE_STRIP, |
|
TRIANGLES = GL.TRIANGLES, |
|
TRIANGLE_STRIP = GL.TRIANGLE_STRIP, |
|
QUADS = GL.QUADS, |
|
} |
|
|
|
} |