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
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Unofficial.OpenTK.Utilities" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Unofficial.OpenTK.Utilities --version 1.0.0
#r "nuget: Unofficial.OpenTK.Utilities, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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 80 4/13/2024