Skip to content

Instantly share code, notes, and snippets.

@Brian61
Created March 14, 2016 12:32
Show Gist options
  • Save Brian61/d2b8144d450a1b4b922a to your computer and use it in GitHub Desktop.
Save Brian61/d2b8144d450a1b4b922a to your computer and use it in GitHub Desktop.
OpenTk(OpenGL) console stack (3 files) with test program at bottom.
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
namespace RLConsole
{
public class RLFrame : GameWindow
{
public static RLFrame Instance { get; private set; }
public static Size DefaultSize { get; set; }
public static WindowBorder DefaultBorder { get; set; }
public static WindowState DefaultState { get; set; }
public static string DefaultTitle { get; set; }
public static Color4 DefaultClearColor { get; set; }
public static int DefaultShaders { get; private set; }
static RLFrame()
{
Instance = null;
DefaultSize = new Size(640, 400);
DefaultBorder = WindowBorder.Fixed;
DefaultState = WindowState.Normal;
DefaultTitle = "RLConsole";
DefaultClearColor = Color4.CornflowerBlue;
}
public bool PauseUpdates { get; set; }
public static int MVPLocation { get; private set; }
public static Matrix4 MVP { get; private set; }
public static int PositionLocation { get; private set; }
public static int TexCoordLocation { get; private set; }
public static int FgColorLocation { get; private set; }
public static int BgColorLocation { get; private set; }
private List<RLSurface> _renderStack;
private bool _loaded;
public RLFrame(string title = null)
: base(DefaultSize.Width, DefaultSize.Height, GraphicsMode.Default, title ?? DefaultTitle,
GameWindowFlags.Default, DisplayDevice.Default, 3, 0,
GraphicsContextFlags.ForwardCompatible)
{
if (Instance != null)
throw new NotSupportedException("Only one RLFrame instance allowed.");
Instance = this;
Debug.WriteLine("gl version: " + GL.GetString(StringName.Version));
_loaded = false;
_renderStack = new List<RLSurface>();
PauseUpdates = false;
WindowBorder = DefaultBorder;
WindowState = DefaultState;
Load += RLFrame_Load;
Unload += RLFrame_Unload;
RenderFrame += RLFrame_RenderFrame;
}
public void AddSurface(RLSurface surface)
{
if (_renderStack.Contains(surface))
throw new ArgumentException("AddSurface: surface already added.");
_renderStack.Add(surface);
if (_loaded)
surface.OnLoad();
OnZOrderChange();
}
public void RemoveSurface(RLSurface surface)
{
if (_renderStack.Remove(surface) && _loaded)
surface.OnUnload();
}
public void OnZOrderChange()
{
if (_renderStack.Count > 1)
_renderStack = _renderStack.OrderBy(s => s.ZOrder).ToList();
}
public void Run(double? fps = null, double? ups = null)
{
var rate = fps ?? 30.0;
base.Run(ups ?? rate, rate);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
GL.Viewport(0, 0, this.Width, this.Height);
MVP = Matrix4.CreateOrthographicOffCenter(0, Width - 1, Height - 1, 0, 0, 1);
}
private void RLFrame_Load(object sender, EventArgs e)
{
VSync = VSyncMode.On;
GL.Enable(EnableCap.Texture2D);
LoadShaders();
_loaded = true;
foreach (var s in _renderStack) {
s.OnLoad();
}
GL.Enable(EnableCap.Blend);// Add OpenGL state for blending to allow for transparency.
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Disable(EnableCap.DepthTest);
MVPLocation = GL.GetUniformLocation(DefaultShaders, "MVP");
}
private void RLFrame_Unload(object sender, EventArgs e)
{
foreach (var s in _renderStack) {
s.OnUnload();
}
GL.DeleteProgram(DefaultShaders);
}
private void RLFrame_RenderFrame(object sender, FrameEventArgs e)
{
GL.ClearColor(DefaultClearColor);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
foreach (var s in _renderStack) {
if (!s.Visible) continue;
s.Render();
}
SwapBuffers();
}
protected void LoadShaders()
{
int vertex_shader = GL.CreateShader(ShaderType.VertexShader);
int fragment_shader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(vertex_shader,
@"#version 120
uniform mat4 MVP;
attribute vec4 position;
attribute vec2 texcoord;
attribute vec4 fgcolor;
attribute vec4 bgcolor;
varying vec2 texcoord_fs;
varying vec4 fgcolor_fs;
varying vec4 bgcolor_fs;
void main(){
texcoord_fs = vec2(texcoord.s, 1.0 - texcoord.t);
fgcolor_fs = fgcolor;
bgcolor_fs = bgcolor;
gl_Position = MVP * position;
}
");
GL.ShaderSource(fragment_shader,
@"#version 120
uniform sampler2D texture;
varying vec2 texcoord_fs;
varying vec4 fgcolor_fs;
varying vec4 bgcolor_fs;
void main(){
vec4 v = texture2D(texture,texcoord_fs);
if(v.r == 1.0 && v.g == 1.0 && v.b == 1.0){
gl_FragColor = fgcolor_fs;
}
else{
gl_FragColor = bgcolor_fs;
}
}
");
GL.CompileShader(vertex_shader);
GL.CompileShader(fragment_shader);
int compiled;
GL.GetShader(vertex_shader, ShaderParameter.CompileStatus, out compiled);
if (compiled < 1) {
Debug.WriteLine(GL.GetShaderInfoLog(vertex_shader));
throw new Exception("vertex shader compilation failed");
}
GL.GetShader(fragment_shader, ShaderParameter.CompileStatus, out compiled);
if (compiled < 1) {
Debug.WriteLine(GL.GetShaderInfoLog(fragment_shader));
throw new Exception("fragment shader compilation failed");
}
DefaultShaders = GL.CreateProgram();
GL.AttachShader(DefaultShaders, vertex_shader);
GL.AttachShader(DefaultShaders, fragment_shader);
PositionLocation = 0;
GL.BindAttribLocation(DefaultShaders, 0, "position");
TexCoordLocation = 1;
GL.BindAttribLocation(DefaultShaders, 1, "texcoord");
FgColorLocation = 2;
GL.BindAttribLocation(DefaultShaders, 2, "fgcolor");
BgColorLocation = 3;
GL.BindAttribLocation(DefaultShaders, 3, "bgcolor");
GL.LinkProgram(DefaultShaders);
GL.GetProgram(DefaultShaders, GetProgramParameterName.LinkStatus, out compiled);
if (compiled < 1) {
Debug.WriteLine(GL.GetProgramInfoLog(DefaultShaders));
throw new Exception("Shader program link failed");
}
GL.DetachShader(DefaultShaders, fragment_shader);
GL.DeleteShader(fragment_shader);
GL.DetachShader(DefaultShaders, vertex_shader);
GL.DeleteShader(vertex_shader);
}
}
}
////////////////////////////////////////////////////////////////////
using OpenTK.Graphics;
using System;
using System.Drawing;
namespace RLConsole
{
public class RLPanel
{
public Size GridSize { get; private set; }
protected int[,] tiles;
protected Color4[,] colors;
protected Color4[,] bgColors;
protected bool dirty;
public RLPanel(Size gridSize)
{
GridSize = gridSize;
tiles = new int[gridSize.Height, gridSize.Width];
colors = new Color4[gridSize.Height, gridSize.Width];
bgColors = new Color4[gridSize.Height, gridSize.Width];
dirty = false;
}
public int GetTile(int col, int row) { return tiles[row, col]; }
public Color4 GetColor(int col, int row) { return colors[row, col]; }
public Color4 GetBackgroundColor(int col, int row) { return bgColors[row, col]; }
public void Set(int col, int row, int tile, Color4? color=null, Color4? bgColor=null)
{
var fg = color ?? Color4.White;
var bg = bgColor ?? Color4.Transparent;
tiles[row, col] = tile;
colors[row, col] = fg;
bgColors[row, col] = bg;
dirty = true;
}
public void Write(int col, int row, string text, Color4? color =null, Color4? bgColor =null)
{
foreach (var c in text) {
if (c == '\n') {
row++;
} else if (c == '\t') {
col += 4;
} else {
Set(col, row, (int) c, color, bgColor);
col++;
}
if (col >= GridSize.Width) {
row++;
col = 0;
}
if (row >= GridSize.Height)
break;
}
}
public void Blit(RLPanel target, Point targetOffset, Point srcOffset, Size srcSize)
{
if (targetOffset.X + srcSize.Width > target.GridSize.Width)
throw new ArgumentOutOfRangeException();
if (targetOffset.Y + srcSize.Height > target.GridSize.Height)
throw new ArgumentOutOfRangeException();
var src = new Rectangle(srcOffset, srcSize);
for (var row = src.Top; row < src.Bottom; row++) {
var targetRow = row + targetOffset.Y;
for (var col = src.Left; col < src.Right; col++) {
var targetCol = col + targetOffset.X;
target.tiles[targetRow, targetCol] = tiles[row, col];
target.colors[targetRow, targetCol] = colors[row, col];
target.bgColors[targetRow, targetCol] = bgColors[row, col];
}
}
target.dirty = true;
}
}
}
///////////////////////////////////////////////////////////////////////////////////
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
namespace RLConsole
{
public class RLSurface : RLPanel
{
protected int num_elements;
protected int tilesPerRow;
protected int shader_program;
protected int texture_id;
protected int vert_id;
protected int elem_id;
protected Bitmap bitmap;
private float texCellWidth;
private float texCellHeight;
private int num_positions;
public Rectangle Bounds
{
get
{
return new Rectangle(Offset.X, Offset.Y,
GridSize.Width * CellSize.Width,
GridSize.Height * CellSize.Height);
}
}
public Point Offset { get; set; }
public Size CellSize { get; private set; }
public int ZOrder { get; set; }
public bool Visible { get; set; }
public bool Enabled { get; set; }
public RLSurface(Size cellSize, Size gridSize, Bitmap bitmap, int zorder = 0,
bool visible = true, bool enabled = true)
: base(gridSize)
{
CellSize = cellSize;
ZOrder = zorder;
Visible = visible;
Enabled = enabled;
this.bitmap = bitmap;
tilesPerRow = bitmap.Width / cellSize.Width;
}
internal virtual void OnLoad()
{
LoadTexture();
CreateBuffers();
}
internal virtual void OnUnload()
{
GL.DeleteTexture(texture_id);
GL.DeleteBuffer(vert_id);
GL.DeleteBuffer(elem_id);
}
protected RLSurface(Size cellSize, Size gridSize, int zorder = 0, bool visible = true)
: base(gridSize)
{
CellSize = cellSize;
ZOrder = zorder;
Visible = visible;
}
public static uint NextPowerOfTwo(uint num)
{
if (num != 0) {
num--;
num |= (num >> 1); //Or first 2 bits
num |= (num >> 2); //Or next 2 bits
num |= (num >> 4); //Or next 4 bits
num |= (num >> 8); //Or next 8 bits
num |= (num >> 16); //Or next 16 bits
num++;
}
return num;
}
protected void LoadTexture()
{
int texWidth = (int) NextPowerOfTwo((uint)bitmap.Width);
int texHeight = (int)NextPowerOfTwo((uint)bitmap.Height);
var imgWidth = bitmap.Width;
var imgHeight = bitmap.Height;
bool npot = texWidth != imgWidth || texHeight != imgHeight;
if (npot) {
var bm = new Bitmap(texWidth, texHeight, bitmap.PixelFormat);
var src = new Rectangle(0, 0, imgWidth, imgHeight);
var dst = new Rectangle(0, 0, texWidth, texHeight);
using (Graphics grD = Graphics.FromImage(bm))
grD.DrawImage(bitmap, dst, src, GraphicsUnit.Pixel);
bitmap.Dispose();
bitmap = bm;
}
texCellWidth = imgWidth / (float)(texWidth * CellSize.Width);
texCellHeight = imgHeight / (float)(texHeight * CellSize.Height);
texture_id = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, texture_id);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
PixelType.UnsignedByte, data.Scan0);
bitmap.UnlockBits(data);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter,
(int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter,
(int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS,
(int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT,
(int)TextureWrapMode.ClampToEdge);
bitmap.Dispose();
bitmap = null;
}
protected void CreateBuffers()
{
var rows = GridSize.Height;
var cols = GridSize.Width;
num_elements = rows * cols * 6;
int[] indices = new int[num_elements];
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
int idx = (j + i * cols) * 48;
int idx4 = (j + i * cols) * 4;
int idx6 = (j + i * cols) * 6;
indices[idx6] = idx4;
indices[idx6 + 1] = idx4 + 1;
indices[idx6 + 2] = idx4 + 2;
indices[idx6 + 3] = idx4 + 2;
indices[idx6 + 4] = idx4 + 3;
indices[idx6 + 5] = idx4;
}
}
GL.GenBuffers(1, out elem_id);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elem_id);
GL.BufferData(BufferTarget.ElementArrayBuffer,
new IntPtr(sizeof(int) * indices.Length), indices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
float[] f = CalculateBuffer();
GL.GenBuffers(1, out vert_id);
GL.BindBuffer(BufferTarget.ArrayBuffer, vert_id);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float) * f.Length),
f, BufferUsageHint.StreamDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
dirty = false;
}
public virtual void Render()
{
if (dirty) {
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float) * 48 * num_positions),
new IntPtr(0), BufferUsageHint.StreamDraw);
GL.BufferSubData(BufferTarget.ArrayBuffer, new IntPtr(0),
new IntPtr(sizeof(float) * 48 * num_positions), CalculateBuffer());
dirty = false;
}
GL.UseProgram(RLFrame.DefaultShaders);
var mvp = RLFrame.MVP;
GL.UniformMatrix4(RLFrame.MVPLocation, false, ref mvp);
//GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, texture_id);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elem_id);
GL.BindBuffer(BufferTarget.ArrayBuffer, vert_id);
GL.EnableVertexAttribArray(RLFrame.PositionLocation);
GL.EnableVertexAttribArray(RLFrame.TexCoordLocation);
GL.EnableVertexAttribArray(RLFrame.FgColorLocation);
GL.EnableVertexAttribArray(RLFrame.BgColorLocation);
GL.VertexAttribPointer(RLFrame.PositionLocation, 2, VertexAttribPointerType.Float,
false, sizeof(float) * 12, 0);
GL.VertexAttribPointer(RLFrame.TexCoordLocation, 2, VertexAttribPointerType.Float,
false, sizeof(float) * 12, new IntPtr(sizeof(float) * 2));
GL.VertexAttribPointer(RLFrame.FgColorLocation, 4, VertexAttribPointerType.Float,
false, sizeof(float) * 12, new IntPtr(sizeof(float) * 4));
GL.VertexAttribPointer(RLFrame.BgColorLocation, 4, VertexAttribPointerType.Float,
false, sizeof(float) * 12, new IntPtr(sizeof(float) * 8));
GL.DrawElements(PrimitiveType.Triangles, num_elements, DrawElementsType.UnsignedInt,
IntPtr.Zero);
GL.DisableVertexAttribArray(RLFrame.PositionLocation);
GL.DisableVertexAttribArray(RLFrame.TexCoordLocation);
GL.DisableVertexAttribArray(RLFrame.FgColorLocation);
GL.DisableVertexAttribArray(RLFrame.BgColorLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.UseProgram(0);
}
protected float[] CalculateBuffer()
{
num_positions = GridSize.Width * GridSize.Height;
var values = new List<float>(48 * num_positions);
var cell_height = CellSize.Height;
var cell_width = CellSize.Width;
for (var row = 0; row < GridSize.Height; row++) {
var y = (float)row * cell_height;
var yb = y + (cell_height - 1);
for (var col = 0; col < GridSize.Width; col++) {
var fg = colors[row, col];
var bg = bgColors[row, col];
var tile = tiles[row, col];
var s = (tile % tilesPerRow) * texCellWidth;
var sr = s + texCellWidth;
var t = (tile / tilesPerRow) * texCellHeight;
var tb = t + texCellHeight;
var x = (float)col * cell_width;
var xr = x - (cell_width - 1);
values.AddRange(new float[]
{
x,y,s,t,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A,
x,yb,s,tb,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A,
xr,yb,sr,tb,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A,
xr,y,sr,t,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A
});
}
}
return values.ToArray();
}
}
}
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
namespace RLConsole
{
public class RLSurface : RLPanel
{
protected int num_elements;
protected int tilesPerRow;
protected int shader_program;
protected int texture_id;
protected int vert_id;
protected int elem_id;
protected Bitmap bitmap;
private float texCellWidth;
private float texCellHeight;
private int num_positions;
public Rectangle Bounds
{
get
{
return new Rectangle(Offset.X, Offset.Y,
GridSize.Width * CellSize.Width,
GridSize.Height * CellSize.Height);
}
}
public Point Offset { get; set; }
public Size CellSize { get; private set; }
public int ZOrder { get; set; }
public bool Visible { get; set; }
public bool Enabled { get; set; }
public RLSurface(Size cellSize, Size gridSize, Bitmap bitmap, int zorder = 0,
bool visible = true, bool enabled = true)
: base(gridSize)
{
CellSize = cellSize;
ZOrder = zorder;
Visible = visible;
Enabled = enabled;
this.bitmap = bitmap;
tilesPerRow = bitmap.Width / cellSize.Width;
}
internal virtual void OnLoad()
{
LoadTexture();
CreateBuffers();
}
internal virtual void OnUnload()
{
GL.DeleteTexture(texture_id);
GL.DeleteBuffer(vert_id);
GL.DeleteBuffer(elem_id);
}
protected RLSurface(Size cellSize, Size gridSize, int zorder = 0, bool visible = true)
: base(gridSize)
{
CellSize = cellSize;
ZOrder = zorder;
Visible = visible;
}
public static uint NextPowerOfTwo(uint num)
{
if (num != 0) {
num--;
num |= (num >> 1); //Or first 2 bits
num |= (num >> 2); //Or next 2 bits
num |= (num >> 4); //Or next 4 bits
num |= (num >> 8); //Or next 8 bits
num |= (num >> 16); //Or next 16 bits
num++;
}
return num;
}
protected void LoadTexture()
{
int texWidth = (int) NextPowerOfTwo((uint)bitmap.Width);
int texHeight = (int)NextPowerOfTwo((uint)bitmap.Height);
var imgWidth = bitmap.Width;
var imgHeight = bitmap.Height;
bool npot = texWidth != imgWidth || texHeight != imgHeight;
if (npot) {
var bm = new Bitmap(texWidth, texHeight, bitmap.PixelFormat);
var src = new Rectangle(0, 0, imgWidth, imgHeight);
var dst = new Rectangle(0, 0, texWidth, texHeight);
using (Graphics grD = Graphics.FromImage(bm))
grD.DrawImage(bitmap, dst, src, GraphicsUnit.Pixel);
bitmap.Dispose();
bitmap = bm;
}
texCellWidth = imgWidth / (float)(texWidth * CellSize.Width);
texCellHeight = imgHeight / (float)(texHeight * CellSize.Height);
texture_id = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, texture_id);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra,
PixelType.UnsignedByte, data.Scan0);
bitmap.UnlockBits(data);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter,
(int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter,
(int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS,
(int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT,
(int)TextureWrapMode.ClampToEdge);
bitmap.Dispose();
bitmap = null;
}
protected void CreateBuffers()
{
var rows = GridSize.Height;
var cols = GridSize.Width;
num_elements = rows * cols * 6;
int[] indices = new int[num_elements];
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
int idx = (j + i * cols) * 48;
int idx4 = (j + i * cols) * 4;
int idx6 = (j + i * cols) * 6;
indices[idx6] = idx4;
indices[idx6 + 1] = idx4 + 1;
indices[idx6 + 2] = idx4 + 2;
indices[idx6 + 3] = idx4 + 2;
indices[idx6 + 4] = idx4 + 3;
indices[idx6 + 5] = idx4;
}
}
GL.GenBuffers(1, out elem_id);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elem_id);
GL.BufferData(BufferTarget.ElementArrayBuffer,
new IntPtr(sizeof(int) * indices.Length), indices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
float[] f = CalculateBuffer();
GL.GenBuffers(1, out vert_id);
GL.BindBuffer(BufferTarget.ArrayBuffer, vert_id);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float) * f.Length),
f, BufferUsageHint.StreamDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
dirty = false;
}
public virtual void Render()
{
if (dirty) {
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float) * 48 * num_positions),
new IntPtr(0), BufferUsageHint.StreamDraw);
GL.BufferSubData(BufferTarget.ArrayBuffer, new IntPtr(0),
new IntPtr(sizeof(float) * 48 * num_positions), CalculateBuffer());
dirty = false;
}
GL.UseProgram(RLFrame.DefaultShaders);
var mvp = RLFrame.MVP;
GL.UniformMatrix4(RLFrame.MVPLocation, false, ref mvp);
//GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, texture_id);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elem_id);
GL.BindBuffer(BufferTarget.ArrayBuffer, vert_id);
GL.EnableVertexAttribArray(RLFrame.PositionLocation);
GL.EnableVertexAttribArray(RLFrame.TexCoordLocation);
GL.EnableVertexAttribArray(RLFrame.FgColorLocation);
GL.EnableVertexAttribArray(RLFrame.BgColorLocation);
GL.VertexAttribPointer(RLFrame.PositionLocation, 2, VertexAttribPointerType.Float,
false, sizeof(float) * 12, 0);
GL.VertexAttribPointer(RLFrame.TexCoordLocation, 2, VertexAttribPointerType.Float,
false, sizeof(float) * 12, new IntPtr(sizeof(float) * 2));
GL.VertexAttribPointer(RLFrame.FgColorLocation, 4, VertexAttribPointerType.Float,
false, sizeof(float) * 12, new IntPtr(sizeof(float) * 4));
GL.VertexAttribPointer(RLFrame.BgColorLocation, 4, VertexAttribPointerType.Float,
false, sizeof(float) * 12, new IntPtr(sizeof(float) * 8));
GL.DrawElements(PrimitiveType.Triangles, num_elements, DrawElementsType.UnsignedInt,
IntPtr.Zero);
GL.DisableVertexAttribArray(RLFrame.PositionLocation);
GL.DisableVertexAttribArray(RLFrame.TexCoordLocation);
GL.DisableVertexAttribArray(RLFrame.FgColorLocation);
GL.DisableVertexAttribArray(RLFrame.BgColorLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.UseProgram(0);
}
protected float[] CalculateBuffer()
{
num_positions = GridSize.Width * GridSize.Height;
var values = new List<float>(48 * num_positions);
var cell_height = CellSize.Height;
var cell_width = CellSize.Width;
for (var row = 0; row < GridSize.Height; row++) {
var y = (float)row * cell_height;
var yb = y + (cell_height - 1);
for (var col = 0; col < GridSize.Width; col++) {
var fg = colors[row, col];
var bg = bgColors[row, col];
var tile = tiles[row, col];
var s = (tile % tilesPerRow) * texCellWidth;
var sr = s + texCellWidth;
var t = (tile / tilesPerRow) * texCellHeight;
var tb = t + texCellHeight;
var x = (float)col * cell_width;
var xr = x - (cell_width - 1);
values.AddRange(new float[]
{
x,y,s,t,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A,
x,yb,s,tb,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A,
xr,yb,sr,tb,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A,
xr,y,sr,t,fg.R,fg.G,fg.B,fg.A,bg.R,bg.G,bg.B,bg.A
});
}
}
return values.ToArray();
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
using RLConsole;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
namespace QuantumTrails
{
class Program
{
static RLSurface surface;
static bool first = true;
[STAThread]
static void Main(string[] args)
{
surface = null;
using (var cons = new RLFrame("Quantum Trails")) {
cons.UpdateFrame += Cons_UpdateFrame;
cons.Run();
}
}
private static void Cons_UpdateFrame(object sender, OpenTK.FrameEventArgs e)
{
if (first) {
var cons = sender as RLFrame;
var assembly = Assembly.GetExecutingAssembly();
foreach (var line in Assembly.GetExecutingAssembly().GetManifestResourceNames())
Debug.WriteLine(line);
var font = new Bitmap(assembly.GetManifestResourceStream(
"QuantumTrails.Media.Bitmaps.terminal8x8_gs_ro.png"));
//var font = BitmapLoader.Exec("terminal8x8_gs_ro.png");
surface = new RLSurface(new Size(9, 9), new Size(80, 50), font);
cons.AddSurface(surface);
first = false;
}
surface.Write(5, 5, "Hello World!");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment