Created
March 14, 2016 12:32
-
-
Save Brian61/d2b8144d450a1b4b922a to your computer and use it in GitHub Desktop.
OpenTk(OpenGL) console stack (3 files) with test program at bottom.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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