Created
June 11, 2018 20:04
-
-
Save nasser/30c5304fa4ea945d33a46097055121d4 to your computer and use it in GitHub Desktop.
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
// https://github.com/tgsstdio/OpenTK-Demos/blob/master/ComputeDemo/Demo.cs | |
using System; | |
using OpenTK.Graphics.OpenGL; | |
using OpenTK; | |
using OpenTK.Graphics; | |
namespace Pico | |
{ | |
public class Demo | |
{ | |
private int _mRenderProgramId; | |
public void Initialize() | |
{ | |
_mRenderProgramId = SetupRenderProgram(); | |
} | |
static uint _bufferWidth = 128; | |
static uint[] _frameBuffer = new uint[_bufferWidth * _bufferWidth]; | |
static int _frameBufferLocation; | |
static void Set(int x, int y, uint c) | |
{ | |
if (x >= _bufferWidth || y >= _bufferWidth || x < 0 || y < 0) | |
return; | |
_frameBuffer[(x % _bufferWidth) + y * _bufferWidth] = c; | |
} | |
// https://en.wikipedia.org/wiki/Midpoint_circle_algorithm | |
static void Circle(int x0, int y0, int radius, uint c) | |
{ | |
int x = radius - 1; | |
int y = 0; | |
int dx = 1; | |
int dy = 1; | |
int err = dx - (radius << 1); | |
while (x >= y) | |
{ | |
Set(x0 + x, y0 + y, c); | |
Set(x0 + y, y0 + x, c); | |
Set(x0 - y, y0 + x, c); | |
Set(x0 - x, y0 + y, c); | |
Set(x0 - x, y0 - y, c); | |
Set(x0 - y, y0 - x, c); | |
Set(x0 + y, y0 - x, c); | |
Set(x0 + x, y0 - y, c); | |
if (err <= 0) | |
{ | |
y++; | |
err += dy; | |
dy += 2; | |
} | |
if (err > 0) | |
{ | |
x--; | |
dx += 2; | |
err += dx - (radius << 1); | |
} | |
} | |
} | |
// https://en.wikipedia.org/wiki/Midpoint_circle_algorithm | |
static void FilledCircle(int x0, int y0, int radius, uint c) | |
{ | |
int x = radius; | |
int y = 0; | |
int dx = 1; | |
int dy = 1; | |
int err = dx - (radius << 1); | |
while (x >= y) | |
{ | |
Line(x0 + x, y0 + y, x0 - x, y0 + y, c); | |
Line(x0 + y, y0 + x, x0 - y, y0 + x, c); | |
Line(x0 - x, y0 - y, x0 + x, y0 - y, c); | |
Line(x0 + y, y0 - x, x0 - y, y0 - x, c); | |
if (err <= 0) | |
{ | |
y++; | |
err += dy; | |
dy += 2; | |
} | |
if (err > 0) | |
{ | |
x--; | |
dx += 2; | |
err += dx - (radius << 1); | |
} | |
} | |
} | |
// https://stackoverflow.com/questions/11678693/all-cases-covered-bresenhams-line-algorithm | |
static void Line(int x0, int y0, int x1, int y1, uint c) | |
{ | |
int w = x1 - x0; | |
int h = y1 - y0; | |
int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0; | |
if (w < 0) dx1 = -1; | |
else if (w > 0) dx1 = 1; | |
if (h < 0) dy1 = -1; | |
else if (h > 0) dy1 = 1; | |
if (w < 0) dx2 = -1; | |
else if (w > 0) dx2 = 1; | |
int longest = Math.Abs(w); | |
int shortest = Math.Abs(h); | |
if (!(longest > shortest)) | |
{ | |
longest = Math.Abs(h); | |
shortest = Math.Abs(w); | |
if (h < 0) dy2 = -1; | |
else if (h > 0) dy2 = 1; | |
dx2 = 0; | |
} | |
int numerator = longest >> 1; | |
for (int i = 0; i <= longest; i++) | |
{ | |
Set(x0, y0, c); | |
numerator += shortest; | |
if (!(numerator < longest)) | |
{ | |
numerator -= longest; | |
x0 += dx1; | |
y0 += dy1; | |
} | |
else | |
{ | |
x0 += dx2; | |
y0 += dy2; | |
} | |
} | |
} | |
static float[] palette = | |
{ | |
40 / 255f, 0 / 255f, 40 / 255f, | |
29 / 255f, 43 / 255f, 83 / 255f, | |
126 / 255f, 37 / 255f, 83 / 255f, | |
0 / 255f, 135 / 255f, 81 / 255f, | |
171 / 255f, 82 / 255f, 54 / 255f, | |
95 / 255f, 87 / 255f, 79 / 255f, | |
194 / 255f, 195 / 255f, 199 / 255f, | |
255 / 255f, 241 / 255f, 232 / 255f, | |
255 / 255f, 0 / 255f, 77 / 255f, | |
255 / 255f, 163 / 255f, 0 / 255f, | |
255 / 255f, 236 / 255f, 39 / 255f, | |
0 / 255f, 228 / 255f, 54 / 255f, | |
41 / 255f, 173 / 255f, 255 / 255f, | |
131 / 255f, 118 / 255f, 156 / 255f, | |
255 / 255f, 204 / 255f, 170 / 255f, | |
255 / 255f, 119 / 255f, 168 / 255f, | |
}; | |
static Random rnd = new Random(); | |
private static float t = 0; | |
private static int[] l = {10, 9, 8, 2, 1}; | |
public void Draw1(int w, int h) | |
{ | |
Array.Clear(_frameBuffer, 0, _frameBuffer.Length); | |
rnd = new Random(0); | |
for (int m = 0; m < 99; m++) | |
{ | |
var x = rnd.Next(8) - 4; | |
var z = rnd.Next(8) - 4; | |
var y = rnd.Next(14) - 7; | |
for (int n = 4; n >= 0; n--) | |
{ | |
var a = t / 4 + n * 0.1; | |
var c = Math.Cos(a) * x - Math.Sin(a) * z; | |
var d = Math.Sin(a) * x - Math.Cos(a) * z + 7; | |
var g = 64 + (c * 64) / d; | |
var hh = 64 + (y * 64) / d; | |
FilledCircle((int) g, (int) hh, (int) Math.Max((7 - d) + n / 2, 0), (uint) l[4 - n]); | |
} | |
} | |
t += 0.1f; | |
///////// | |
GL.UseProgram(_mRenderProgramId); | |
GL.BindBuffer(BufferTarget.UniformBuffer, _frameBufferLocation); | |
GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, sizeof(uint) * _frameBuffer.Length, _frameBuffer); | |
GL.Uniform2(GL.GetUniformLocation(_mRenderProgramId, "screen"), (float) w, (float) h); | |
GL.Uniform1(GL.GetUniformLocation(_mRenderProgramId, "width"), _bufferWidth); | |
GL.Uniform3(GL.GetUniformLocation(_mRenderProgramId, "palette"), palette.Length / 3, palette); | |
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); | |
} | |
public void Draw(int w, int h) | |
{ | |
var f = 0.15 * t; | |
Array.Clear(_frameBuffer, 0, _frameBuffer.Length); | |
for (int i = 0; i < 128; i++) | |
{ | |
Line(0, i, i, 0, (uint) ((i * 2 + t * 8) % 16)); | |
Line(128, i, i, 128, (uint) ((i * 2 + t * 8) % 16)); | |
} | |
for (int j = 1; j < 32; j++) | |
{ | |
for (int i = 2; i < 10; i++) | |
{ | |
var y = 0.2 - i / 5.0; | |
var g = y * y * 0.3 + (Math.Sin(f) + 1) * 0.75; | |
var k = j / 2.0; | |
var ww = Math.Cos(f + k) * g - Math.Sin(f + k) * g; | |
var q = Math.Sin(f + k) * g + Math.Cos(f + k) * g + 5; | |
var a = 64 + 64 * ww / q; | |
var b = 64 + 64 * y / q + Math.Sin(0.25 * (f + k + a)) * (Math.Cos(f) * 10); | |
FilledCircle((int) a - 2, (int) b - 2, (int) (6 - q), 0); | |
FilledCircle((int) a - 2, (int) (64 - b + 64) - 2, (int) (6 - q), 0); | |
FilledCircle((int) a, (int) b, (int) (6 - q), (uint) (1 + (i % 2))); | |
FilledCircle((int) a, (int) (64 - b + 64), (int) (6 - q), (uint) (8 + ((i - 2) % 7))); | |
} | |
} | |
t += 0.1f; | |
///////// | |
GL.UseProgram(_mRenderProgramId); | |
GL.BindBuffer(BufferTarget.UniformBuffer, _frameBufferLocation); | |
GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, sizeof(uint) * _frameBuffer.Length, _frameBuffer); | |
GL.Uniform2(GL.GetUniformLocation(_mRenderProgramId, "screen"), (float) w, (float) h); | |
GL.Uniform1(GL.GetUniformLocation(_mRenderProgramId, "width"), _bufferWidth); | |
GL.Uniform3(GL.GetUniformLocation(_mRenderProgramId, "palette"), palette.Length / 3, palette); | |
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4); | |
} | |
private int SetupRenderProgram() | |
{ | |
int progHandle = GL.CreateProgram(); | |
int vp = GL.CreateShader(ShaderType.VertexShader); | |
int fp = GL.CreateShader(ShaderType.FragmentShader); | |
const string vpSrc = @"#version 430 | |
in vec2 pos; | |
void main() { | |
gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); | |
}"; | |
const string fpSrc = @"#version 430 | |
out vec4 color; | |
uniform vec2 screen; | |
uniform uint width; | |
uniform vec3 palette[16]; | |
layout (binding=0, packed) uniform pixelBufferLocation { | |
uint pixelBuffer [16384]; | |
}; | |
void main() { | |
float smallest_side = min(screen.y, screen.x); | |
float biggest_side = max(screen.y, screen.x); | |
float scale = smallest_side / width; | |
vec2 padding = vec2(0.0); | |
if(screen.x <= screen.y) | |
padding.y = (biggest_side - smallest_side) / 2.0; | |
else | |
padding.x = (biggest_side - smallest_side) / 2.0; | |
int ix = int((gl_FragCoord.x - padding.x) / scale); | |
int iy = int((gl_FragCoord.y - padding.y) / scale) * int(width); | |
if(ix < 0 || ix >= width || iy < 0 || iy > width*width) { | |
color = vec4(0.0); | |
} else { | |
int idx = ix + iy; | |
uint c = pixelBuffer[idx]; | |
color = vec4(palette[c], 1.0); | |
} | |
}"; | |
GL.ShaderSource(vp, vpSrc); | |
GL.ShaderSource(fp, fpSrc); | |
GL.CompileShader(vp); | |
int rvalue; | |
GL.GetShader(vp, ShaderParameter.CompileStatus, out rvalue); | |
if (rvalue != (int) All.True) | |
{ | |
Console.WriteLine("Error in compiling vp"); | |
Console.WriteLine((All) rvalue); | |
Console.WriteLine(GL.GetShaderInfoLog(vp)); | |
} | |
GL.AttachShader(progHandle, vp); | |
GL.CompileShader(fp); | |
GL.GetShader(fp, ShaderParameter.CompileStatus, out rvalue); | |
if (rvalue != (int) All.True) | |
{ | |
Console.WriteLine("Error in compiling fp"); | |
Console.WriteLine((All) rvalue); | |
Console.WriteLine(GL.GetShaderInfoLog(fp)); | |
} | |
GL.AttachShader(progHandle, fp); | |
GL.BindFragDataLocation(progHandle, 0, "color"); | |
GL.LinkProgram(progHandle); | |
GL.GetProgram(progHandle, GetProgramParameterName.LinkStatus, out rvalue); | |
if (rvalue != (int) All.True) | |
{ | |
Console.WriteLine("Error in linking sp"); | |
Console.WriteLine((All) rvalue); | |
Console.WriteLine(GL.GetProgramInfoLog(progHandle)); | |
} | |
GL.UseProgram(progHandle); | |
GL.Uniform1(GL.GetUniformLocation(progHandle, "srcTex"), 0); | |
var vertArray = GL.GenVertexArray(); | |
GL.BindVertexArray(vertArray); | |
var posBuf = GL.GenBuffer(); | |
GL.BindBuffer(BufferTarget.ArrayBuffer, posBuf); | |
float[] data = | |
{ | |
-1.0f, -1.0f, | |
-1.0f, 1.0f, | |
1.0f, -1.0f, | |
1.0f, 1.0f | |
}; | |
IntPtr dataSize = (IntPtr) (sizeof(float) * 8); | |
GL.BufferData(BufferTarget.ArrayBuffer, dataSize, data, BufferUsageHint.StreamDraw); | |
int posPtr = GL.GetAttribLocation(progHandle, "pos"); | |
GL.VertexAttribPointer(posPtr, 2, VertexAttribPointerType.Float, false, 0, 0); | |
GL.EnableVertexAttribArray(posPtr); | |
_frameBufferLocation = GL.GenBuffer(); | |
GL.BindBuffer(BufferTarget.UniformBuffer, _frameBufferLocation); | |
GL.BufferData(BufferTarget.UniformBuffer, sizeof(uint) * _frameBuffer.Length, _frameBuffer, | |
BufferUsageHint.StreamDraw); | |
var blockIndex = GL.GetUniformBlockIndex(progHandle, "pixelBufferLocation"); | |
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, _frameBufferLocation); // TODO 0?? | |
GL.UniformBlockBinding(progHandle, blockIndex, 0); // TODO 0?? | |
GL.GenTexture(); | |
return progHandle; | |
} | |
} | |
static class MainClass | |
{ | |
static void StatusPrint(StringName n) | |
{ | |
Console.WriteLine("{0}: {1}", n, GL.GetString(n)); | |
} | |
static void StatusPrint(GetPName n) | |
{ | |
Console.WriteLine("{0}: {1}", n, GL.GetInteger(n)); | |
} | |
[STAThread] | |
public static void Main(string[] args) | |
{ | |
const int width = 1024 * 4; | |
const int height = 1024 * 4; | |
using (var game = new GameWindow(width, height, GraphicsMode.Default, "Pico", GameWindowFlags.Default, | |
DisplayDevice.Default, 4, 5, GraphicsContextFlags.Default)) | |
{ | |
Demo d = new Demo(); | |
StatusPrint(GetPName.MaxUniformBlockSize); | |
game.Load += (sender, e) => | |
{ | |
// setup settings, load textures, sounds | |
d.Initialize(); | |
game.VSync = VSyncMode.On; | |
StatusPrint(StringName.Renderer); | |
StatusPrint(StringName.ShadingLanguageVersion); | |
StatusPrint(StringName.Vendor); | |
StatusPrint(StringName.Version); | |
StatusPrint(GetPName.MaxFragmentUniformComponents); | |
StatusPrint(GetPName.MaxFragmentUniformVectors); | |
StatusPrint(GetPName.MaxUniformBlockSize); | |
}; | |
game.RenderFrame += (sender, e) => | |
{ | |
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); | |
d.Draw(game.Width, game.Height); | |
game.SwapBuffers(); | |
// Console.WriteLine(game.RenderFrequency); | |
}; | |
game.Resize += (sender, e) => { GL.Viewport(0, 0, game.Width, game.Height); }; | |
game.Run(60.0); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment