Unofficial.OpenTK.Utilities
1.0.0
dotnet add package Unofficial.OpenTK.Utilities --version 1.0.0
NuGet\Install-Package Unofficial.OpenTK.Utilities -Version 1.0.0
<PackageReference Include="Unofficial.OpenTK.Utilities" Version="1.0.0" />
paket add Unofficial.OpenTK.Utilities --version 1.0.0
#r "nuget: Unofficial.OpenTK.Utilities, 1.0.0"
// Install Unofficial.OpenTK.Utilities as a Cake Addin #addin nuget:?package=Unofficial.OpenTK.Utilities&version=1.0.0 // Install Unofficial.OpenTK.Utilities as a Cake Tool #tool nuget:?package=Unofficial.OpenTK.Utilities&version=1.0.0
OpenTK.Utility Extension Library
This C# library was developed to provide an intuitive and efficient interface for graphics rendering using OpenGL through the OpenTK library. It offers a wide range of functionalities to create and manipulate OpenGL objects, buffers, textures of various types, and more. This project allows developers to create graphic applications with ease.
Key Features
Structured and Organized OpenGL Objects leveraging Modern OpenGL and extensive use of Direct State Access (DSA).
Full support for creating and managing well-structured buffers that are easy to use and ensure complete security in data manipulation and access, everything well organized.
Support for a variety of texture types, including 1D, 2D, 3D, cube textures, views, and array textures.
This library includes built-in support for Reading and writing images using StbImageSharp and StbimageWriterSharp, seamlessly integrated into the codebase. This feature allows for effortless loading of various image formats directly within the library without external dependencies
The development was designed to be extensible, so almost everything has interfaces, so you can use your own codes if the project structure doesn't suit you.
Font support thanks to FreetypeSharp
Installation
To use this library in your project, you can clone the repository directly to your local machine. After cloning the repository, you'll be able to reference the project within your own development environment. This method provides flexibility and control over integrating the library into your project, allowing you to easily track updates and contribute to the source code if desired.
Use the package via nuget:
Usage Examples
Namespaces
OpenTK.Utilities
OpenTK.Utilities.Objects
OpenTK.Utilities.Images
OpenTK.Utilities.Assistants
OpenTK.Utilities.Primitives
Vertexs Arrays
BufferVertices = new BufferImmutable<Data>(Vertices, StorageUseFlag.ClientStorageBit);
BufferElements = new BufferImmutable<uint>(indices, StorageUseFlag.ClientStorageBit);
VertexArrayObject = new VertexArrayObject();
VertexArrayObject.FixElementBuffer(BufferElements);
VertexArrayObject.IncludeVertexBuffer(BufferVertices);
VertexArrayObject.SetAttribFormat(0, 0, 3, VertexAttribType.Float, (int)Marshal.OffsetOf<Data>("Pos"));
VertexArrayObject.SetAttribFormat(0, 1, 2, VertexAttribType.Float, (int)Marshal.OffsetOf<Data>("TexCoord"));
VertexArrayObject.SetAttribFormat(0, 2, 4, VertexAttribType.Float, (int)Marshal.OffsetOf<Data>("Color"));
Pass a Vertex Buffer of a structure with the organized data.
[VertexBinding(0)]
public struct VertexPosUvNorm(Vector3 position, Vector2 uv, Vector3 normal)
{
[VertexAttrib(VertexAttribType.Float, 0, 3)]
public Vector3 Position = position;
[VertexAttrib(VertexAttribType.Float, 1, 2)]
public Vector2 Uv = uv;
[VertexAttrib(VertexAttribType.Float, 2, 3)]
public Vector3 Normal = normal;
}
VertexArrayObject.FixVertexBuffer<VertexPosUvNorm>(BufferVertices);
Buffers
var bufferConstant = new BufferConstant<Vector3>();
bufferConstant.BindBufferBase(BufferRangeTarget.UniformBuffer, 0);
bufferConstant.Data = new Vector3(1, 1, 0);
var bufferMapped = new BufferMapping<Transform>(5);
bufferMapped.BindBufferBase(BufferRangeTarget.ShaderStorageBuffer, bindingIndex: 1);
var bufferMutable = new BufferMutable<Data>(BufferUsageHint.DynamicDraw);
bufferMutable.ReserveStorage(50);
bufferMutable.Update(new Data[50]);
bufferMutable[5] = new Data();
// Don't keep this, Read the description of this object.
MappedRegion<Data> mappedRegion = bufferMutable.GetMapping(2, 8);
mappedRegion[0].Pos = new Vector3(100f);
mappedRegion[^1].Pos = new Vector3(450f);
foreach (var i in mappedRegion)
{
Console.WriteLine(i);
}
// Pos: <100. 100. 100> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <450. 450. 450> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// It is crucial that it is discarded.
mappedRegion.Dispose();
foreach (var i in bufferMutable)
{
Console.WriteLine(i);
}
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <100. 100. 100> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <450. 450. 450> TexCoord: <0. 0> Color: <0. 0. 0. 0>
// Pos: <0. 0. 0> TexCoord: <0. 0> Color: <0. 0. 0. 0>
bufferMutable.Dispose();
Shaders
Using the Traditional way
var shaderProgram = new ShaderProgram(ProgramMode.Unique,
Shader.FromFile(ShaderType.VertexShader, "Resources/Vertex.vert"),
Shader.FromFile(ShaderType.FragmentShader, "Resources/Fragment.frag"))
shaderProgram = EnableExceptions = true;
ShaderSample.Uniform("Model", transform.ModelMatrix);
ShaderSample.Uniform("View", Cemara.View);
ShaderSample.Uniform("Projection", Cemara.Proj);
var pos = ShaderSample.GetAttribute("inPos");
var uv = ShaderSample.GetAttribute("inUv");
var nor = ShaderSample.GetAttribute("inNorm");
VertexArrayObject.SetAttribFormat(0, pos, 3, VertexAttribType.Float, (int)Marshal.OffsetOf<Data>("Position"));
VertexArrayObject.SetAttribFormat(1, nor, 2, VertexAttribType.Float, (int)Marshal.OffsetOf<Data>("Uv"));
VertexArrayObject.SetAttribFormat(2, uv, 3, VertexAttribType.Float, (int)Marshal.OffsetOf<Data>("Normal"));
// Available resources
_ = this.ShaderVertex.ActivesAttributes;
_ = this.ShaderVertex.ActivesAtomicBuffers;
_ = this.ShaderVertex.ActivesShaderStorageBlocks;
_ = this.ShaderVertex.ActivesUniforms;
_ = this.ShaderVertex.ActivesUniformsBlocks;
Combined with pipeline object
// Note that it must be created in a separable way.
var ShaderVertex = new ShaderProgram(ProgramMode.Separable,
Shader.FromFile(ShaderType.VertexShader, "Resources\\Vertex.vert"));
var ShaderFragTexture = new ShaderProgram(ProgramMode.Separable,
Shader.FromFile(ShaderType.FragmentShader, "Resources\\Fragment.frag"));
var ShaderFragSelect = new ShaderProgram(ProgramMode.Separable,
Shader.FromFile(ShaderType.FragmentShader, "Resources\\Pixel.frag"));
Pipeline = new PipelineObject();
Pipeline.SetShader(ShaderVertex);
// or
PipelineProgram[ProgramStage.Vertex] = ShaderVertex;
Drawing
using var BufferIndiretCmd = new BufferConstant<DrawElementsIndirectCommand>();
BufferIndiretCmd.Data = new DrawElementsIndirectCommand
{
Base = 0,
Count = BufferElements.Count,
BaseInstance = 0,
InstanceCount = 100,
BaseVertex = 0,
};
Pipeline.Bind();
VertexArrayObject.Bind();
Drawing.MultiElementsIndirect(PrimitiveType.Triangles, DrawElementsType.UnsignedInt, BufferIndiretCmd, 1);
// It is advisable to use this depending on the way you choose to render your objects.
// Even more so if you are using both the pipeline object and the shader object in your application.
// For the less experienced like me:
// If you render using a pipeline object and then try to render
// with a shader object and have not restored the pipeline context
// it will not render anything, at render time it must either have a
// shader program linked, or a pipeline program.
Default.VertexArrayObject.Bind();
Default.PipelineProgram.Bind();
Texture
Load
var img = ImageLoad.FromFile("Resources/Goku Ultra Instinct 4K.jpg");
Texture2D = new Texture2D(TextureFormat.Srgb8, img.Width, img.Height);
Texture2D.Update(img.Width, img.Height, PixelFormat.Rgb, PixelType.UnsignedByte, img.Data);
Texture2D.Filtering = Filtering.Linear;
Texture2D.Wrapping = Wrapping2D.ClampToBorder;
Texture2D.GenerateMipmap();
// Use of extension 'GL_ARB_bindless_texture'.
// https://www.khronos.org/opengl/wiki/Bindless_Texture
ShaderSample.Uniform("BaseColor", Texture2D.BindlessHandler);
Textures Views
Texture2DView View2D = Texture2D;
Save
if(ImGui.Button("SaveScreen"))
{
using Texture2D screenTex = Default.Framebuffer.ExtractTextureColor<Texture2D>(WinSize);
TextureManager.SaveJpg(screenTex, filePath: "Resources", fileName: "ScreenShoot", 100)
}
ReadOnly Objects
Almost all objects have a read-only version of themselves, either by interface or by an instance. It seems confusing, but it's quite simple. I decided to implement this to facilitate security, so external objects can be secured without risk of disposal.
VertexArray = new VertexArrayObject();
ReadOnlyVertexArrayObject vertex = VertexArray;
this.ShaderVertex = new ShaderProgram(ProgramMode.Separable,
Shader.FromFile(ShaderType.VertexShader, "Resources\\Vertex.vert"));
ReadOnlyShaderProgram shader = ShaderVertex;
// Due to their nature, 'Textures' and 'bufferObjects' only have per interface.
Texture2D = new Texture2D(TextureFormat.Rgba8, img.Width, img.Height, 5);
IReadOnlyTexture2D texture = Texture2D;
See the example to understand better: Sample
Contribution
Contributions are welcome! There's still a lot to do and review, I've only tested a few features, feel free to report issues, suggest improvements, or send pull requests for this project.
Credits
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- OpenTK.Graphics (>= 4.8.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 139 | 4/13/2024 |