/// <summary> /// Create the texture, using this technique. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for allocating resources. /// </param> public override void Create(GraphicsContext ctx) { // Define storage InternalFormat internalFormat = _PixelFormat.ToInternalFormat(); if (!IsImmutableSupported(ctx)) { PixelFormat format = _PixelFormat.ToDataFormat(); for (uint level = 0, w = _Width, h = _Height; level < _MipmapLevels; level++, w = Math.Max(1, w / 2), h = Math.Max(1, h / 2)) { Gl.TexImage2D(_Target, (int)level, internalFormat, (int)w, (int)h, 0, format, /* Unused */ PixelType.UnsignedByte, IntPtr.Zero); // Always check for errors Gl.CheckErrors(); } } else { Gl.TexStorage2D(_Target, (int)_MipmapLevels, internalFormat, (int)_Width, (int)_Height); // Always check for errors Gl.CheckErrors(); } // Define mipmap array for (uint level = 0, w = _Width, h = _Height; level < _MipmapLevels; level++, w = Math.Max(1, w / 2), h = Math.Max(1, h / 2)) { _Texture2d.SetMipmap(_PixelFormat, w, h, 1, level); } }
/// <summary> /// Update the reference Buffer, using this technique. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for allocating resources. /// </param> public override void Create(GraphicsContext ctx) { if (ctx.Extensions.DirectStateAccess_ARB || ctx.Version.IsCompatible(Gl.Version_450)) { if (!ctx.Extensions.BufferStorage_ARB || !Buffer.Immutable) { // Emulates glBufferStorage error checking (only for size) if (Buffer.Immutable && Buffer.Size != 0) { throw new GlException(ErrorCode.InvalidOperation); } Gl.NamedBufferData(Buffer.ObjectName, _Size, _Array, Buffer.Hint); } else { if (Buffer.Immutable) { Gl.NamedBufferStorage(Buffer.ObjectName, _Size, _Array, Buffer.UsageMask); } else { Gl.NamedBufferData(Buffer.ObjectName, _Size, _Array, Buffer.Hint); } } } else { if (!ctx.Extensions.BufferStorage_ARB || !Buffer.Immutable) { // Emulates glBufferStorage error checking (only for size) if (Buffer.Immutable && Buffer.Size != 0) { throw new GlException(ErrorCode.InvalidOperation); } Gl.BufferData(Buffer.Target, _Size, _Array, Buffer.Hint); } else { if (Buffer.Immutable) { Gl.BufferStorage(Buffer.Target, _Size, _Array, Buffer.UsageMask); } else { Gl.BufferData(Buffer.Target, _Size, _Array, Buffer.Hint); } } } // Explictly check for errors Gl.CheckErrors(); Buffer.Size = _Size; }
public static void Check() { try { Gl.CheckErrors(); } catch (Exception e) { StaticLogger.Logger.Error(e); } }
/// <summary> /// Update the reference Buffer, using this technique. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for allocating resources. /// </param> public override void Create(GraphicsContext ctx) { if (ctx.Extensions.DirectStateAccess_ARB || ctx.Version.IsCompatible(Gl.Version_450)) { CreateDSA(ctx); } else { CreateCompatible(ctx); } // Explictly check for errors Gl.CheckErrors(); Buffer.Size = _Size; }
/// <summary> /// Construct an UniformBlockBinding. /// </summary> /// <param name="program"> /// The <see cref="ShaderProgram"/> defining this uniform block. /// </param> /// <param name="uniformBlockIndex"> /// A <see cref="UInt32"/> that specifies the index used for identifying the uniform block. /// </param> public UniformBlockBinding(ShaderProgram program, uint uniformBlockIndex) { if (program == null) { throw new ArgumentNullException("program"); } int[] uniformBlockParams; // Index Index = uniformBlockIndex; // Name length int uniformBlockNameLength; uniformBlockParams = new int[1]; Gl.GetActiveUniformBlock(program.ObjectName, Index, Gl.UNIFORM_BLOCK_NAME_LENGTH, uniformBlockParams); uniformBlockNameLength = uniformBlockParams[0]; // Name StringBuilder uniformBlockNameBuffer = new StringBuilder(uniformBlockNameLength); int nameLength; Gl.GetActiveUniformBlockName(program.ObjectName, Index, uniformBlockNameBuffer.Capacity, out nameLength, uniformBlockNameBuffer); Gl.CheckErrors(); Name = uniformBlockNameBuffer.ToString(); // Data size uniformBlockParams = new int[1]; Gl.GetActiveUniformBlock(program.ObjectName, Index, Gl.UNIFORM_BLOCK_DATA_SIZE, uniformBlockParams); DataSize = (uint)uniformBlockParams[0]; // Active uniforms uniformBlockParams = new int[1]; Gl.GetActiveUniformBlock(program.ObjectName, Index, Gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS, uniformBlockParams); ActiveUniforms = (uint)uniformBlockParams[0]; // Uniform indices uniformBlockParams = new int[ActiveUniforms]; Gl.GetActiveUniformBlock(program.ObjectName, Index, Gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, uniformBlockParams); UniformIndices = uniformBlockParams; }
/// <summary> /// Construct an UniformBlockBinding. /// </summary> /// <param name="program"> /// The <see cref="ShaderProgram"/> defining this uniform block. /// </param> /// <param name="uniformBlockIndex"> /// A <see cref="UInt32"/> that specifies the index used for identifying the uniform block. /// </param> public UniformBlockBinding(ShaderProgram program, uint uniformBlockIndex) { if (program == null) { throw new ArgumentNullException("program"); } int[] uniformBlockParams; // Index Index = uniformBlockIndex; // Name length int uniformBlockNameLength; uniformBlockParams = new int[1]; Gl.GetActiveUniformBlock(program.ObjectName, Index, UniformBlockPName.UniformBlockNameLength, uniformBlockParams); uniformBlockNameLength = uniformBlockParams[0]; // Name StringBuilder uniformBlockNameBuffer = new StringBuilder(uniformBlockNameLength); int nameLength; Gl.GetActiveUniformBlockName(program.ObjectName, Index, uniformBlockNameBuffer.Capacity, out nameLength, uniformBlockNameBuffer); Gl.CheckErrors(); Name = uniformBlockNameBuffer.ToString(); // Data size uniformBlockParams = new int[1]; Gl.GetActiveUniformBlock(program.ObjectName, Index, UniformBlockPName.UniformBlockDataSize, uniformBlockParams); DataSize = (uint)uniformBlockParams[0]; // Active uniforms uniformBlockParams = new int[1]; Gl.GetActiveUniformBlock(program.ObjectName, Index, UniformBlockPName.UniformBlockActiveUniforms, uniformBlockParams); ActiveUniforms = (uint)uniformBlockParams[0]; // Uniform indices uniformBlockParams = new int[ActiveUniforms]; Gl.GetActiveUniformBlock(program.ObjectName, Index, UniformBlockPName.UniformBlockActiveUniformIndices, uniformBlockParams); UniformIndices = Array.ConvertAll(uniformBlockParams, delegate(int item) { return((uint)item); }); }
/// <summary> /// Invalidate a range of the content of this Buffer. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> that created this Buffer. /// </param> public void Invalidate(GraphicsContext ctx, IntPtr offset, uint length) { if (ctx.Extensions.InvalidateSubdata_ARB || ctx.Version.IsCompatible(Gl.Version_430)) { Gl.InvalidateBufferSubData(ObjectName, offset, length); } else { if (!Immutable && RequiresName(ctx)) { ctx.Bind(this); Gl.BufferSubData(Target, offset, length, IntPtr.Zero); } } Gl.CheckErrors(); }
/// <summary> /// Invalidate the content of this Buffer. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> that created this Buffer. /// </param> public void Invalidate(GraphicsContext ctx) { if (ctx.Extensions.InvalidateSubdata_ARB || ctx.Version.IsCompatible(Gl.Version_430)) { Gl.InvalidateBufferData(ObjectName); } else { if (!Immutable && RequiresName(ctx)) { ctx.Bind(this); Gl.BufferData(Target, Size, IntPtr.Zero, Hint); } } Gl.CheckErrors(); }
/// <summary> /// Map the GPU buffer allocated by this Buffer. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> required for mapping this Buffer. /// </param> /// <param name="mask"> /// A <see cref="BufferAccess"/> that specify the map access. /// </param> /// <exception cref="InvalidOperationException"> /// Exception thrown if this Buffer is already mapped. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if this Buffer does not exist for <paramref name="ctx"/>. /// </exception> public void Map(GraphicsContext ctx, BufferAccess mask) { CheckThisExistence(ctx); if (IsMapSupported(ctx)) { #if !MONODROID if (ctx.Extensions.DirectStateAccess_ARB || ctx.Version.IsCompatible(Gl.Version_450)) { if ((MappedBuffer = Gl.MapNamedBuffer(ObjectName, mask)) == IntPtr.Zero) { Gl.CheckErrors(); } } else { #endif ctx.Bind(this); if ((MappedBuffer = Gl.MapBuffer(Target, mask)) == IntPtr.Zero) { Gl.CheckErrors(); } #if !MONODROID } #endif } else { if (GpuBuffer == null) { throw new GlException(ErrorCode.InvalidOperation); } if ((MappedBuffer = GpuBuffer.AlignedBuffer) == IntPtr.Zero) { throw new GlException(ErrorCode.InvalidOperation); } } Debug.Assert(MappedBuffer != IntPtr.Zero); MapOffset = IntPtr.Zero; MapSize = Size; _Access = mask; }
/// <summary> /// Reset the allocated GPU buffer for this Buffer. /// </summary> /// <param name="ctx"> /// /// </param> /// <param name="size"> /// A <see cref="UInt32"/> that determine the size of the buffer object GPU buffer, in bytes. /// </param> /// <param name="data"> /// /// </param> protected void CreateGpuBuffer(GraphicsContext ctx, uint size, IntPtr data) { if (Immutable && _GpuBufferSize > 0) { throw new InvalidOperationException("buffer is immutable"); } if (Immutable && ctx.Extensions.BufferStorage_ARB) { Gl.BufferStorage(Target, size, data, (uint)_UsageMask); Gl.CheckErrors(); } else { Gl.BufferData(Target, size, data, Hint); if (CpuBufferAddress != IntPtr.Zero) { Gl.BufferSubData(Target, IntPtr.Zero, _GpuBufferSize, CpuBufferAddress); } } // Store GPU buffer size _GpuBufferSize = size; }
private void ContextCreated(object sender, NativeWindowEventArgs e) { AttributeId[] attributes = null; _vao = new VertexArrayObject(true); { var texture = new TQTexture(File.ReadAllBytes("texture.tex")); _texture = new Texture(TextureTarget.Texture2d); _texture.Parameteri(TextureParameterName.TextureWrapS, TextureWrapMode.Repeat); _texture.Parameteri(TextureParameterName.TextureWrapT, TextureWrapMode.Repeat); _texture.Parameteri(TextureParameterName.TextureMinFilter, TextureMinFilter.Linear); _texture.Parameteri(TextureParameterName.TextureMagFilter, TextureMagFilter.Linear); foreach (var frame in texture) { var dds = new DDS.DDS(frame.Data); InternalFormat internalFormat; if (dds.Header.Capabilities.HasFlag(Capabilities.Complex)) { switch (dds.Header.PixelFormat.FourCC) { case "DXT5": internalFormat = InternalFormat.CompressedRgbaS3tcDxt5Ext; break; default: throw new NotImplementedException(); } } else { throw new NotImplementedException(); } _texture.Storage2D((int)dds.Header.MipmapCount, internalFormat, (int)dds.Header.Width, (int)dds.Header.Height); foreach (var layer in dds) { int level = 0; foreach (var mip in layer) { unsafe { fixed(byte *ptr = mip.Data) { _texture.CompressedSubImage2D( level++, internalFormat, xOffset: 0, yOffset: 0, width: (int)Math.Max(1, (dds.Header.Width * 2) >> level), height: (int)Math.Max(1, (dds.Header.Height * 2) >> level), data: mip.Data); Gl.CheckErrors(); } } } break; //TODO: Further layers. } break; //TODO: Further frames. } } var mesh = new Mesh.Mesh(File.ReadAllBytes("mesh.msh")); foreach (var part in mesh) { if (part.Is(out VertexBuffer vertexBuffer)) { Console.Write("Loading VBO..."); var vbo = new Buffer(true); vbo.BufferData(vertexBuffer.Buffer, BufferUsage.StaticDraw); _vao.VertexBuffer(0, vbo, IntPtr.Zero, vertexBuffer.Header.Stride); Console.Write(" OK!"); attributes = vertexBuffer.Attributes.ToArray(); Console.Write($" (also got {attributes.Length} attributes)"); _vertexCount = vertexBuffer.Header.VertexCount; Console.WriteLine($" (also got vertex count {_vertexCount})"); } else if (part.Is(out Shaders shaders)) { foreach (var shader in shaders) { { Console.Write($"Sort of loading {shader.FileName}..."); using (var vertexShader = new Shader(ShaderType.VertexShader, File.ReadAllText($"{shader.FileName}.vertex.glsl"))) using (var fragmentShader = new Shader(ShaderType.FragmentShader, File.ReadAllText($"{shader.FileName}.fragment.glsl"))) { _program = new ShaderProgram(vertexShader, fragmentShader); } _program.Link(); Console.WriteLine(" OK!"); } { Console.Write($"Setting up attibutes..."); var offset = 0u; foreach (var attribute in attributes) { switch (attribute) { case AttributeId.Position: SetUpAttribute(_vao, _program, "position", 3, VertexAttribType.Float, normalized: false, offset, bindingIndex: 0); break; case AttributeId.Normal: SetUpAttribute(_vao, _program, "normal", 3, VertexAttribType.Float, normalized: true, offset, bindingIndex: 0); break; case AttributeId.Tangent: SetUpAttribute(_vao, _program, "tangent", 3, VertexAttribType.Float, normalized: true, offset, bindingIndex: 0); break; case AttributeId.Bitangent: SetUpAttribute(_vao, _program, "bitangent", 3, VertexAttribType.Float, normalized: true, offset, bindingIndex: 0); break; case AttributeId.UV: SetUpAttribute(_vao, _program, "uv", 2, VertexAttribType.Float, normalized: false, offset, bindingIndex: 0); break; case AttributeId.Weights: SetUpAttribute(_vao, _program, "weights", 4, VertexAttribType.Float, normalized: false, offset, bindingIndex: 0); break; case AttributeId.Bones: SetUpAttribute(_vao, _program, "bones", 4, VertexAttribType.Byte, normalized: false, offset, bindingIndex: 0); break; case AttributeId.Bytes: SetUpAttribute(_vao, _program, "bytes", 4, VertexAttribType.UnsignedByte, normalized: false, offset, bindingIndex: 0); break; } offset += GetAttributeSize(attribute); } Console.WriteLine(" OK!"); } { Console.Write($"Setting up uniforms..."); if (_program.TryGetUniformLocation("transformation", out var transformationUniform)) { var matrix = new Matrix4x4( .5f, 0, 0, 0, 0, .5f, 0, 0, 0, 0, .5f, 0, 0, -.7f, 0, 1 ); _program.UniformMatrix4f(transformationUniform, transpose: false, in matrix); } else { throw new NotImplementedException(); } Console.WriteLine(" OK!"); } } } else if (part.Is(out IndexBuffer indexBuffer)) { Console.Write("Loading IBO..."); var ibo = new Buffer(true); ibo.BufferData(indexBuffer.TriangleIndices, BufferUsage.StaticDraw); _vao.ElementBuffer(ibo); Console.WriteLine(" OK!"); var drawRanges = new List <(int, int)>(); foreach (var drawCall in indexBuffer) { drawRanges.Add((drawCall.Common.StartFaceIndex, drawCall.Common.FaceCount)); } _drawRanges = drawRanges.ToArray(); } else if (part.Is(out Bones bones)) { _boneVao = new VertexArrayObject(true); Console.Write("Loading Bones..."); _boneMatrices = new Matrix4x4[bones.Count]; _bonePositions = new Vector3[bones.Count]; for (int i = 0; i < _boneMatrices.Length; i++) { _boneMatrices[i] = Matrix4x4.Identity; } foreach (var bone in bones) { var i = bone.Index; var position = new Vector4(bone.Position, 1); var bonePosition = Vector4.Transform(position, _boneMatrices[i]); _bonePositions[i] = new Vector3(bonePosition.X, bonePosition.Y, bonePosition.Z); var boneMatrix = new Matrix4x4( bone.Axes[0], bone.Axes[1], bone.Axes[2], 0, bone.Axes[3], bone.Axes[4], bone.Axes[5], 0, bone.Axes[6], bone.Axes[7], bone.Axes[8], 0, bone.Position.X, bone.Position.Y, bone.Position.Z, 1 ); _boneMatrices[i] = boneMatrix * _boneMatrices[i]; foreach (var childBone in bone) { _boneMatrices[childBone.Index] = _boneMatrices[i]; } } var boneVbo = new Buffer(true); Span <Vector3> boneVboData = (from p in _bonePositions select new Vector3(p.X / 2, p.Y / 2 - .7f, p.Z / 2)).ToArray().AsSpan(); _boneVao.VertexBuffer(0, boneVbo, IntPtr.Zero, 3 * sizeof(float)); Gl.CheckErrors(); boneVbo.BufferData(boneVboData, BufferUsage.StaticDraw); Gl.CheckErrors(); //TODO: LINQ it! var boneIbo = new Buffer(true); Gl.CheckErrors(); var boneIboEntries = new List <(int, int)>(); foreach (var parent in bones) { foreach (var child in parent) { boneIboEntries.Add((parent.Index, child.Index)); } } boneIbo.BufferData(boneIboEntries.SelectMany(x => new[] { (ushort)x.Item1, (ushort)x.Item2 }).ToArray().AsSpan(), BufferUsage.StaticDraw); _boneVao.ElementBuffer(boneIbo); Gl.CheckErrors(); _boneLinkCount = boneIboEntries.Count; using (var vertexShader = new Shader(ShaderType.VertexShader, File.ReadAllText("bones.vertex.glsl"))) using (var fragmentShader = new Shader(ShaderType.FragmentShader, File.ReadAllText("bones.fragment.glsl"))) { _boneProgram = new ShaderProgram(vertexShader, fragmentShader); } _boneProgram.Link(); Console.WriteLine(" OK!"); SetUpAttribute(_boneVao, _boneProgram, "position", 3, VertexAttribType.Float, normalized: false, relativeOffset: 0, bindingIndex: 0); Gl.CheckErrors(); } } }
/// <summary> /// Map a range of the GPU buffer allocated by this Buffer. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> required for mapping this Buffer. /// </param> /// <param name="mask"> /// A <see cref="BufferAccessMask"/> that specify the map access. /// </param> /// <exception cref="InvalidOperationException"> /// Exception thrown if this Buffer is already mapped. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if this Buffer does not exist for <paramref name="ctx"/>. /// </exception> public void Map(GraphicsContext ctx, BufferAccessMask mask, IntPtr offset = default(IntPtr), uint size = 0) { CheckThisExistence(ctx); uint mapSize = size != 0 ? size : Size; if (IsMapRangeSupported(ctx)) { #if !MONODROID if (ctx.Extensions.DirectStateAccess_ARB || ctx.Version.IsCompatible(Gl.Version_450)) { if ((MappedBuffer = Gl.MapNamedBufferRange(ObjectName, offset, mapSize, mask)) == IntPtr.Zero) { Gl.CheckErrors(); } } else { #endif ctx.Bind(this); if ((MappedBuffer = Gl.MapBufferRange(Target, offset, mapSize, mask)) == IntPtr.Zero) { Gl.CheckErrors(); } #if !MONODROID } #endif } else { if (GpuBuffer == null) { throw new GlException(ErrorCode.InvalidOperation); } if (GpuBuffer.AlignedBuffer == IntPtr.Zero) { throw new GlException(ErrorCode.InvalidOperation); } MappedBuffer = new IntPtr(GpuBuffer.AlignedBuffer.ToInt64() + offset.ToInt64()); } // Determine map access if (mask.HasFlag(BufferAccessMask.MapReadBit) && mask.HasFlag(BufferAccessMask.MapWriteBit)) { _Access = BufferAccess.ReadWrite; } else if (mask.HasFlag(BufferAccessMask.MapReadBit)) { _Access = BufferAccess.ReadOnly; } else if (mask.HasFlag(BufferAccessMask.MapWriteBit)) { _Access = BufferAccess.WriteOnly; } else { _Access = 0; } Debug.Assert(MappedBuffer != IntPtr.Zero); MapOffset = offset; MapSize = mapSize; _AccessMask = mask; }