diff --git a/JAngine/Rendering/2D.cs b/JAngine/Rendering/2D.cs index b73a0ba..88ee893 100644 --- a/JAngine/Rendering/2D.cs +++ b/JAngine/Rendering/2D.cs @@ -20,6 +20,7 @@ public Vertex2D(Vector2 position, Vector2 texCoord) public Vertex2D(float x, float y) { Position = new Vector2(x, y); + TexCoord = Position; } } diff --git a/JAngine/Rendering/Mesh.cs b/JAngine/Rendering/Mesh.cs index 58089a1..b460229 100644 --- a/JAngine/Rendering/Mesh.cs +++ b/JAngine/Rendering/Mesh.cs @@ -16,6 +16,7 @@ public ShaderAttributeAttribute(string nameInShader) public sealed class Mesh: IDisposable { + private readonly List _textures; private readonly List _vaos; private readonly Dictionary _vertexBuffers; private readonly Dictionary _instanceBuffers; @@ -25,6 +26,7 @@ public Mesh(Window window, string name) { Window = window; Name = name; + _textures = new List(); _vaos = new List(); _ebo = new Buffer(window, $"{name}.buffer"); _vertexBuffers = new Dictionary(TypeComparer.Default); @@ -205,12 +207,27 @@ public IEnumerable> GetInstances(int start = 0, int co yield return new BufferDataReference(buf, i); } } + + public void AddTexture(Texture texture) + { + _textures.Add(texture); + + foreach (VertexArray vao in _vaos) + { + vao.AddTexture(texture); + } + } public void BindToShader(Shader shader) { VertexArray vao = new VertexArray(Window, Name + ".vao", shader, _ebo); _vaos.Add(vao); + foreach (Texture texture in _textures) + { + vao.AddTexture(texture); + } + foreach (IBuffer buffer in _vertexBuffers.Values) { AddAttributes(vao, buffer, 0); diff --git a/JAngine/Rendering/OpenGL/GL.cs b/JAngine/Rendering/OpenGL/GL.cs index c972e34..2d29615 100644 --- a/JAngine/Rendering/OpenGL/GL.cs +++ b/JAngine/Rendering/OpenGL/GL.cs @@ -1,3 +1,4 @@ +using System.Buffers; using System.Runtime.InteropServices; namespace JAngine.Rendering.OpenGL; @@ -311,12 +312,17 @@ internal enum VertexAttribType : Enum internal enum TextureTarget : Enum { + Texture1D = 0x0DE0, Texture2D = 0x0DE1, + Texture3D = 0x806F, ProxyTexture2D = 0x8064, Texture1DArray = 0x8C18, + Texture2DArray = 0x8C1A, ProxyTexture1DArray = 0x8C19, TextureRectangle = 0x84F5, ProxyTextureRectangle = 0x84F7, + TextureCubeMap = 0x8513, + TextureCubeMapArray = 0x9009, TextureCubeMapPositiveX = 0x8515, TextureCubeMapNegativeX = 0x8516, TextureCubeMapPositiveY = 0x8517, @@ -326,6 +332,71 @@ internal enum TextureTarget : Enum ProxyTextureCubeMap = 0x851B, } + internal enum SizedInternalFormat : Enum + { + R8 = 0x8229, + R8Snorm = 0x8F94, + R16 = 0x822A, + R16Snorm = 0x8F98, + Rg8 = 0x822B, + Rg8Snorm = 0x8F95, + Rg16 = 0x822C, + Rg16Snorm = 0x8F99, + R3G3B2 = 0x2A10, + Rgb4 = 0x804F, + Rgb5 = 0x8050, + Rgb8 = 0x8051, + Rgb8Snorm = 0x8F96, + Rgb10 = 0x8052, + Rgb12 = 0x8053, + Rgb16Snorm = 0x8F9A, + Rgba2 = 0x8055, + Rgba4 = 0x8056, + Rgb5A1 = 0x8057, + Rgba8 = 0x8058, + Rgba8Snorm = 0x8F97, + Rgb10A2 = 0x8059, + Rgb10A2Ui = 0x906F, + Rgba12 = 0x805A, + Rgba16 = 0x805B, + Srgb8 = 0x8C41, + Srgb8Alpha8 = 0x8C43, + R16F = 0x822D, + Rg16F = 0x822F, + Rgb16F = 0x881B, + Rgba16F = 0x881A, + R32F = 0x822E, + Rg32F = 0x8230, + Rgb32F = 0x8815, + Rgba32F = 0x8814, + R11FG11FB10F = 0x8C3A, + Rgb9E5 = 0x8C3D, + R8I = 0x8231, + R8Ui = 0x8232, + R16I = 0x8233, + R16Ui = 0x8234, + R32I = 0x8235, + R32Ui = 0x8236, + Rg8I = 0x8237, + Rg8Ui = 0x8238, + Rg16I = 0x8239, + Rg16Ui = 0x823A, + Rg32I = 0x823B, + Rg32Ui = 0x823C, + Rgb8I = 0x8D8F, + Rgb8Ui = 0x8D7D, + Rgb16I = 0x8D89, + Rgb16Ui = 0x8D77, + Rgb32I = 0x8D83, + Rgb32Ui = 0x8D71, + Rgba8I = 0x8D8E, + Rgba8Ui = 0x8D7C, + Rgba16I = 0x8D88, + Rgba16Ui = 0x8D76, + Rgba32I = 0x8D82, + Rgba32Ui = 0x8D70, + } + internal enum PixelFormat : Enum { Red = 0x1903, @@ -334,24 +405,29 @@ internal enum PixelFormat : Enum Bgr = 0x80E0, Rgba = 0x1908, Bgra = 0x80E1, - RedInteger = 0x8D94, - RgInteger = 0x8228, - RgbInteger = 0x8D98, - BgrInteger = 0x8D9A, - RgbaInteger = 0x8D99, - BgraInteger = 0x8D9B, - StencilIndex = 0x1901, DepthComponent = 0x1902, - DepthStencil = 0x821A, + StencilIndex = 0x1901, } - + internal enum PixelType : Enum { - GL_UNSIGNED_BYTE0x1401, - GL_BYTE0x1400, - GL_UNSIGNED_SHORT0x1403, - GL_SHORT0x1402 - // TODO: Not done yet. + UnsignedByte = 0x1401, + Byte = 0x1400, + UnsignedShort = 0x1403, + Short = 0x1402, + UnsignedInt = 0x1405, + Int = 0x1404, + HalfFloat = 0x140B, + Float = 0x1406, + UnsignedByte332 = 0x8032, + UnsignedByte233Rev = 0x8362, + UnsignedShort4444Rev = 0x8365, + UnsignedShort5551 = 0x8034, + UnsignedShort1555Rev = 0x8366, + UnsignedInt8888 = 0x8367, + UnsignedInt8888Rev = 0x8367, + UnsignedInt1010102 = 0x8036, + UnsignedInt2101010Rev = 0x8368, } private static readonly delegate* unmanaged ViewportPtr = @@ -393,6 +469,8 @@ internal enum PixelType : Enum (delegate* unmanaged)Glfw.GetProcAddress("glGetActiveUniform"); private static readonly delegate* unmanaged GetUniformLocationPtr = (delegate* unmanaged)Glfw.GetProcAddress("glGetUniformLocation"); + private static readonly delegate* unmanaged Uniform1iPtr = + (delegate* unmanaged)Glfw.GetProcAddress("glUniform1i"); private static readonly delegate* unmanaged CreateShaderPtr = (delegate* unmanaged)Glfw.GetProcAddress("glCreateShader"); @@ -443,13 +521,19 @@ internal enum PixelType : Enum private static readonly delegate* unmanaged VertexArrayAttribLFormatPtr = (delegate* unmanaged)Glfw.GetProcAddress("glVertexArrayAttribLFormat"); - private static readonly delegate* unmanaged GenTexturesPtr = - (delegate* unmanaged)Glfw.GetProcAddress("glGenTextures"); + private static readonly delegate* unmanaged CreateTexturesPtr = + (delegate* unmanaged)Glfw.GetProcAddress("glCreateTextures"); private static readonly delegate* unmanaged DeleteTexturesPtr = (delegate* unmanaged)Glfw.GetProcAddress("glDeleteTextures"); - private static readonly delegate* unmanaged TexImage2D = - (delegate* unmanaged)Glfw.GetProcAddress("glTexImage2D"); - + private static readonly delegate* unmanaged TextureStorage2DPtr = + (delegate* unmanaged)Glfw.GetProcAddress("glTextureStorage2D"); + private static readonly delegate* unmanaged TextureSubImage2DPtr = + (delegate* unmanaged)Glfw.GetProcAddress("glTextureSubImage2D"); + private static readonly delegate* unmanaged GenerateTextureMipmapPtr = + (delegate* unmanaged)Glfw.GetProcAddress("glGenerateTextureMipmap"); + private static readonly delegate* unmanaged BindTextureUnitPtr = + (delegate* unmanaged)Glfw.GetProcAddress("glBindTextureUnit"); + internal static void Viewport(int x, int y, int width, int height) { @@ -555,6 +639,11 @@ internal static int GetUniformLocation(uint program, byte* namePtr) return GetUniformLocationPtr(program, namePtr); } + internal static void Uniform1i(int location, int v0) + { + Uniform1iPtr(location, v0); + } + internal static uint CreateShader(ShaderType shaderType) { return CreateShaderPtr(shaderType); @@ -715,10 +804,10 @@ internal static void VertexArrayAttribLFormat(uint vao, uint attribIndex, int si VertexArrayAttribLFormatPtr(vao, attribIndex, size, type, relativeOffset); } - internal static uint GenTexture() + internal static uint CreateTexture(TextureTarget target) { uint texture = 0; - GenTexturesPtr(1, &texture); + CreateTexturesPtr(target, 1, &texture); return texture; } @@ -726,4 +815,29 @@ internal static void DeleteTexture(uint texture) { DeleteVertexArraysPtr(1, &texture); } + + internal static void TextureStorage2D(uint texture, int levels, SizedInternalFormat internalformat, int width, + int height) + { + TextureStorage2DPtr(texture, levels, internalformat, width, height); + } + + internal static void TextureSubImage2D(uint texture, int level, int xoffset, int yoffset, int width, int height, PixelFormat format, PixelType type, ref T pixels) + where T : unmanaged + { + fixed (void* pixelPtr = &pixels) + { + TextureSubImage2DPtr(texture, level, xoffset, yoffset, width, height, format, type, pixelPtr); + } + } + + internal static void GenerateTextureMipmap(uint texture) + { + GenerateTextureMipmapPtr(texture); + } + + internal static void BindTextureUnit(uint unit, uint texture) + { + BindTextureUnitPtr(unit, texture); + } } diff --git a/JAngine/Rendering/OpenGL/Shader.cs b/JAngine/Rendering/OpenGL/Shader.cs index 8230b5c..5f7040c 100644 --- a/JAngine/Rendering/OpenGL/Shader.cs +++ b/JAngine/Rendering/OpenGL/Shader.cs @@ -3,6 +3,18 @@ namespace JAngine.Rendering.OpenGL; +internal sealed class UniformUpdate : IGlEvent +{ + internal int Location { get; } + internal object Value { get; } + + internal UniformUpdate(int location, object value) + { + Location = location; + Value = value; + } +} + public abstract class ShaderStage : IGlObject, IDisposable { private readonly Gl.ShaderType _type; @@ -213,6 +225,15 @@ void IGlObject.DispatchEvent(IGlEvent glEvent) Marshal.FreeCoTaskMem(namePtr); } break; + case UniformUpdate uniform: + // TODO: Allow more types. + switch (uniform.Value) + { + case int value: + Gl.Uniform1i(uniform.Location, value); + break; + } + break; case DisposeEvent: Gl.DeleteProgram(Handle); Handle = 0; @@ -220,6 +241,11 @@ void IGlObject.DispatchEvent(IGlEvent glEvent) } } + public void SetUniform(string name, int value) + { + Window.QueueUpdate(this, new UniformUpdate(_uniforms[name].Location, value)); + } + internal bool TryGetAttribute(string name, [NotNullWhen(true)] out Attribute? attribute) { return _attributes.TryGetValue(name, out attribute); diff --git a/JAngine/Rendering/OpenGL/Texture.cs b/JAngine/Rendering/OpenGL/Texture.cs new file mode 100644 index 0000000..0c63b7a --- /dev/null +++ b/JAngine/Rendering/OpenGL/Texture.cs @@ -0,0 +1,48 @@ +using System.Numerics; + +namespace JAngine.Rendering.OpenGL; + +public sealed class Texture : IGlObject +{ + private uint _handle; + private readonly Window _window; + private readonly Vector4[,] _pixels; + + public Texture(Window window, string name, Vector4[,] pixels) + { + _window = window; + Name = name; + Width = pixels.GetLength(0); + Height = pixels.GetLength(1); + + window.QueueUpdate(this, CreateEvent.Singleton); + window.QueueUpdate(this, UpdateDataEvent.Default); + _pixels = pixels; + } + + public int Width { get; } + public int Height { get; } + + uint IGlObject.Handle => _handle; + public string Name { get; } + Window IGlObject.Window => _window; + void IGlObject.DispatchEvent(IGlEvent glEvent) + { + switch (glEvent) + { + case CreateEvent: + _handle = Gl.CreateTexture(Gl.TextureTarget.Texture2D); + Gl.TextureStorage2D(_handle, 1, Gl.SizedInternalFormat.Rgba32F, Width, Height); + break; + case UpdateDataEvent: + Gl.TextureSubImage2D(_handle, 0, 0, 0, Width, Height, Gl.PixelFormat.Rgba, Gl.PixelType.Float, ref _pixels[0, 0]); + Gl.GenerateTextureMipmap(_handle); + break; + } + } + + internal void Bind(uint unit) + { + Gl.BindTextureUnit(unit, _handle); + } +} diff --git a/JAngine/Rendering/OpenGL/VertexArray.cs b/JAngine/Rendering/OpenGL/VertexArray.cs index 8a0028e..63769cf 100644 --- a/JAngine/Rendering/OpenGL/VertexArray.cs +++ b/JAngine/Rendering/OpenGL/VertexArray.cs @@ -6,6 +6,7 @@ public sealed class VertexArray : IGlObject, IDisposable private uint _handle; private readonly IBuffer _ebo; private readonly Dictionary _attributeBuffers = new(); + private readonly Texture?[] _textures = new Texture[32]; public VertexArray(Window window, string name, Shader shader, IBuffer ebo) { @@ -24,6 +25,11 @@ public VertexArray(Window window, string name, Shader shader, IBuffer ebo) internal int PointCount => _ebo.Count; public int InstanceCount { get; set; } = 1; + public void AddTexture(Texture texture) + { + _textures[0] = texture; //TODO + } + public BufferBinding BindBuffer(IBuffer buffer, int offset = 0) { lock (_attributeBuffers) @@ -90,6 +96,16 @@ void IGlObject.DispatchEvent(IGlEvent glEvent) internal void Bind() { Gl.BindVertexArray(_handle); + Shader.Bind(); + for (int i = 0; i < _textures.Length; i++) + { + Texture? texture = _textures[i]; + if (texture is not null) + { + Shader.SetUniform($"uTextures[{i}]", i); + texture.Bind((uint)i); + } + } } public void Dispose() diff --git a/JAngine/Rendering/Window.cs b/JAngine/Rendering/Window.cs index 0f9ded1..6ce287c 100644 --- a/JAngine/Rendering/Window.cs +++ b/JAngine/Rendering/Window.cs @@ -276,7 +276,6 @@ private void RenderThread() foreach (VertexArray vao in _vaos) { vao.Bind(); - vao.Shader.Bind(); Gl.DrawElementsInstanced(Gl.PrimitiveType.Triangles, vao.PointCount, Gl.DrawElementsType.UnsignedInt, 0, vao.InstanceCount); } diff --git a/JAngine/Shaders/2D.frag b/JAngine/Shaders/2D.frag index 9799409..b283819 100644 --- a/JAngine/Shaders/2D.frag +++ b/JAngine/Shaders/2D.frag @@ -2,8 +2,10 @@ in vec2 fTexCoord; in vec4 fColor; +uniform sampler2D[32] uTextures; + out vec4 Color; void main() { - Color = vec4(1) * fColor; + Color = vec4(1) * fColor * texture(uTextures[0], fTexCoord); } \ No newline at end of file diff --git a/Sandbox/Program.cs b/Sandbox/Program.cs index 1f564b2..0184e73 100644 --- a/Sandbox/Program.cs +++ b/Sandbox/Program.cs @@ -1,6 +1,7 @@ using System.Numerics; using JAngine.Rendering; using JAngine.Rendering.Gui; +using JAngine.Rendering.OpenGL; try {