diff --git a/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Program.cs b/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Program.cs index bb86e58759..ebaf8dc893 100644 --- a/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Program.cs +++ b/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Program.cs @@ -1,10 +1,11 @@ using System; -using System.Drawing; using System.IO; using Silk.NET.Maths; using Silk.NET.Windowing; using Silk.NET.OpenGL; -using StbImageSharp; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using Color = System.Drawing.Color; // Textures! // In this tutorial, you'll learn how to load and render textures. @@ -170,7 +171,7 @@ void main() _gl.DetachShader(_program, fragmentShader); _gl.DeleteShader(vertexShader); _gl.DeleteShader(fragmentShader); - + // Set up our vertex attributes! These tell the vertex array (VAO) how to process the vertex data we defined // earlier. Each vertex array contains attributes. @@ -195,49 +196,64 @@ void main() _gl.BindBuffer(BufferTargetARB.ArrayBuffer, 0); _gl.BindBuffer(BufferTargetARB.ElementArrayBuffer, 0); - // Now we create our texture! - // First, we create the texture itself. Then, we must set an active texture unit. Each texture unit is a + // Now we begin the process of creating our texture! + // First, we create the texture handle. Then, we must set an active texture unit. Each texture unit is a // separate bindable texture that we can use in a shader. GPUs have a maximum number of texture units they // can use, however the OpenGL spec states there MUST be at least 32 units available. - // Much like buffers, we then bind the texture to a Texture2D target. + // Much like buffers, we then bind the texture to the Texture2D target. _texture = _gl.GenTexture(); _gl.ActiveTexture(TextureUnit.Texture0); _gl.BindTexture(TextureTarget.Texture2D, _texture); - // Use StbImageSharp to load an image from our PNG file. - // This will load and decompress the result into a raw byte array that we can pass directly into OpenGL. - ImageResult result = ImageResult.FromMemory(File.ReadAllBytes("silk.png"), ColorComponents.RedGreenBlueAlpha); - - fixed (byte* ptr = result.Data) + // Use ImageSharp to load an image from our PNG file. + using (Image image = Image.Load("silk.png")) { - // Upload our texture data to the GPU. - // Let's go over each parameter used here: - // 1. Tell OpenGL that we want to upload to the texture bound in the Texture2D target. - // 2. We are uploading the "base" texture level, therefore this value should be 0. You don't need to + // Now, let's create the texture itself. + // Much like buffers, the texture is not created until you call glTexImage2D, where you define some + // parameters to describe the texture. Let's go over each parameter used here: + // 1. Tell OpenGL that we want to use the texture bound in the Texture2D target. + // 2. We are creating the "base" texture level, therefore this value should be 0. You don't need to // worry about texture levels for now. // 3. We tell OpenGL that we want the GPU to store this data as RGBA formatted data on the GPU itself. // 4. The image's width. // 5. The image's height. - // 6. This is the image's border. This valu MUST be 0. It is a leftover component from legacy OpenGL, and - // it serves no purpose. + // 6. This is the image's border. This value MUST be 0. It is a leftover component from legacy OpenGL, + // and it serves no purpose. // 7. Our image data is formatted as RGBA data, therefore we must tell OpenGL we are uploading RGBA data. - // 8. StbImageSharp returns this data as a byte[] array, therefore we must tell OpenGL we are uploading - // data in the unsigned byte format. - // 9. The actual pointer to our data! - _gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint) result.Width, - (uint) result.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, ptr); + // 8. The Rgba32 struct contains four color channels stored as bytes. Therefore we must tell OpenGL we + // each color channel will be an unsigned byte. + // 9. This parameter is a pointer to an array of texture data. ImageSharp doesn't provide a single array + // of data, so we just pass in null here, and upload our texture data below instead. + _gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint) image.Width, (uint) image.Height, + 0, PixelFormat.Rgba, PixelType.UnsignedByte, null); + + // Upload our texture data line-by-line. + image.ProcessPixelRows(accessor => + { + for (int y = 0; y < accessor.Height; y++) + { + fixed (void* data = accessor.GetRowSpan(y)) + { + // glTexSubImage2D allows us to upload data to arbitrary locations within the texture. + // This can be used to upload to sub-regions of the texture. + // In this case, we use it to upload each line of our texture data to the texture. + _gl.TexSubImage2D(TextureTarget.Texture2D, 0, 0, y, (uint) accessor.Width, 1, + PixelFormat.Rgba, PixelType.UnsignedByte, data); + } + } + }); } - // Let's set some texture parameters! + // Now let's set some texture parameters! // This tells the GPU how it should sample the texture. - + // Set the texture wrap mode to repeat. // The texture wrap mode defines what should happen when the texture coordinates go outside of the 0-1 range. // In this case, we set it to repeat. The texture will just repeatedly tile over and over again. // You'll notice we're using S and T wrapping here. This is OpenGL's version of the standard UV mapping you // may be more used to, where S is on the X-axis, and T is on the Y-axis. - _gl.TextureParameter(_texture, TextureParameterName.TextureWrapS, (int) TextureWrapMode.Repeat); - _gl.TextureParameter(_texture, TextureParameterName.TextureWrapT, (int) TextureWrapMode.Repeat); + _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.Repeat); + _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.Repeat); // The min and mag filters define how the texture should be sampled as it resized. // The min, or minification filter, is used when the texture is reduced in size. @@ -246,8 +262,8 @@ void main() // You can also use nearest (point) filtering, or anisotropic filtering, which is only available on the min // filter. // You may notice that the min filter defines a "mipmap" filter as well. We'll go over mipmaps below. - _gl.TextureParameter(_texture, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear); - _gl.TextureParameter(_texture, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Linear); + _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear); + _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Linear); // Generate mipmaps for this texture. // Note: We MUST do this or the texture will appear as black (this is an option you can change but this is diff --git a/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Tutorial 1.3 - Textures.csproj b/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Tutorial 1.3 - Textures.csproj index 01749d18b8..ac9b08dd54 100644 --- a/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Tutorial 1.3 - Textures.csproj +++ b/examples/CSharp/OpenGL Tutorials/Tutorial 1.3 - Textures/Tutorial 1.3 - Textures.csproj @@ -12,9 +12,9 @@ - + - + diff --git a/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Texture.cs b/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Texture.cs index d3397d0939..970bfb8165 100644 --- a/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Texture.cs +++ b/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Texture.cs @@ -1,7 +1,8 @@ using System; using System.IO; using Silk.NET.OpenGL; -using StbImageSharp; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; namespace Tutorial { @@ -19,14 +20,24 @@ public unsafe Texture(GL gl, string path) _handle = _gl.GenTexture(); Bind(); - // Load the image from memory. - ImageResult result = ImageResult.FromMemory(File.ReadAllBytes(path), ColorComponents.RedGreenBlueAlpha); - - fixed (byte* ptr = result.Data) + //Loading an image using imagesharp. + using (var img = Image.Load(path)) { - // Create our texture and upload the image data. - _gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint) result.Width, - (uint) result.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, ptr); + //Reserve enough memory from the gpu for the whole image + gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint) img.Width, (uint) img.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, null); + + img.ProcessPixelRows(accessor => + { + //ImageSharp 2 does not store images in contiguous memory by default, so we must send the image row by row + for (int y = 0; y < accessor.Height; y++) + { + fixed (void* data = accessor.GetRowSpan(y)) + { + //Loading the actual image. + gl.TexSubImage2D(TextureTarget.Texture2D, 0, 0, y, (uint) accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, data); + } + } + }); } SetParameters(); diff --git a/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Tutorial 1.4 - Abstraction.csproj b/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Tutorial 1.4 - Abstraction.csproj index 1426fa3261..16c8b18908 100644 --- a/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Tutorial 1.4 - Abstraction.csproj +++ b/examples/CSharp/OpenGL Tutorials/Tutorial 1.4 - Abstractions/Tutorial 1.4 - Abstraction.csproj @@ -26,7 +26,7 @@ - + - \ No newline at end of file +