diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..add57be
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+bin/
+obj/
+/packages/
+riderModule.iml
+/_ReSharper.Caches/
\ No newline at end of file
diff --git a/.idea/.idea.shdr/.idea/.gitignore b/.idea/.idea.shdr/.idea/.gitignore
new file mode 100644
index 0000000..cd90912
--- /dev/null
+++ b/.idea/.idea.shdr/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/.idea.shdr.iml
+/projectSettingsUpdater.xml
+/modules.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.shdr/.idea/discord.xml b/.idea/.idea.shdr/.idea/discord.xml
new file mode 100644
index 0000000..cf77f1e
--- /dev/null
+++ b/.idea/.idea.shdr/.idea/discord.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.shdr/.idea/encodings.xml b/.idea/.idea.shdr/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.shdr/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.shdr/.idea/indexLayout.xml b/.idea/.idea.shdr/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.shdr/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/before.bat b/before.bat
new file mode 100644
index 0000000..65d82f2
--- /dev/null
+++ b/before.bat
@@ -0,0 +1,2 @@
+xcopy "C:\Users\richard may clarkson\RiderProjects\shdr\shdr\Resource" "C:\Users\richard may clarkson\RiderProjects\shdr\shdr\bin\Debug\net6.0\Resource" /E /H /C /R /Q /Y
+xcopy "C:\Users\richard may clarkson\RiderProjects\shdr\shdr\Resource" "C:\Users\richard may clarkson\RiderProjects\shdr\shdr\bin\Release\net6.0\Resource" /E /H /C /R /Q /Y
\ No newline at end of file
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..9e5e1fd
--- /dev/null
+++ b/global.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "6.0.0",
+ "rollForward": "latestMajor",
+ "allowPrerelease": true
+ }
+}
\ No newline at end of file
diff --git a/shdr.sln b/shdr.sln
new file mode 100644
index 0000000..f8dcd1c
--- /dev/null
+++ b/shdr.sln
@@ -0,0 +1,16 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shdr", "shdr\shdr.csproj", "{5F7BB6FD-5D0B-4E3A-8D87-295F9802F734}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5F7BB6FD-5D0B-4E3A-8D87-295F9802F734}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5F7BB6FD-5D0B-4E3A-8D87-295F9802F734}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5F7BB6FD-5D0B-4E3A-8D87-295F9802F734}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5F7BB6FD-5D0B-4E3A-8D87-295F9802F734}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/shdr.sln.DotSettings.user b/shdr.sln.DotSettings.user
new file mode 100644
index 0000000..e25f193
--- /dev/null
+++ b/shdr.sln.DotSettings.user
@@ -0,0 +1,6 @@
+
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
+ <Policy Inspect="True" Prefix="__" Suffix="" Style="aa_bb" />
+ <AssemblyExplorer>
+ <Assembly Path="C:\Users\richard may clarkson\RiderProjects\shdr\shdr\bin\Debug\net6.0\NAudio.Core.dll" />
+</AssemblyExplorer>
\ No newline at end of file
diff --git a/shdr/Engine/Fbo.cs b/shdr/Engine/Fbo.cs
new file mode 100644
index 0000000..ca391da
--- /dev/null
+++ b/shdr/Engine/Fbo.cs
@@ -0,0 +1,136 @@
+using OpenTK.Graphics.OpenGL4;
+
+namespace shdr.Engine
+{
+ public class __fbo
+ {
+ private static int _active;
+ private static readonly Dictionary _frames = new();
+ private readonly bool _useDepth;
+ private int _colorAttachment;
+ private int _depthAttachment;
+ public int handle;
+ private int _height;
+ private int _width;
+
+ public __fbo(int width, int height)
+ {
+ _width = width;
+ _height = height;
+ _useDepth = false;
+ handle = -1;
+ init();
+ _frames[handle] = this;
+ }
+
+ public __fbo(int width, int height, bool useDepth)
+ {
+ _width = width;
+ _height = height;
+ _useDepth = useDepth;
+ handle = -1;
+ init();
+ _frames[handle] = this;
+ }
+
+ private void dispose()
+ {
+ GL.DeleteFramebuffer(handle);
+ GL.DeleteTexture(_colorAttachment);
+ if (_useDepth) GL.DeleteTexture(_depthAttachment);
+ }
+
+ private void init()
+ {
+ if (handle != -1) dispose();
+
+ handle = GL.GenFramebuffer();
+ bind();
+ _colorAttachment = GL.GenTexture();
+ GL.BindTexture(TextureTarget.Texture2D, _colorAttachment);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS,
+ (int)TextureWrapMode.ClampToBorder);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT,
+ (int)TextureWrapMode.ClampToBorder);
+ GL.TexStorage2D(TextureTarget2d.Texture2D, 1, SizedInternalFormat.Rgba8, _width, _height);
+ GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0,
+ TextureTarget.Texture2D, _colorAttachment, 0);
+ if (_useDepth)
+ {
+ _depthAttachment = GL.GenTexture();
+ GL.BindTexture(TextureTarget.Texture2D, _depthAttachment);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter,
+ (int)TextureMinFilter.Nearest);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter,
+ (int)TextureMagFilter.Nearest);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureCompareMode,
+ (int)TextureCompareMode.None);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS,
+ (int)TextureWrapMode.ClampToEdge);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT,
+ (int)TextureWrapMode.ClampToEdge);
+ GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.DepthComponent, _width, _height, 0,
+ PixelFormat.DepthComponent, PixelType.UnsignedInt, IntPtr.Zero);
+ GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment,
+ TextureTarget.Texture2D, _depthAttachment, 0);
+ }
+
+ FramebufferErrorCode status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
+ if (status != FramebufferErrorCode.FramebufferComplete)
+ throw new Exception(
+ $"Incomplete Framebuffer! {status} should be {FramebufferErrorCode.FramebufferComplete}");
+
+ unbind();
+ }
+
+ private void _resize(int width, int height)
+ {
+ _width = width;
+ _height = height;
+ init();
+ }
+
+ public static void resize(int width, int height)
+ {
+ foreach (KeyValuePair frame in _frames) frame.Value._resize(width, height);
+ }
+
+ public void bind_color(TextureUnit unit)
+ {
+ GL.ActiveTexture(unit);
+ GL.BindTexture(TextureTarget.Texture2D, _colorAttachment);
+ }
+
+ public int bind_depth(TextureUnit unit)
+ {
+ if (!_useDepth) throw new Exception("Trying to bind depth texture of a framebuffer without depth!");
+ GL.ActiveTexture(unit);
+ GL.BindTexture(TextureTarget.Texture2D, _depthAttachment);
+ return _depthAttachment;
+ }
+
+ public void bind()
+ {
+ if (handle == _active) return;
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, handle);
+ _active = handle;
+ }
+
+ public void blit(int handle = 0)
+ {
+ GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, this.handle);
+ GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, handle);
+ GL.BlitFramebuffer(0, 0, _width, _height, 0, 0, _width, _height, ClearBufferMask.ColorBufferBit,
+ BlitFramebufferFilter.Nearest);
+ unbind();
+ }
+
+ public static void unbind()
+ {
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
+ _active = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/Font.cs b/shdr/Engine/Font.cs
new file mode 100644
index 0000000..6040eeb
--- /dev/null
+++ b/shdr/Engine/Font.cs
@@ -0,0 +1,185 @@
+using OpenTK.Graphics.OpenGL4;
+using shdr.Shared;
+using StbTrueTypeSharp;
+
+namespace shdr.Engine
+{
+ public static class __font
+ {
+ private const float ipw = 1.0f / 2048f;
+ private const float iph = ipw;
+ private static readonly float[] _ascent;
+ private static readonly StbTrueType.stbtt_packedchar[][] _chars;
+
+ private static readonly __mesh _mesh;
+ private static readonly __texture[] _texture;
+
+ private static readonly KeyValuePair[] _paths = {
+ new("Resource/Font/Dank Mono Italic.otf", 18),
+ new("Resource/Font/JetBrainsMono-Regular.ttf", 20),
+ new("Resource/Font/monofur-regular.ttf", 19)
+ };
+
+
+ private static int _index;
+ public static int index
+ {
+ set => _index = value % _paths.Length;
+ get => _index;
+ }
+
+ // I have absolutely no idea how to use unsafe :((
+ static unsafe __font()
+ {
+ _mesh = new __mesh(
+ __mesh.__draw_mode.triangle,
+ new __shader("Resource/Shader/font.vert", "Resource/Shader/font.frag"),
+ __vao.__attrib.float3, __vao.__attrib.float2, __vao.__attrib.float4
+ );
+
+ _chars = new StbTrueType.stbtt_packedchar[_paths.Length][];
+ _ascent = new float[_paths.Length];
+ _texture = new __texture[_paths.Length];
+
+ for (int i = 0; i < _paths.Length; i++)
+ {
+ int height = _paths[i].Value;
+ _chars[i] = new StbTrueType.stbtt_packedchar[256];
+ byte[] buffer = File.ReadAllBytes(_paths[i].Key);
+ StbTrueType.stbtt_fontinfo fontInfo = StbTrueType.CreateFont(buffer, 0);
+
+ StbTrueType.stbtt_pack_context packContext = new();
+
+ byte[] bitmap = new byte[2048 * 2048];
+ fixed (byte* dat = bitmap)
+ {
+ StbTrueType.stbtt_PackBegin(packContext, dat, 2048, 2048, 0, 1, null);
+ }
+
+ StbTrueType.stbtt_PackSetOversampling(packContext, 8, 8);
+ fixed (byte* dat = buffer)
+ {
+ fixed (StbTrueType.stbtt_packedchar* c = _chars[i])
+ {
+ StbTrueType.stbtt_PackFontRange(packContext, dat, 0, height, 32, 256, c);
+ }
+ }
+
+ StbTrueType.stbtt_PackEnd(packContext);
+
+ int asc;
+ StbTrueType.stbtt_GetFontVMetrics(fontInfo, &asc, null, null);
+ _ascent[i] = asc * StbTrueType.stbtt_ScaleForPixelHeight(fontInfo, height);
+
+ _texture[i] = __texture.load_from_buffer(bitmap, 2048, 2048, PixelFormat.Red, PixelInternalFormat.R8,
+ TextureMinFilter.Nearest, TextureMagFilter.Nearest);
+ }
+ }
+
+ public static void bind()
+ {
+ _texture[index].bind(TextureUnit.Texture0);
+ _mesh.begin();
+ }
+
+ public static void render()
+ {
+ _mesh.render();
+ __texture.unbind();
+ }
+
+ public static void draw(string text, float x, float y, uint color, bool shadow, float scale = 1.0f)
+ {
+ int length = text.Length;
+ float drawX = x;
+ float drawY = y + _ascent[index] * scale;
+ float alpha = ((color >> 24) & 0xFF) / 255.0f;
+ float red = ((color >> 16) & 0xFF) / 255.0f;
+ float green = ((color >> 8) & 0xFF) / 255.0f;
+ float blue = (color & 0xFF) / 255.0f;
+ for (int i = 0; i < length; i++)
+ {
+ char charCode = text[i];
+ char previous = i > 0 ? text[i - 1] : ' ';
+ if (previous == '\u00a7') continue;
+
+ if (charCode == '\u00a7' && i < length - 1)
+ {
+ char next = text[i + 1];
+ if (__fmt.values.TryGetValue(next, out __fmt fmt))
+ {
+ uint newColor = fmt.color;
+ red = ((newColor >> 16) & 0xFF) / 255.0f;
+ green = ((newColor >> 8) & 0xFF) / 255.0f;
+ blue = (newColor & 0xFF) / 255.0f;
+ }
+
+ continue;
+ }
+
+ if (charCode < 32 || charCode > 32 + 256) charCode = ' ';
+
+ StbTrueType.stbtt_packedchar c = _chars[index][charCode - 32];
+
+ float dxs = drawX + c.xoff * scale;
+ float dys = drawY + c.yoff * scale;
+ float dx1S = drawX + c.xoff2 * scale;
+ float dy1S = drawY + c.yoff2 * scale;
+
+ if (shadow)
+ {
+ int j1 = _mesh.float3(dxs + scale * 1.5f, dys + scale * 1.5f, 1).float2(c.x0 * ipw, c.y0 * iph)
+ .float4(red * 0, green * 0, blue * 0, alpha).next();
+ int j2 = _mesh.float3(dxs + scale * 1.5f, dy1S + scale * 1.5f, 1).float2(c.x0 * ipw, c.y1 * iph)
+ .float4(red * 0, green * 0, blue * 0, alpha).next();
+ int j3 = _mesh.float3(dx1S + scale * 1.5f, dy1S + scale * 1.5f, 1).float2(c.x1 * ipw, c.y1 * iph)
+ .float4(red * 0, green * 0, blue * 0, alpha).next();
+ int j4 = _mesh.float3(dx1S + scale * 1.5f, dys + scale * 1.5f, 1).float2(c.x1 * ipw, c.y0 * iph)
+ .float4(red * 0, green * 0, blue * 0, alpha).next();
+ _mesh.quad(j1, j2, j3, j4);
+ }
+
+ int k1 = _mesh.float3(dxs, dys, 0).float2(c.x0 * ipw, c.y0 * iph)
+ .float4(red, green, blue, alpha).next();
+ int k2 = _mesh.float3(dxs, dy1S, 0).float2(c.x0 * ipw, c.y1 * iph)
+ .float4(red, green, blue, alpha).next();
+ int k3 = _mesh.float3(dx1S, dy1S, 0).float2(c.x1 * ipw, c.y1 * iph)
+ .float4(red, green, blue, alpha).next();
+ int k4 = _mesh.float3(dx1S, dys, 0).float2(c.x1 * ipw, c.y0 * iph)
+ .float4(red, green, blue, alpha).next();
+ _mesh.quad(k1, k2, k3, k4);
+
+ drawX += c.xadvance * scale;
+ drawX -= 0.4f * scale;
+ }
+ }
+
+ public static float get_width(string text, float scale = 1.0f)
+ {
+ int length = text.Length;
+ float width = 0;
+ for (int i = 0; i < length; i++)
+ {
+ char charCode = text[i];
+ char previous = i > 0 ? text[i - 1] : ' ';
+ if (previous == '\u00a7') continue;
+
+ if (charCode < 32 || charCode > 32 + 256) charCode = ' ';
+
+ StbTrueType.stbtt_packedchar c = _chars[index][charCode - 32];
+
+ width += c.xadvance * scale;
+ width -= 0.4f * scale;
+ }
+
+ width += 0.4f * scale;
+
+ return width;
+ }
+
+ public static float get_height(float scale = 1.0f)
+ {
+ return _ascent[index] * scale;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/GlStateManager.cs b/shdr/Engine/GlStateManager.cs
new file mode 100644
index 0000000..fbd494f
--- /dev/null
+++ b/shdr/Engine/GlStateManager.cs
@@ -0,0 +1,83 @@
+using OpenTK.Graphics.OpenGL4;
+
+namespace shdr.Engine
+{
+ public static class __gl_state_manager
+ {
+ private static bool _depthEnabled;
+ private static bool _blendEnabled;
+ private static bool _cullEnabled;
+
+ private static bool _depthSaved;
+ private static bool _blendSaved;
+ private static bool _cullSaved;
+
+ public static void save_state()
+ {
+ _depthSaved = _depthEnabled;
+ _blendSaved = _blendEnabled;
+ _cullSaved = _cullEnabled;
+ }
+
+ public static void restore_state()
+ {
+ if (_depthSaved)
+ enable_depth();
+ else
+ disable_depth();
+ if (_blendSaved)
+ enable_blend();
+ else
+ disable_blend();
+ if (_cullSaved)
+ enable_cull();
+ else
+ disable_cull();
+ }
+
+ public static void enable_depth()
+ {
+ if (_depthEnabled) return;
+ _depthEnabled = true;
+ GL.Enable(EnableCap.DepthTest);
+ }
+
+ public static void disable_depth()
+ {
+ if (!_depthEnabled) return;
+ _depthEnabled = false;
+ GL.Disable(EnableCap.DepthTest);
+ }
+
+ public static void enable_blend()
+ {
+ if (_blendEnabled) return;
+ _blendEnabled = true;
+ GL.Enable(EnableCap.Blend);
+ GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+ }
+
+ public static void disable_blend()
+ {
+ if (_blendEnabled)
+ {
+ _blendEnabled = false;
+ GL.Disable(EnableCap.Blend);
+ }
+ }
+
+ public static void enable_cull()
+ {
+ if (_cullEnabled) return;
+ _cullEnabled = true;
+ GL.Enable(EnableCap.CullFace);
+ }
+
+ public static void disable_cull()
+ {
+ if (!_cullEnabled) return;
+ _cullEnabled = false;
+ GL.Disable(EnableCap.CullFace);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/Ibo.cs b/shdr/Engine/Ibo.cs
new file mode 100644
index 0000000..2778a8c
--- /dev/null
+++ b/shdr/Engine/Ibo.cs
@@ -0,0 +1,50 @@
+using OpenTK.Graphics.OpenGL4;
+
+namespace shdr.Engine
+{
+ public class __ibo
+ {
+ private static int _active;
+ private readonly byte[] _bitDest = new byte[4];
+ private readonly int _handle;
+ private readonly MemoryStream _indices;
+
+ public __ibo(int initialCapacity)
+ {
+ _handle = GL.GenBuffer();
+ _indices = new MemoryStream(initialCapacity);
+ }
+
+ public void bind()
+ {
+ if (_handle == _active) return;
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, _handle);
+ _active = _handle;
+ }
+
+ public static void unbind()
+ {
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
+ _active = 0;
+ }
+
+ public void put(int element)
+ {
+ BitConverter.TryWriteBytes(_bitDest, element);
+ _indices.Write(_bitDest);
+ }
+
+ public void upload(bool unbindAfter = true)
+ {
+ if (_active != _handle) bind();
+ GL.BufferData(BufferTarget.ElementArrayBuffer, (int)_indices.Length, _indices.GetBuffer(),
+ BufferUsageHint.DynamicDraw);
+ if (unbindAfter) unbind();
+ }
+
+ public void clear()
+ {
+ _indices.SetLength(0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/Mesh.cs b/shdr/Engine/Mesh.cs
new file mode 100644
index 0000000..c99bcbc
--- /dev/null
+++ b/shdr/Engine/Mesh.cs
@@ -0,0 +1,218 @@
+using OpenTK.Graphics.OpenGL4;
+using OpenTK.Mathematics;
+using shdr.Shared;
+
+namespace shdr.Engine
+{
+ public class __mesh
+ {
+ private readonly __draw_mode _drawMode;
+ private readonly __ibo _ibo;
+ private readonly __shader _shader;
+
+ private readonly __vao _vao;
+ private readonly __vbo _vbo;
+ private bool _building;
+ private int _index;
+ private int _vertex;
+
+ public __mesh(__draw_mode drawMode, __shader shader, params __vao.__attrib[] attribs)
+ {
+ _drawMode = drawMode;
+ _shader = shader;
+ int stride = attribs.Sum(attrib => (int)attrib * sizeof(float));
+ _vbo = new __vbo(stride * drawMode.size * 256 * sizeof(float));
+ _vbo.bind();
+ _ibo = new __ibo(drawMode.size * 512 * sizeof(float));
+ _ibo.bind();
+ _vao = new __vao(attribs);
+ __vbo.unbind();
+ __ibo.unbind();
+ __vao.unbind();
+ }
+
+ public int next()
+ {
+ return _vertex++;
+ }
+
+ public __mesh float1(float p0)
+ {
+ _vbo.put(p0);
+ return this;
+ }
+
+ public __mesh float2(float p0, float p1)
+ {
+ _vbo.put(p0);
+ _vbo.put(p1);
+ return this;
+ }
+
+ public __mesh float2(Vector2 p0)
+ {
+ _vbo.put(p0.X);
+ _vbo.put(p0.Y);
+ return this;
+ }
+
+ public __mesh float3(float p0, float p1, float p2)
+ {
+ _vbo.put(p0);
+ _vbo.put(p1);
+ _vbo.put(p2);
+ return this;
+ }
+
+ public __mesh float3(Matrix4 transform, float p0, float p1, float p2)
+ {
+ Vector4 pos = new(p0, p1, p2, 1);
+ pos.transform(transform);
+ _vbo.put(pos.X);
+ _vbo.put(pos.Y);
+ _vbo.put(pos.Z);
+ return this;
+ }
+
+ public __mesh float3(Vector3 p0)
+ {
+ _vbo.put(p0.X);
+ _vbo.put(p0.Y);
+ _vbo.put(p0.Z);
+ return this;
+ }
+
+ public __mesh float4(float p0, float p1, float p2, float p3)
+ {
+ _vbo.put(p0);
+ _vbo.put(p1);
+ _vbo.put(p2);
+ _vbo.put(p3);
+ return this;
+ }
+
+ public __mesh float4(uint color)
+ {
+ return float4(((color >> 16) & 0xff) * 0.003921569f, ((color >> 8) & 0xff) * 0.003921569f,
+ (color & 0xff) * 0.003921569f, ((color >> 24) & 0xff) * 0.003921569f);
+ }
+
+ public __mesh float4(uint color, float alpha)
+ {
+ return float4(((color >> 16) & 0xff) * 0.003921569f, ((color >> 8) & 0xff) * 0.003921569f,
+ (color & 0xff) * 0.003921569f, alpha);
+ }
+
+ public void line(int p0, int p1)
+ {
+ _ibo.put(p0);
+ _ibo.put(p1);
+ _index += 2;
+ }
+
+ public void tri(int p0, int p1, int p2)
+ {
+ _ibo.put(p0);
+ _ibo.put(p1);
+ _ibo.put(p2);
+ _index += 3;
+ }
+
+ public void quad(int p0, int p1, int p2, int p3)
+ {
+ _ibo.put(p0);
+ _ibo.put(p1);
+ _ibo.put(p2);
+ _ibo.put(p2);
+ _ibo.put(p3);
+ _ibo.put(p0);
+ _index += 6;
+ }
+
+ public void begin()
+ {
+ if (_building) throw new Exception("Already building");
+ _vbo.clear();
+ _ibo.clear();
+ _vertex = 0;
+ _index = 0;
+ _building = true;
+ }
+
+ public void end()
+ {
+ if (!_building) throw new Exception("Not building");
+
+ if (_index > 0)
+ {
+ _vbo.upload();
+ _ibo.upload();
+ }
+
+ _building = false;
+ }
+
+ public void render()
+ {
+ if (_building) end();
+
+ if (_index <= 0) return;
+ __gl_state_manager.save_state();
+ __gl_state_manager.enable_blend();
+ if (__render_system.rendering3d)
+ __gl_state_manager.enable_depth();
+ else
+ __gl_state_manager.disable_depth();
+ _shader?.bind();
+ _shader?.set_defaults();
+ _vao.bind();
+ _ibo.bind();
+ _vbo.bind();
+ GL.DrawElements(_drawMode.as_gl(), _index, DrawElementsType.UnsignedInt, 0);
+ __ibo.unbind();
+ __vbo.unbind();
+ __vao.unbind();
+ __gl_state_manager.restore_state();
+ }
+
+ public sealed class __draw_mode
+ {
+ private static int _cidCounter;
+
+ public static readonly __draw_mode line = new(2);
+ public static readonly __draw_mode triangle = new(3);
+ public static readonly __draw_mode triangleFan = new(3);
+ private readonly int _cid;
+ public readonly int size;
+
+ private __draw_mode(int size)
+ {
+ this.size = size;
+ _cid = _cidCounter++;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is __draw_mode mode) return _cid == mode._cid;
+
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return _cid;
+ }
+
+ public BeginMode as_gl()
+ {
+ return _cid switch
+ {
+ 0 => BeginMode.Lines,
+ 1 => BeginMode.Triangles,
+ 2 => BeginMode.TriangleFan,
+ _ => throw new Exception("wtf is going on?")
+ };
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/RenderSystem.cs b/shdr/Engine/RenderSystem.cs
new file mode 100644
index 0000000..882262c
--- /dev/null
+++ b/shdr/Engine/RenderSystem.cs
@@ -0,0 +1,56 @@
+using OpenTK.Graphics.OpenGL4;
+using OpenTK.Mathematics;
+using OpenTK.Windowing.GraphicsLibraryFramework;
+
+namespace shdr.Engine
+{
+ public static class __render_system
+ {
+ private static readonly __shader _basic = new("Resource/Shader/basic.vert", "Resource/Shader/basic.frag");
+
+ public static __shader user = null;
+
+ private static Matrix4 _projection;
+ private static Matrix4 _lookAt;
+ private static readonly Matrix4[] _model = new Matrix4[7];
+ private static int _modelIdx;
+
+ public static readonly __mesh basic = new(__mesh.__draw_mode.triangle, _basic, __vao.__attrib.float3, __vao.__attrib.float4);
+
+ public static readonly __mesh post = new(__mesh.__draw_mode.triangle, null, __vao.__attrib.float2);
+ public static readonly __fbo frame = new(__shdr.instance.Size.X, __shdr.instance.Size.Y, true);
+ public static readonly __fbo prevFrame = new(__shdr.instance.Size.X, __shdr.instance.Size.Y, true);
+ public static bool rendering3d;
+
+ static __render_system()
+ {
+ Array.Fill(_model, Matrix4.Identity);
+ }
+
+ public static ref Matrix4 model => ref _model[_modelIdx];
+
+ public static Vector2i size => __shdr.instance.Size;
+
+ public static void push()
+ {
+ _model[_modelIdx + 1] = model;
+ _modelIdx++;
+ }
+
+ public static void pop()
+ {
+ _modelIdx--;
+ }
+
+ public static void set_defaults(this __shader shader)
+ {
+ shader.set_matrix4("_proj", _projection);
+ shader.set_float("_time", (float)GLFW.GetTime());
+ }
+
+ public static void update_projection()
+ {
+ Matrix4.CreateOrthographicOffCenter(0, __shdr.instance.Size.X, __shdr.instance.Size.Y, 0, -1, 1, out _projection);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/Shader.cs b/shdr/Engine/Shader.cs
new file mode 100644
index 0000000..3569a24
--- /dev/null
+++ b/shdr/Engine/Shader.cs
@@ -0,0 +1,164 @@
+using OpenTK.Graphics.OpenGL4;
+using OpenTK.Mathematics;
+
+namespace shdr.Engine
+{
+ // taken from https://github.com/opentk/LearnOpenTK/blob/master/Common/Shader.cs
+ public class __shader
+ {
+ private static int _active;
+ private readonly int _handle;
+ private readonly Dictionary _uniformLocations;
+
+ public __shader(string vertPath, string fragPath, string geomPath = null)
+ {
+ string shaderSource = File.ReadAllText(vertPath);
+ int vertexShader = GL.CreateShader(ShaderType.VertexShader);
+ GL.ShaderSource(vertexShader, shaderSource);
+ compile_shader(vertexShader);
+
+ shaderSource = File.ReadAllText(fragPath);
+ int fragmentShader = GL.CreateShader(ShaderType.FragmentShader);
+ GL.ShaderSource(fragmentShader, shaderSource);
+ compile_shader(fragmentShader);
+
+ int geometryShader = -1;
+ if (geomPath != null)
+ {
+ shaderSource = File.ReadAllText(geomPath);
+ geometryShader = GL.CreateShader(ShaderType.GeometryShader);
+ GL.ShaderSource(geometryShader, shaderSource);
+ compile_shader(geometryShader);
+ }
+
+ _handle = GL.CreateProgram();
+
+ GL.AttachShader(_handle, vertexShader);
+ GL.AttachShader(_handle, fragmentShader);
+ if (geometryShader != -1) GL.AttachShader(_handle, geometryShader);
+
+ link_program(_handle);
+
+ GL.DetachShader(_handle, vertexShader);
+ GL.DetachShader(_handle, fragmentShader);
+ if (geometryShader != -1) GL.DetachShader(_handle, geometryShader);
+ GL.DeleteShader(fragmentShader);
+ GL.DeleteShader(vertexShader);
+ if (geometryShader != -1) GL.DeleteShader(geometryShader);
+
+ GL.GetProgram(_handle, GetProgramParameterName.ActiveUniforms, out int numberOfUniforms);
+
+ _uniformLocations = new Dictionary();
+
+ for (int i = 0; i < numberOfUniforms; i++)
+ {
+ string key = GL.GetActiveUniform(_handle, i, out _, out _);
+ int location = GL.GetUniformLocation(_handle, key);
+ _uniformLocations.Add(key, location);
+ }
+ }
+
+ private static void compile_shader(int shader)
+ {
+ GL.CompileShader(shader);
+
+ GL.GetShader(shader, ShaderParameter.CompileStatus, out int code);
+ if (code == (int)All.True) return;
+ string infoLog = GL.GetShaderInfoLog(shader);
+ throw new Exception($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}");
+ }
+
+ private static void link_program(int program)
+ {
+ GL.LinkProgram(program);
+
+ GL.GetProgram(program, GetProgramParameterName.LinkStatus, out int code);
+ if (code == (int)All.True) return;
+ string infoLog = GL.GetProgramInfoLog(program);
+ throw new Exception($"Error occurred whilst linking Program({program}) \n\n{infoLog}");
+ }
+
+ public void bind()
+ {
+ if (_handle == _active) return;
+ GL.UseProgram(_handle);
+ _active = _handle;
+ }
+
+ public static void unbind()
+ {
+ GL.UseProgram(0);
+ _active = 0;
+ }
+
+ public int get_attrib_location(string attribName)
+ {
+ return GL.GetAttribLocation(_handle, attribName);
+ }
+
+ ///
+ /// Set a uniform int on this shader.
+ ///
+ /// The name of the uniform
+ /// The data to set
+ public void set_int(string name, int data)
+ {
+ if (!_uniformLocations.ContainsKey(name)) return;
+ bind();
+ GL.Uniform1(_uniformLocations[name], data);
+ }
+
+ ///
+ /// Set a uniform float on this shader.
+ ///
+ /// The name of the uniform
+ /// The data to set
+ public void set_float(string name, float data)
+ {
+ if (!_uniformLocations.ContainsKey(name)) return;
+ bind();
+ GL.Uniform1(_uniformLocations[name], data);
+ }
+
+ ///
+ /// Set a uniform Matrix4 on this shader
+ ///
+ /// The name of the uniform
+ /// The data to set
+ ///
+ ///
+ /// The matrix is transposed before being sent to the shader.
+ ///
+ ///
+ public void set_matrix4(string name, Matrix4 data)
+ {
+ if (!_uniformLocations.ContainsKey(name)) return;
+ bind();
+ GL.UniformMatrix4(_uniformLocations[name], true, ref data);
+ }
+
+ ///
+ /// Set a uniform Vector3 on this shader.
+ ///
+ /// The name of the uniform
+ /// The data to set
+ public void set_vector3(string name, Vector3 data)
+ {
+ if (!_uniformLocations.ContainsKey(name)) return;
+ bind();
+ GL.Uniform3(_uniformLocations[name], data);
+ }
+
+ ///
+ /// Set a uniform Vector2 on this shader.
+ ///
+ /// The name of the uniform
+ /// The data to set
+ public void set_vector2(string name, Vector2 data)
+ {
+ if (!_uniformLocations.ContainsKey(name)) return;
+ bind();
+ GL.Uniform2(_uniformLocations[name], data);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/Texture.cs b/shdr/Engine/Texture.cs
new file mode 100644
index 0000000..e4b0bc1
--- /dev/null
+++ b/shdr/Engine/Texture.cs
@@ -0,0 +1,112 @@
+using OpenTK.Graphics.OpenGL4;
+using OpenTK.Mathematics;
+using StbImageSharp;
+
+namespace shdr.Engine
+{
+ // taken from https://github.com/opentk/LearnOpenTK/blob/master/Common/Texture.cs
+ public class __texture
+ {
+ private static int _active;
+ private static readonly Dictionary _textures = new();
+ private readonly int _handle;
+ public readonly float height;
+
+ public readonly float width;
+
+ private __texture(int glHandle, int width, int height)
+ {
+ _handle = glHandle;
+ this.width = width;
+ this.height = height;
+ _textures[glHandle] = this;
+ }
+
+ public static __texture load_from_file(string path)
+ {
+ int handle = GL.GenTexture();
+
+ GL.ActiveTexture(TextureUnit.Texture0);
+ GL.BindTexture(TextureTarget.Texture2D, handle);
+
+ StbImage.stbi_set_flip_vertically_on_load(1);
+ using Stream stream = File.OpenRead(path);
+ ImageResult image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
+
+ GL.TexImage2D(TextureTarget.Texture2D,
+ 0,
+ PixelInternalFormat.Rgba,
+ image.Width,
+ image.Height,
+ 0,
+ PixelFormat.Bgra,
+ PixelType.UnsignedByte,
+ image.Data);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter,
+ (int)TextureMinFilter.NearestMipmapNearest);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
+
+ GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
+
+ return new __texture(handle, image.Width, image.Height);
+ }
+
+ public static __texture load_from_buffer(byte[] buffer, int width, int height, PixelFormat format,
+ PixelInternalFormat internalFormat, TextureMinFilter minFilter = TextureMinFilter.LinearMipmapLinear,
+ TextureMagFilter magFilter = TextureMagFilter.Linear)
+ {
+ int handle = GL.GenTexture();
+
+ GL.ActiveTexture(TextureUnit.Texture0);
+ GL.BindTexture(TextureTarget.Texture2D, handle);
+
+#pragma warning disable CA1416
+ GL.TexImage2D(TextureTarget.Texture2D,
+ 0,
+ internalFormat,
+ width,
+ height,
+ 0,
+ format,
+ PixelType.UnsignedByte,
+ buffer);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)minFilter);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)magFilter);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
+
+ if (minFilter is TextureMinFilter.LinearMipmapLinear or TextureMinFilter.LinearMipmapNearest or TextureMinFilter.NearestMipmapNearest)
+ GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
+
+ return new __texture(handle, width, height);
+#pragma warning restore CA1416
+ }
+
+ public void bind(TextureUnit unit)
+ {
+ if (_handle == _active) return;
+ GL.ActiveTexture(unit);
+ GL.BindTexture(TextureTarget.Texture2D, _handle);
+ _active = _handle;
+ }
+
+ public static void unbind()
+ {
+ GL.BindTexture(TextureTarget.Texture2D, 0);
+ _active = 0;
+ }
+
+ public static Vector2 current_bounds()
+ {
+ if (!_textures.ContainsKey(_active)) return new Vector2(1, 1);
+ __texture current = _textures[_active];
+ return new Vector2(current.width, current.height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/Vao.cs b/shdr/Engine/Vao.cs
new file mode 100644
index 0000000..e815d68
--- /dev/null
+++ b/shdr/Engine/Vao.cs
@@ -0,0 +1,48 @@
+using OpenTK.Graphics.OpenGL4;
+
+namespace shdr.Engine
+{
+ public class __vao
+ {
+ public enum __attrib
+ {
+ float1 = 1,
+ float2 = 2,
+ float3 = 3,
+ float4 = 4
+ }
+
+ private static int _active;
+ private readonly int _handle;
+
+ public __vao(params __attrib[] attribs)
+ {
+ _handle = GL.GenVertexArray();
+ bind();
+ int stride = attribs.Sum(attrib => (int)attrib);
+ int offset = 0;
+ for (int i = 0; i < attribs.Length; i++)
+ {
+ GL.EnableVertexAttribArray(i);
+ GL.VertexAttribPointer(i, (int)attribs[i], VertexAttribPointerType.Float, false, stride * sizeof(float),
+ offset);
+ offset += (int)attribs[i] * sizeof(float);
+ }
+
+ unbind();
+ }
+
+ public void bind()
+ {
+ if (_handle == _active) return;
+ GL.BindVertexArray(_handle);
+ _active = _handle;
+ }
+
+ public static void unbind()
+ {
+ GL.BindVertexArray(0);
+ _active = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/Vbo.cs b/shdr/Engine/Vbo.cs
new file mode 100644
index 0000000..d265cc9
--- /dev/null
+++ b/shdr/Engine/Vbo.cs
@@ -0,0 +1,50 @@
+using OpenTK.Graphics.OpenGL4;
+
+namespace shdr.Engine
+{
+ public class __vbo
+ {
+ private static int _active;
+ private readonly byte[] _bitDest = new byte[4];
+ private readonly int _handle;
+ private readonly MemoryStream _vertices;
+
+ public __vbo(int initialCapacity)
+ {
+ _handle = GL.GenBuffer();
+ _vertices = new MemoryStream(initialCapacity);
+ }
+
+ public void bind()
+ {
+ if (_handle == _active) return;
+ GL.BindBuffer(BufferTarget.ArrayBuffer, _handle);
+ _active = _handle;
+ }
+
+ public static void unbind()
+ {
+ GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
+ _active = 0;
+ }
+
+ public void put(float element)
+ {
+ BitConverter.TryWriteBytes(_bitDest, element);
+ _vertices.Write(_bitDest);
+ }
+
+ public void upload(bool unbindAfter = true)
+ {
+ if (_active != _handle) bind();
+ GL.BufferData(BufferTarget.ArrayBuffer, (int)_vertices.Length, _vertices.GetBuffer(),
+ BufferUsageHint.DynamicDraw);
+ if (unbindAfter) unbind();
+ }
+
+ public void clear()
+ {
+ _vertices.SetLength(0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Engine/VertexData.cs b/shdr/Engine/VertexData.cs
new file mode 100644
index 0000000..f8697ef
--- /dev/null
+++ b/shdr/Engine/VertexData.cs
@@ -0,0 +1,18 @@
+using OpenTK.Mathematics;
+
+namespace shdr.Engine
+{
+ public class __vertex_data
+ {
+ public uint color = 0xffffffff;
+ public Vector3 normal;
+ public Vector3 pos;
+ public Vector2 uv;
+
+ public __vertex_data(Vector3 pos, Vector2 uv)
+ {
+ this.pos = pos;
+ this.uv = uv;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Program.cs b/shdr/Program.cs
new file mode 100644
index 0000000..695b529
--- /dev/null
+++ b/shdr/Program.cs
@@ -0,0 +1,27 @@
+using OpenTK.Mathematics;
+using OpenTK.Windowing.Common;
+using OpenTK.Windowing.Desktop;
+using OpenTK.Windowing.GraphicsLibraryFramework;
+
+namespace shdr
+{
+ public static class __program
+ {
+ // ReSharper disable once InconsistentNaming
+ [STAThread]
+ public static void Main(string[] args)
+ {
+ NativeWindowSettings nativeWindowSettings = new()
+ {
+ Size = new Vector2i(1152, 720),
+ Title = "shdr",
+ Flags = ContextFlags.ForwardCompatible
+ };
+
+ GLFW.Init();
+ GLFW.WindowHint(WindowHintBool.Resizable, false);
+ using __shdr window = new(GameWindowSettings.Default, nativeWindowSettings);
+ window.Run();
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Resource/Font/Dank Mono Italic.otf b/shdr/Resource/Font/Dank Mono Italic.otf
new file mode 100644
index 0000000..3b879b2
Binary files /dev/null and b/shdr/Resource/Font/Dank Mono Italic.otf differ
diff --git a/shdr/Resource/Font/JetBrainsMono-Regular.ttf b/shdr/Resource/Font/JetBrainsMono-Regular.ttf
new file mode 100644
index 0000000..8da8aa4
Binary files /dev/null and b/shdr/Resource/Font/JetBrainsMono-Regular.ttf differ
diff --git a/shdr/Resource/Font/monofur-regular.ttf b/shdr/Resource/Font/monofur-regular.ttf
new file mode 100644
index 0000000..9aebf80
Binary files /dev/null and b/shdr/Resource/Font/monofur-regular.ttf differ
diff --git a/shdr/Resource/Font/saxmono.ttf b/shdr/Resource/Font/saxmono.ttf
new file mode 100644
index 0000000..76c77d6
Binary files /dev/null and b/shdr/Resource/Font/saxmono.ttf differ
diff --git a/shdr/Resource/Shader/basic.frag b/shdr/Resource/Shader/basic.frag
new file mode 100644
index 0000000..5a21f21
--- /dev/null
+++ b/shdr/Resource/Shader/basic.frag
@@ -0,0 +1,9 @@
+#version 330 core
+
+in vec4 ourColor;
+
+out vec4 color;
+
+void main() {
+ color = ourColor;
+}
\ No newline at end of file
diff --git a/shdr/Resource/Shader/basic.vert b/shdr/Resource/Shader/basic.vert
new file mode 100644
index 0000000..f8180d1
--- /dev/null
+++ b/shdr/Resource/Shader/basic.vert
@@ -0,0 +1,13 @@
+#version 330 core
+
+layout (location = 0) in vec3 aPos;
+layout (location = 1) in vec4 aColor;
+
+out vec4 ourColor;
+
+uniform mat4 _proj;
+
+void main() {
+ gl_Position = vec4(aPos, 1.0) * _proj;
+ ourColor = aColor;
+}
\ No newline at end of file
diff --git a/shdr/Resource/Shader/font.frag b/shdr/Resource/Shader/font.frag
new file mode 100644
index 0000000..f4be206
--- /dev/null
+++ b/shdr/Resource/Shader/font.frag
@@ -0,0 +1,12 @@
+#version 330 core
+
+in vec4 ourColor;
+in vec2 ourTexCoord;
+
+out vec4 color;
+
+uniform sampler2D ourTexture;
+
+void main() {
+ color = vec4(vec3(1), texture(ourTexture, ourTexCoord)) * ourColor;
+}
\ No newline at end of file
diff --git a/shdr/Resource/Shader/font.vert b/shdr/Resource/Shader/font.vert
new file mode 100644
index 0000000..aad8085
--- /dev/null
+++ b/shdr/Resource/Shader/font.vert
@@ -0,0 +1,16 @@
+#version 330 core
+
+layout (location = 0) in vec3 aPos;
+layout (location = 1) in vec2 aTexCoord;
+layout (location = 2) in vec4 color;
+
+out vec4 ourColor;
+out vec2 ourTexCoord;
+
+uniform mat4 _proj;
+
+void main() {
+ gl_Position = vec4(aPos, 1.0) * _proj;
+ ourColor = color;
+ ourTexCoord = aTexCoord;
+}
\ No newline at end of file
diff --git a/shdr/Resource/Shader/user.frag b/shdr/Resource/Shader/user.frag
new file mode 100644
index 0000000..a46b983
--- /dev/null
+++ b/shdr/Resource/Shader/user.frag
@@ -0,0 +1,13 @@
+#version 410 core
+
+vec2 uv;
+out vec4 color;
+
+uniform vec2 _resolution;
+uniform float _time;
+uniform sampler2D _prevFrame;
+
+void main() {
+ uv = gl_FragCoord.xy / _resolution.xy;
+ color = vec4(uv.r, 0., uv.g, 1.);
+}
\ No newline at end of file
diff --git a/shdr/Resource/Shader/user.vert b/shdr/Resource/Shader/user.vert
new file mode 100644
index 0000000..36d3ffd
--- /dev/null
+++ b/shdr/Resource/Shader/user.vert
@@ -0,0 +1,7 @@
+#version 410 core
+
+layout (location = 0) in vec2 aPos;
+
+void main() {
+ gl_Position = vec4(aPos, 0.0, 1.0);
+}
\ No newline at end of file
diff --git a/shdr/Resource/Texture/glslfuncs.txt b/shdr/Resource/Texture/glslfuncs.txt
new file mode 100644
index 0000000..ee6dca7
--- /dev/null
+++ b/shdr/Resource/Texture/glslfuncs.txt
@@ -0,0 +1,196 @@
+all
+any
+asin
+asinh
+atan
+atanh
+atomicAdd
+atomicAnd
+atomicCompSwap
+atomicCounter
+atomicCounterDecrement
+atomicCounterIncrement
+atomicExchange
+atomicMax
+atomicMin
+atomicOr
+atomicXor
+abs
+acos
+acosh
+barrier
+bitCount
+bitfieldExtract
+bitfieldInsert
+bitfieldReverse
+ceil
+clamp
+cos
+cosh
+cross
+degrees
+determinant
+dFdx
+dFdxCoarse
+dFdxFine
+dFdy
+dFdyCoarse
+dFdyFine
+distance
+dot
+EmitStreamVertex
+EmitVertex
+EndPrimitive
+EndStreamPrimitive
+equal
+exp
+exp2
+faceforward
+findLSB
+findMSB
+floatBitsToInt
+floatBitsToUint
+floor
+fma
+fract
+frexp
+fwidth
+fwidthCoarse
+fwidthFine
+gl_ClipDistance
+gl_CullDistance
+gl_FragCoord
+gl_FragDepth
+gl_FrontFacing
+gl_GlobalInvocationID
+gl_HelperInvocation
+gl_InstanceID
+gl_InvocationID
+gl_Layer
+gl_LocalInvocationID
+gl_LocalInvocationIndex
+gl_NumSamples
+gl_NumWorkGroups
+gl_PatchVerticesIn
+gl_PointCoord
+gl_PointSize
+gl_Position
+gl_PrimitiveID
+gl_PrimitiveIDIn
+gl_SampleID
+gl_SampleMask
+gl_SampleMaskIn
+gl_SamplePosition
+gl_TessCoord
+gl_TessLevelInner
+gl_TessLevelOuter
+gl_VertexID
+gl_ViewportIndex
+gl_WorkGroupID
+gl_WorkGroupSize
+greaterThan
+greaterThanEqual
+groupMemoryBarrier
+imageAtomicAdd
+imageAtomicAnd
+imageAtomicCompSwap
+imageAtomicExchange
+imageAtomicMax
+imageAtomicMin
+imageAtomicOr
+imageAtomicXor
+imageLoad
+imageSamples
+imageSize
+imageStore
+imulExtended
+intBitsToFloat
+interpolateAtCentroid
+interpolateAtOffset
+interpolateAtSample
+inverse
+inversesqrt
+isinf
+isnan
+ldexp
+length
+lessThan
+lessThanEqual
+log
+log2
+matrixCompMult
+max
+memoryBarrier
+memoryBarrierAtomicCounter
+memoryBarrierBuffer
+memoryBarrierImage
+memoryBarrierShared
+min
+mix
+mod
+modf
+noise
+noise1
+noise2
+noise3
+noise4
+normalize
+not
+notEqual
+outerProduct
+packDouble2x32
+packHalf2x16
+packSnorm2x16
+packSnorm4x8
+packUnorm
+packUnorm2x16
+packUnorm4x8
+pow
+radians
+reflect
+refract
+removedTypes
+round
+roundEven
+sign
+sin
+sinh
+smoothstep
+sqrt
+step
+tan
+tanh
+texelFetch
+texelFetchOffset
+texture
+textureGather
+textureGatherOffset
+textureGatherOffsets
+textureGrad
+textureGradOffset
+textureLod
+textureLodOffset
+textureOffset
+textureProj
+textureProjGrad
+textureProjGradOffset
+textureProjLod
+textureProjLodOffset
+textureProjOffset
+textureQueryLevels
+textureQueryLod
+textureSamples
+textureSize
+transpose
+trunc
+uaddCarry
+uintBitsToFloat
+umulExtended
+unpackDouble2x32
+unpackHalf2x16
+unpackSnorm2x16
+unpackSnorm4x8
+unpackUnorm
+unpackUnorm2x16
+unpackUnorm4x8
+usubBorrow
\ No newline at end of file
diff --git a/shdr/Shared/AABB.cs b/shdr/Shared/AABB.cs
new file mode 100644
index 0000000..67444bf
--- /dev/null
+++ b/shdr/Shared/AABB.cs
@@ -0,0 +1,22 @@
+namespace shdr.Shared
+{
+ public struct __aabb
+ {
+ public float minX;
+ public float minY;
+ public float minZ;
+ public float maxX;
+ public float maxY;
+ public float maxZ;
+
+ public __aabb(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
+ {
+ this.minX = minX;
+ this.minY = minY;
+ this.minZ = minZ;
+ this.maxX = maxX;
+ this.maxY = maxY;
+ this.maxZ = maxZ;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Shared/DiscordRpc.cs b/shdr/Shared/DiscordRpc.cs
new file mode 100644
index 0000000..bd80f34
--- /dev/null
+++ b/shdr/Shared/DiscordRpc.cs
@@ -0,0 +1,39 @@
+using NetDiscordRpc;
+using NetDiscordRpc.RPC;
+using OpenTK.Windowing.GraphicsLibraryFramework;
+
+namespace shdr.Shared
+{
+ public static class __discord_rpc
+ {
+ private static DiscordRPC _client;
+
+ public static void init()
+ {
+ _client = new DiscordRPC("1043932456606244896");
+ _client.Initialize();
+
+ new Thread(() =>
+ {
+ unsafe
+ {
+ while (!GLFW.WindowShouldClose(__shdr.instance.WindowPtr))
+ {
+ _client.SetPresence(new RichPresence
+ {
+ Assets = new Assets
+ {
+ LargeImageKey = "cover-image",
+ LargeImageText = "GLSLand"
+ },
+ Details = $"Editing {__shdr.path}",
+ State = $"Line {__shdr.dat.end.lin}"
+ });
+ Thread.Sleep(2000);
+ }
+ _client.Dispose();
+ }
+ }).Start();
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Shared/Extensions.cs b/shdr/Shared/Extensions.cs
new file mode 100644
index 0000000..2401554
--- /dev/null
+++ b/shdr/Shared/Extensions.cs
@@ -0,0 +1,160 @@
+using System.Text;
+using OpenTK.Mathematics;
+
+namespace shdr.Shared
+{
+ public static class __maps
+ {
+ public static Dictionary create(params KeyValuePair[] pairs)
+ {
+ return pairs.ToDictionary(pair => pair.Key, pair => pair.Value);
+ }
+ }
+
+ public static class __extensions
+ {
+ public static string content_to_string(this t[] arr)
+ {
+ string o = arr.ToString() ?? string.Empty;
+ o = o[..^1];
+ foreach (t item in arr) o += item + ", ";
+ o = o[..^2];
+ o += "]";
+ return o;
+ }
+
+ public static string repeat(this string str, int times)
+ {
+ return new StringBuilder(str.Length * times).Insert(0, str, times).ToString();
+ }
+
+ public static string content_to_string(this Dictionary arr)
+ {
+ StringBuilder o = new("Map<");
+ o.Append(typeof(t));
+ o.Append(", ");
+ o.Append(typeof(tv));
+ o.Append(">(");
+ foreach (KeyValuePair item in arr)
+ {
+ o.Append('(');
+ o.Append(item.Key);
+ o.Append(", ");
+ o.Append(item.Value);
+ o.Append("), ");
+ }
+
+ if (arr.Count > 0) o.Remove(o.Length - 3, 3);
+ o.Append(')');
+ return o.ToString();
+ }
+
+ public static void transform(this ref Vector4 vec, Matrix4 m4F)
+ {
+ float f = vec.X;
+ float g = vec.Y;
+ float h = vec.Z;
+ float i = vec.W;
+ vec.X = MathF.FusedMultiplyAdd(m4F.M11, f,
+ MathF.FusedMultiplyAdd(m4F.M21, g, MathF.FusedMultiplyAdd(m4F.M31, h, m4F.M41 + i)));
+ vec.Y = MathF.FusedMultiplyAdd(m4F.M12, f,
+ MathF.FusedMultiplyAdd(m4F.M22, g, MathF.FusedMultiplyAdd(m4F.M32, h, m4F.M42 + i)));
+ vec.Z = MathF.FusedMultiplyAdd(m4F.M13, f,
+ MathF.FusedMultiplyAdd(m4F.M23, g, MathF.FusedMultiplyAdd(m4F.M33, h, m4F.M43 + i)));
+ vec.W = MathF.FusedMultiplyAdd(m4F.M14, f,
+ MathF.FusedMultiplyAdd(m4F.M24, g, MathF.FusedMultiplyAdd(m4F.M34, h, m4F.M44 + i)));
+ }
+
+ public static Vector2 normalized_fast(this ref Vector2 vec)
+ {
+ if (vec == Vector2.Zero) return vec;
+ float length = MathHelper.InverseSqrtFast((float)(vec.X * (double)vec.X + vec.Y * (double)vec.Y));
+ vec.X *= length;
+ vec.Y *= length;
+ return vec;
+ }
+
+ public static Vector3 normalized_fast(this ref Vector3 vec)
+ {
+ if (vec == Vector3.Zero) return vec;
+ float length =
+ MathHelper.InverseSqrtFast((float)(vec.X * (double)vec.X + vec.Y * (double)vec.Y + vec.Z * (double)vec.Z));
+ vec.X *= length;
+ vec.Y *= length;
+ vec.Z *= length;
+ return vec;
+ }
+
+ public static float to_radians(this float degrees)
+ {
+ return (float)(degrees * Math.PI / 180.0);
+ }
+
+ public static float to_degrees(this float radians)
+ {
+ return (float)(radians * 180 / Math.PI);
+ }
+
+ public static void scale(this ref Matrix4 matrix4, float scalar)
+ {
+ matrix4 *= Matrix4.CreateScale(scalar);
+ }
+
+ public static void scale(this ref Matrix4 matrix4, Vector3 scalar)
+ {
+ matrix4 *= Matrix4.CreateScale(scalar);
+ }
+
+ public static void scale(this ref Matrix4 matrix4, float x, float y, float z)
+ {
+ matrix4 *= Matrix4.CreateScale(x, y, z);
+ }
+
+ public static void translate(this ref Matrix4 matrix4, Vector3 translation)
+ {
+ matrix4 *= Matrix4.CreateTranslation(translation);
+ }
+
+ public static void translate(this ref Matrix4 matrix4, float x, float y, float z)
+ {
+ matrix4 *= Matrix4.CreateTranslation(x, y, z);
+ }
+
+ public static void rotate(this ref Matrix4 matrix4, float angle, Vector3 axis)
+ {
+ matrix4 *= Matrix4.CreateFromAxisAngle(axis, angle / 180f * MathF.PI);
+ }
+
+ public static void rotate(this ref Matrix4 matrix4, float angle, float x, float y, float z)
+ {
+ matrix4 *= Matrix4.CreateFromAxisAngle(new Vector3(x, y, z), angle / 180f * MathF.PI);
+ }
+
+ public static void set(this ref Matrix4 mat, Matrix4 other)
+ {
+ mat.M11 = other.M11;
+ mat.M12 = other.M12;
+ mat.M13 = other.M13;
+ mat.M14 = other.M14;
+ mat.M21 = other.M21;
+ mat.M22 = other.M22;
+ mat.M23 = other.M23;
+ mat.M24 = other.M24;
+ mat.M31 = other.M31;
+ mat.M32 = other.M32;
+ mat.M33 = other.M33;
+ mat.M34 = other.M34;
+ mat.M41 = other.M41;
+ mat.M42 = other.M42;
+ mat.M43 = other.M43;
+ mat.M44 = other.M44;
+ }
+
+ public static int distance_sq(this Vector2i vec, Vector2i other)
+ {
+ (int x, int y) = vec;
+ (int i, int i1) = other;
+ return (x - i) * (x - i) + (y - i1) * (y - i1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Shared/Formatting.cs b/shdr/Shared/Formatting.cs
new file mode 100644
index 0000000..a5b898a
--- /dev/null
+++ b/shdr/Shared/Formatting.cs
@@ -0,0 +1,71 @@
+namespace shdr.Shared
+{
+ public sealed class __fmt
+ {
+ public static readonly Dictionary values = new();
+
+ public static readonly __fmt black = new(0, '0');
+ public static readonly __fmt darkblue = new(0x0000aa, '1');
+ public static readonly __fmt darkgreen = new(0x00aa00, '2');
+ public static readonly __fmt darkcyan = new(0x00aaaa, '3');
+ public static readonly __fmt darkred = new(0xaa0000, '4');
+ public static readonly __fmt darkpurple = new(0xaa00aa, '5');
+ public static readonly __fmt gold = new(0xffaa00, '6');
+ public static readonly __fmt gray = new(0xaaaaaa, '7');
+ public static readonly __fmt darkgray = new(0x555555, '8');
+ public static readonly __fmt blue = new(0x5555ff, '9');
+ public static readonly __fmt green = new(0x55ff55, 'a');
+ public static readonly __fmt cyan = new(0x55ffff, 'b');
+ public static readonly __fmt red = new(0xff5555, 'c');
+ public static readonly __fmt purple = new(0xff55ff, 'd');
+ public static readonly __fmt yellow = new(0xffff55, 'e');
+ public static readonly __fmt white = new(0xffffff, 'f');
+ public static readonly __fmt reset = new(0, 'r');
+ public static readonly __fmt keyword = new(0xff7084, 'g');
+ public static readonly __fmt number = new(0xa0ffe0, 'h');
+ public static readonly __fmt normal = new (0xffffff, 'i');
+ public static readonly __fmt operator_ = new(0xabc8ff, 'j');
+ public static readonly __fmt function = new(0x66e5ff, 'k');
+
+ public static string key(string str)
+ {
+ return $"{__fmt.keyword}{str}{__fmt.normal}";
+ }
+
+ public static string num(string str)
+ {
+ return $"{__fmt.number}{str}{__fmt.normal}";
+ }
+
+ public static string norm(string str)
+ {
+ return $"{__fmt.normal}{str}{__fmt.normal}";
+ }
+
+ public static string op(string str)
+ {
+ return $"{__fmt.operator_}{str}{__fmt.normal}";
+ }
+
+ public static string func(string str)
+ {
+ return $"{__fmt.function}{str}{__fmt.normal}";
+ }
+
+ public override string ToString()
+ {
+ return "\u00a7" + _code;
+ }
+
+ private readonly char _code;
+
+ public readonly uint color;
+
+ private __fmt(uint color, char code)
+ {
+ this.color = color;
+ _code = code;
+ values[code] = this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Shared/TextBox.cs b/shdr/Shared/TextBox.cs
new file mode 100644
index 0000000..7e0c9fc
--- /dev/null
+++ b/shdr/Shared/TextBox.cs
@@ -0,0 +1,516 @@
+using System.Collections.Concurrent;
+using System.Numerics;
+using System.Text;
+using System.Text.RegularExpressions;
+using OpenTK.Graphics.OpenGL4;
+using OpenTK.Mathematics;
+using OpenTK.Windowing.GraphicsLibraryFramework;
+using shdr.Engine;
+
+namespace shdr.Shared
+{
+ public static class __text_box
+ {
+ public struct __pos
+ {
+ public int col;
+ public int lin;
+
+ public static bool operator ==(__pos one, __pos two)
+ {
+ return one.col == two.col && one.lin == two.lin;
+ }
+
+ public static bool operator !=(__pos one, __pos two)
+ {
+ return !(one == two);
+ }
+ }
+
+ public struct __data
+ {
+ public float lastUpdate = 0;
+ public __pos prevStart = default;
+ public __pos prevEnd = default;
+ public __pos start = new();
+ public __pos end = new();
+ public float scroll = 0f;
+ public List text = new();
+ public List display = new();
+
+ public __data()
+ {
+ }
+ }
+
+ public enum __dir
+ {
+ up,
+ down,
+ left,
+ right,
+ none
+ }
+
+ private static readonly Dictionary> _fmt;
+ private static readonly HashSet _fmtKeys;
+ private static readonly HashSet _delimiters;
+ private static readonly HashSet _operators;
+
+ static __text_box()
+ {
+ List keywords = new()
+ {
+ "^float$",
+ "^int$",
+ "^vec2$",
+ "^vec3$",
+ "^vec4$",
+ "^void$",
+ "^layout$",
+ "^in$",
+ "^out$",
+ "^inout$",
+ "^if$",
+ "^for$",
+ "^while$",
+ "^const$",
+ "^uniform$",
+ "^sampler2D$",
+ "^sampler1D$",
+ "^sampler3D$",
+ "^return$",
+ "^break$",
+ "^continue$",
+ "^#[a-zA-Z0-9_]+$",
+ };
+ _fmt = new Dictionary>
+ {
+ { "-?^\\d*e?\\.?\\d*", __fmt.num }
+ };
+ foreach (string str in keywords)
+ {
+ _fmt[str] = __fmt.key;
+ }
+
+ foreach (string str in File.ReadLines("Resource/Texture/glslfuncs.txt"))
+ {
+ _fmt[str] = __fmt.func;
+ }
+
+ _fmtKeys = new HashSet(_fmt.Keys);
+ _delimiters = new HashSet
+ {
+ "(", ")", "{", "}", "[", "]", ";", ",", ".", "+", "-", "*", "/", "%", "=", "!", "<", ">", "&", "|", "^",
+ "~", "?", ":", "\\", "\"", "'", "`", " ", "\n"
+ };
+ _operators = new HashSet
+ {
+ "(", ")", "{", "}", "[", "]", "+", "-", "*", "/", "%", "=", "!", "<", ">", "&", "|", "^", "~", "?", ":", "\\", "\"", "'", "`", ";"
+ };
+ }
+
+ public static void update(ref __data dat, bool firstRun = false)
+ {
+ if (dat.display.Count < dat.text.Count)
+ {
+ dat.display.AddRange(new string[dat.text.Count - dat.display.Count]);
+ }
+ if (dat.display.Count > dat.text.Count)
+ {
+ dat.display.RemoveRange(dat.text.Count, dat.display.Count - dat.text.Count);
+ }
+ for (int i = firstRun ? 0 : Math.Min(dat.start.lin, dat.end.lin);
+ i <=
+ (firstRun
+ ? dat.text.Count - 1
+ : Math.Max(dat.start.lin, dat.end.lin));
+ i++)
+ {
+ string str = dat.text[i];
+ StringBuilder full = new();
+ StringBuilder word = new();
+ foreach (char c in str)
+ {
+ if (_delimiters.Contains(c.ToString()))
+ {
+ string st = word.ToString();
+ string works = "";
+ foreach (string key in _fmtKeys)
+ {
+ Match mat = Regex.Match(st, key);
+ if (mat.Value == st)
+ {
+ works = key;
+ break;
+ }
+ }
+
+ full.Append(works != "" ? _fmt[works](st) : __fmt.norm(st));
+ full.Append(_operators.Contains(c.ToString()) ? __fmt.op(c.ToString()) : __fmt.norm(c.ToString()));
+ word.Clear();
+ continue;
+ }
+
+ word.Append(c);
+ }
+
+ {
+ string st = word.ToString();
+ string works = "";
+ foreach (string key in _fmtKeys)
+ {
+ Match mat = Regex.Match(st, key);
+ if (mat.Value == st)
+ {
+ works = key;
+ break;
+ }
+ }
+
+ full.Append(works != "" ? _fmt[works](st) : __fmt.norm(st));
+ word.Clear();
+ }
+
+ dat.display[i] = full.ToString();
+ }
+ }
+
+ private static float safe(int e)
+ {
+ return __font.get_width(" ") * e - (e - 1) * 0.4f;
+ }
+
+ public static void render(ref __data dat, float x, float y, float width, float height)
+ {
+ float d = MathF.Pow(MathHelper.Clamp((Environment.TickCount - dat.lastUpdate) / 100f, 0, 1), 2f);
+ float sline = __util.lerp(dat.prevStart.lin, dat.start.lin, d);
+ float scol = __util.lerp(safe(dat.prevStart.col),
+ __font.get_width(dat.text[dat.start.lin][..dat.start.col]), d);
+ float eline = __util.lerp(dat.prevEnd.lin, dat.end.lin, d);
+ float ecol = __util.lerp(safe(dat.prevEnd.col),
+ __font.get_width(dat.text[dat.end.lin][..dat.end.col]), d);
+ float lineHeight = __font.get_height() * 1.6f;
+
+ if (sline < -dat.scroll)
+ {
+ dat.scroll = -sline;
+ }
+ if (eline > -dat.scroll + (int)(height - 20) / lineHeight - 1.5f)
+ {
+ dat.scroll = -eline + (int)(height - 20) / lineHeight - 1.5f;
+ }
+
+ uint cyan = (uint)new Color4(0, 238, 255,
+ (byte)((Math.Abs(Math.Sin(GLFW.GetTime() % 1.0 * Math.PI)) + 1) * 127)).ToArgb();
+
+ uint hotPink = (uint)new Color4(0xFF, 0x00, 0x94,
+ (byte)((Math.Abs(Math.Sin(GLFW.GetTime() % 1.0 * Math.PI)) + 1) * 127)).ToArgb();
+ GL.Enable(EnableCap.ScissorTest);
+ GL.Scissor((int)Math.Floor(x), (int)Math.Floor(y), (int)Math.Ceiling(width), (int)Math.Ceiling(height));
+ float textOffset = dat.scroll * lineHeight + 15f;
+
+ __util.draw_rect(x, y, width, textOffset + lineHeight * eline, 0xcc202531);
+ __util.draw_rect(x, y + textOffset + lineHeight + lineHeight * eline, width,
+ height + lineHeight * dat.text.Count, 0xcc202531);
+ __util.draw_rect(x, y + textOffset + lineHeight * eline, width, lineHeight, 0xee202531);
+
+ __font.bind();
+ for (int i = 0; i < dat.display.Count; i++)
+ {
+ __font.draw((i + 1).ToString(), x + 20, y + i * lineHeight + textOffset + 2.5f, 0xffcccccc, true);
+ __font.draw(dat.display[i], x + 50, y + i * lineHeight + textOffset + 2.5f, 0xffffffff, true);
+ }
+
+ __font.render();
+
+ __util.draw_rect(x + 50 + scol + -1, y + textOffset + sline * lineHeight + 2, 2, lineHeight - 4, cyan);
+ __util.draw_rect(x + 50 + ecol - 1, y + textOffset + eline * lineHeight + 2, 2, lineHeight - 4, hotPink);
+
+ GL.Disable(EnableCap.ScissorTest);
+ }
+
+ private static void ensure_pos(ref __data dat, ref __pos pos, __dir dir)
+ {
+ pos.lin = MathHelper.Clamp(pos.lin, 0, dat.text.Count - 1);
+
+ if (pos.col > dat.text[pos.lin].Length)
+ {
+ if (pos.lin == dat.text.Count - 1)
+ {
+ pos.col = dat.text[pos.lin].Length;
+ }
+ else if (dir is __dir.down or __dir.up)
+ {
+ pos.col = dat.text[pos.lin].Length;
+ }
+ else
+ {
+ pos.lin++;
+ pos.col = 0;
+ }
+ }
+
+ if (pos.col < 0)
+ {
+ if (pos.lin == 0)
+ {
+ pos.col = 0;
+ }
+ else
+ {
+ pos.lin--;
+ pos.col = dat.text[pos.lin].Length;
+ }
+ }
+ }
+
+ private static void ensure_poses(ref __data dat, __dir dir)
+ {
+ if (dat.start.lin > dat.end.lin || (dat.start.lin == dat.end.lin && dat.start.col > dat.end.col))
+ {
+ (dat.start, dat.end) = (dat.end, dat.start);
+ }
+
+ ensure_pos(ref dat, ref dat.start, dir);
+ ensure_pos(ref dat, ref dat.end, dir);
+ }
+
+ private static int spaces(string str)
+ {
+ return str.Length - str.TrimStart().Length;
+ }
+
+ public static void wheel(ref __data dat, float scroll)
+ {
+ dat.scroll += Math.Sign(scroll);
+ }
+
+ public static void key(ref __data dat, Keys key, bool shiftDown, bool controlDown)
+ {
+ dat.lastUpdate = Environment.TickCount;
+ dat.prevEnd = dat.end;
+ dat.prevStart = dat.start;
+
+ bool typingHappened = false;
+ bool important = false;
+
+ void cursor(ref __data dat, Vector2i dir)
+ {
+ ref __pos one = ref dat.end;
+ if (dir.X < 0 || dir.Y < 0)
+ {
+ one = ref dat.start;
+ }
+
+ ref __pos two = ref dat.end;
+ if (dir.X > 0 || dir.Y > 0)
+ {
+ two = ref dat.start;
+ }
+
+ one.col += dir.X;
+ one.lin += dir.Y;
+ if (shiftDown) return;
+ two.col = one.col;
+ two.lin = one.lin;
+ }
+
+ __dir dir = __dir.none;
+
+ switch (key)
+ {
+ case Keys.S:
+ if (controlDown)
+ {
+ string str = string.Join("\n", dat.text);
+ File.WriteAllText(__shdr.path, str);
+ try
+ {
+ __render_system.user = new __shader("Resource/Shader/user.vert", __shdr.path);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ }
+
+ break;
+ case Keys.Down:
+ cursor(ref dat, (0, 1));
+ dir = __dir.down;
+ break;
+ case Keys.Up:
+ cursor(ref dat, (0, -1));
+ dir = __dir.up;
+ break;
+ case Keys.Left:
+ cursor(ref dat, (-1, 0));
+ dir = __dir.left;
+ break;
+ case Keys.Right:
+ cursor(ref dat, (1, 0));
+ dir = __dir.right;
+ break;
+ case Keys.Home:
+ if (controlDown)
+ {
+ dat.end.lin = 0;
+ dat.end.col = 0;
+ }
+ else
+ {
+ dat.end.col = spaces(dat.text[dat.end.lin]);
+ }
+
+ if (!shiftDown)
+ {
+ dat.start.col = dat.end.col;
+ dat.start.lin = dat.end.lin;
+ }
+
+ break;
+ case Keys.End:
+ if (controlDown)
+ {
+ dat.end.lin = dat.text.Count - 1;
+ }
+
+ dat.end.col = dat.text[dat.end.lin].Length;
+ if (!shiftDown)
+ {
+ dat.start.col = dat.end.col;
+ dat.start.lin = dat.end.lin;
+ }
+
+ break;
+ case Keys.Enter:
+ {
+ important = true;
+ typingHappened = true;
+ string text = dat.text[dat.start.lin];
+ int s = spaces(dat.text[dat.start.lin]);
+ if (dat.start == dat.end)
+ {
+ dat.text[dat.start.lin] = text[..dat.start.col];
+ dat.text.Insert(dat.end.lin + 1, " ".repeat(s) + text[dat.start.col..]);
+ }
+
+ dat.start.lin++;
+ dat.start.col = s;
+ dat.end.col = s;
+ dat.end.lin = dat.start.lin;
+ break;
+ }
+ case Keys.Backspace:
+ typingHappened = true;
+ string text1 = dat.text[dat.start.lin];
+ if (dat.start == dat.end)
+ {
+ if (dat.start.col > 0)
+ {
+ dat.text[dat.start.lin] = text1[..(dat.start.col - 1)] + text1[dat.start.col..];
+ dat.start.col--;
+ dat.end.col--;
+ }
+ else if (dat.start.lin > 0)
+ {
+ important = true;
+ dat.start.lin--;
+ dat.end.lin--;
+ dat.start.col = dat.end.col = dat.text[dat.start.lin].Length;
+ dat.text[dat.start.lin] += text1;
+ dat.text.RemoveAt(dat.start.lin + 1);
+ }
+ }
+ else
+ {
+ if (dat.end.lin != dat.start.lin)
+ {
+ important = true;
+ dat.text[dat.start.lin] = text1[..dat.start.col] + dat.text[dat.end.lin][dat.end.col..];
+ dat.text[dat.end.lin] = dat.text[dat.end.lin][dat.end.col..];
+ for (int i = dat.start.lin + 1; i <= dat.end.lin; i++)
+ {
+ dat.text.RemoveAt(dat.start.lin + 1);
+ }
+ }
+ else
+ {
+ dat.text[dat.start.lin] = text1[..dat.start.col] + text1[dat.end.col..];
+ }
+
+ dat.end = dat.start;
+ }
+
+ break;
+ case Keys.Delete:
+ typingHappened = true;
+ dat.end.col++;
+ dat.start.col++;
+ ensure_pos(ref dat, ref dat.end, __dir.right);
+ ensure_pos(ref dat, ref dat.start, __dir.right);
+ __text_box.key(ref dat, Keys.Backspace, shiftDown, controlDown);
+ break;
+ case Keys.Tab:
+ typingHappened = true;
+ if (dat.start == dat.end)
+ {
+ string text2 = dat.text[dat.start.lin];
+ if (shiftDown)
+ {
+ int ec = dat.end.col;
+ int el = dat.end.lin;
+ if (ec >= 2)
+ {
+ dat.end.col -= 2;
+ dat.start.col -= 2;
+ if (dat.text[el][ec - 1] == dat.text[el][ec - 2] && dat.text[el][ec - 1] == ' ')
+ {
+ // remove chars @ ec - 1 and ec -2
+ dat.text[el] = text2[..(ec - 2)] + text2[ec..];
+ }
+ }
+ }
+ else
+ {
+ type(ref dat, " ");
+ }
+ }
+
+ break;
+ }
+
+ if (typingHappened)
+ update(ref dat, important);
+
+ ensure_poses(ref dat, dir);
+ }
+
+ public static void type(ref __data dat, string str)
+ {
+ dat.lastUpdate = Environment.TickCount;
+ dat.prevEnd = dat.end;
+ dat.prevStart = dat.start;
+
+ if (dat.start == dat.end)
+ {
+ dat.text[dat.start.lin] = dat.text[dat.start.lin][..dat.start.col] + str +
+ dat.text[dat.start.lin][dat.start.col..];
+ dat.start.col += str.Length;
+ dat.end.col = dat.start.col;
+ }
+ else
+ {
+ string text = dat.text[dat.start.lin];
+ dat.text[dat.start.lin] = text[..dat.start.col] + str + text[dat.end.col..];
+ dat.start.col += str.Length;
+ dat.end.col = dat.start.col;
+ }
+
+ update(ref dat);
+
+ ensure_poses(ref dat, __dir.none);
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/Shared/Util.cs b/shdr/Shared/Util.cs
new file mode 100644
index 0000000..03c1606
--- /dev/null
+++ b/shdr/Shared/Util.cs
@@ -0,0 +1,31 @@
+using shdr.Engine;
+
+namespace shdr.Shared
+{
+ public static class __util
+ {
+ public static readonly float sqrt2 = MathF.Sqrt(2);
+
+ public static float lerp(float start, float end, float delta)
+ {
+ return start + (end - start) * delta;
+ }
+
+ public static void clamp(ref int val, int start, int end)
+ {
+ val = Math.Min(Math.Max(val, start), end);
+ }
+
+ public static void draw_rect(float x, float y, float width, float height, uint color)
+ {
+ __render_system.basic.begin();
+ __render_system.basic.quad(
+ __render_system.basic.float3(x, y, 0).float4(color).next(),
+ __render_system.basic.float3(x + width, y, 0).float4(color).next(),
+ __render_system.basic.float3(x + width, y + height, 0).float4(color).next(),
+ __render_system.basic.float3(x, y + height, 0).float4(color).next()
+ );
+ __render_system.basic.render();
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/code-edit.svg b/shdr/code-edit.svg
new file mode 100644
index 0000000..7bdf511
--- /dev/null
+++ b/shdr/code-edit.svg
@@ -0,0 +1,17 @@
+
\ No newline at end of file
diff --git a/shdr/shdr.cs b/shdr/shdr.cs
new file mode 100644
index 0000000..64abe20
--- /dev/null
+++ b/shdr/shdr.cs
@@ -0,0 +1,147 @@
+using System.Drawing;
+using OpenTK.Graphics.OpenGL4;
+using OpenTK.Mathematics;
+using OpenTK.Windowing.Common;
+using OpenTK.Windowing.Desktop;
+using OpenTK.Windowing.GraphicsLibraryFramework;
+using shdr.Engine;
+using shdr.Shared;
+
+namespace shdr
+{
+ public class __shdr : GameWindow
+ {
+ private static int _ticks;
+ public static __shdr instance;
+ public static __text_box.__data dat;
+ public static string path;
+ public static __mesh uMesh;
+
+ public __shdr(GameWindowSettings windowSettings, NativeWindowSettings nativeWindowSettings) : base(
+ windowSettings, nativeWindowSettings)
+ {
+ instance = this;
+ {
+ path = Console.ReadLine();
+ if (path.Trim().Length == 0)
+ {
+ int i = 0;
+ while (File.Exists($"shader{i}.frag"))
+ {
+ i++;
+ }
+
+ path = $"shader{i}.frag";
+ }
+ }
+ List defaultText = File.ReadLines("Resource/Shader/user.frag").ToList();
+ dat = new __text_box.__data
+ {
+ text = File.Exists(path) ? File.ReadAllLines(path).ToList() : defaultText
+ };
+ __text_box.update(ref dat, true);
+ string str = string.Join("\n", dat.text);
+ File.WriteAllText(path, str);
+
+ try
+ {
+ __render_system.user = new __shader("Resource/Shader/user.vert", path);
+ }
+ catch (Exception e)
+ {
+ __render_system.user = new __shader("Resource/Shader/user.vert", "shader1.frag");
+ Console.WriteLine(e.Message);
+ }
+ uMesh = new __mesh(__mesh.__draw_mode.triangle, null, __vao.__attrib.float2);
+ uMesh.begin();
+ uMesh.quad(
+ uMesh.float2(-1, -1).next(),
+ uMesh.float2(1, -1).next(),
+ uMesh.float2(1, 1).next(),
+ uMesh.float2(-1, 1).next()
+ );
+ uMesh.end();
+ __discord_rpc.init();
+ }
+
+ protected override void OnLoad()
+ {
+ base.OnLoad();
+
+ GL.ClearColor(0f, 0f, 0f, 0f);
+ GL.DepthFunc(DepthFunction.Lequal);
+ __gl_state_manager.enable_blend();
+ }
+
+ protected override void OnResize(ResizeEventArgs e)
+ {
+ base.OnResize(e);
+
+ if (e.Size == Vector2i.Zero)
+ return;
+
+ GL.ClearColor(0f, 0f, 0f, 0f);
+ __render_system.update_projection();
+ GL.Viewport(new Rectangle(0, 0, Size.X, Size.Y));
+ __fbo.resize(Size.X, Size.Y);
+ }
+
+ protected override void OnMouseWheel(MouseWheelEventArgs e)
+ {
+ base.OnMouseWheel(e);
+
+ __text_box.wheel(ref dat, e.OffsetY);
+ }
+
+ protected override void OnTextInput(TextInputEventArgs e)
+ {
+ base.OnTextInput(e);
+
+ __text_box.type(ref dat, e.AsString);
+ }
+
+ private bool _renderTextBox = true;
+
+ protected override void OnKeyDown(KeyboardKeyEventArgs e)
+ {
+ base.OnKeyDown(e);
+
+ if (e.Key == Keys.F1)
+ {
+ _renderTextBox = !_renderTextBox;
+ }
+ else if (e.Key == Keys.F2)
+ {
+ __font.index++;
+ }
+
+ __text_box.key(ref dat, e.Key, KeyboardState.IsKeyDown(Keys.LeftShift), KeyboardState.IsKeyDown(Keys.LeftControl));
+ }
+
+ protected override void OnRenderFrame(FrameEventArgs args)
+ {
+ base.OnRenderFrame(args);
+
+ __render_system.frame.bind();
+ GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+
+ __render_system.user.bind();
+ __render_system.prevFrame.bind_color(TextureUnit.Texture15);
+ __render_system.user.set_int("_prevFrame", 15);
+ __render_system.user.set_vector2("_resolution", Size.ToVector2());
+ __render_system.user.set_float("_time", (float)GLFW.GetTime());
+ uMesh.render();
+
+ __render_system.frame.blit(__render_system.prevFrame.handle);
+
+ __render_system.frame.bind();
+
+ if (_renderTextBox)
+ __text_box.render(ref dat, 10, 10, Size.X - 20, Size.Y - 20);
+
+ __render_system.frame.blit();
+
+ SwapBuffers();
+ }
+ }
+}
\ No newline at end of file
diff --git a/shdr/shdr.csproj b/shdr/shdr.csproj
new file mode 100644
index 0000000..53e6c59
--- /dev/null
+++ b/shdr/shdr.csproj
@@ -0,0 +1,27 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ disable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+