Pages

Showing posts with label Textures. Show all posts
Showing posts with label Textures. Show all posts

OpenTK Textures

So you want to know how to use textures? Well i don't know what to say other than read on :]

First off is just the prefix, Loading a texture in its simplest form.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private Bitmap texture_source;
private int texture;

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    //Load texture from file
    texture_source = new Bitmap("texture.png");

    //Generate empty texture
    texture = GL.GenTexture();

    //Link empty texture to texture2d
    GL.BindTexture(TextureTarget.Texture2D, texture);

    //Must be set else the texture will show glColor
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);

    //Describe to gl what we want the bound texture to look like
    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, texture_source.Width, texture_source.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
    
    //Lock pixel data to memory and prepare for pass through
    System.Drawing.Imaging.BitmapData bitmap_data = texture_source.LockBits(new Rectangle(0, 0, texture_source.Width, texture_source.Height),
        System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    //Tell gl to write the data from are bitmap image/data to the bound texture
    GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, texture_source.Width, texture_source.Height, PixelFormat.Bgra, PixelType.UnsignedByte, bitmap_data.Scan0);
    
    //Release from memory
    texture_source.UnlockBits(bitmap_data);

    //Release texture
    GL.BindTexture(TextureTarget.Texture2D, 0);

    //Enable textures from texture2d target
    GL.Enable(EnableCap.Texture2D);
}

Method
For convenience

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
private int LoadTexture(string path, int quality = 0, bool repeat = true, bool flip_y = false)
{
    Bitmap bitmap = new Bitmap(path);

    //Flip the image
    if (flip_y)
        bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);

    //Generate a new texture target in gl
    int texture = GL.GenTexture();

    //Will bind the texture newly/empty created with GL.GenTexture
    //All gl texture methods targeting Texture2D will relate to this texture
    GL.BindTexture(TextureTarget.Texture2D, texture);

    //The reason why your texture will show up glColor without setting these parameters is actually
    //TextureMinFilters fault as its default is NearestMipmapLinear but we have not established mipmapping
    //We are only using one texture at the moment since mipmapping is a collection of textures pre filtered
    //I'm assuming it stops after not having a collection to check.
    switch (quality)
    {
        case 0:
        default://Low quality
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
            break;
        case 1://High quality
            //This is in my opinion the best since it doesnt average the result and not blurred to shit
            //but most consider this low quality...
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Nearest);
            break;
    }

    if (repeat)
    {
        //This will repeat the texture past its bounds set by TexImage2D
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Repeat);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Repeat);
    }
    else
    {
        //This will clamp the texture to the edge, so manipulation will result in skewing
        //It can also be useful for getting rid of repeating texture bits at the borders
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
    }

    //Creates a definition of a texture object in opengl
    /* Parameters
     * Target - Since we are using a 2D image we specify the target Texture2D
     * MipMap Count / LOD - 0 as we are not using mipmapping at the moment
     * InternalFormat - The format of the gl texture, Rgba is a base format it works all around
     * Width;
     * Height;
     * Border - must be 0;
     * 
     * Format - this is the images format not gl's the format Bgra i believe is only language specific
     *          C# uses little-endian so you have ARGB on the image A 24 R 16 G 8 B, B is the lowest
     *          So it gets counted first, as with a language like Java it would be PixelFormat.Rgba
     *          since Java is big-endian default meaning A is counted first.
     *          but i could be wrong here it could be cpu specific :P
     *          
     * PixelType - The type we are using, eh in short UnsignedByte will just fill each 8 bit till the pixelformat is full
     *             (don't quote me on that...)
     *             you can be more specific and say for are RGBA to little-endian BGRA -> PixelType.UnsignedInt8888Reversed
     *             this will mimic are 32bit uint in little-endian.
     *             
     * Data - No data at the moment it will be written with TexSubImage2D
     */
    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bitmap.Width, bitmap.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);

    //Load the data from are loaded image into virtual memory so it can be read at runtime
    System.Drawing.Imaging.BitmapData bitmap_data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
        System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    //Writes data to are texture target
    /* Target;
     * MipMap;
     * X Offset - Offset of the data on the x axis
     * Y Offset - Offset of the data on the y axis
     * Width;
     * Height;
     * Format;
     * Type;
     * Data - Now we have data from the loaded bitmap image we can load it into are texture data
     */
    GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, bitmap.Width, bitmap.Height, PixelFormat.Bgra, PixelType.UnsignedByte, bitmap_data.Scan0);

    //Release from memory
    bitmap.UnlockBits(bitmap_data);

    //get rid of bitmap object its no longer needed in this method
    bitmap.Dispose();

    /*Binding to 0 is telling gl to use the default or null texture target
    *This is useful to remember as you may forget that a texture is targeted
    *And may overflow to functions that you dont necessarily want to
    *Say you bind a texture
    *
    * Bind(Texture);
    * DrawObject1();
    *                <-- Insert Bind(NewTexture) or Bind(0)
    * DrawObject2();
    * 
    * Object2 will use Texture if not set to 0 or another.
    */
    GL.BindTexture(TextureTarget.Texture2D, 0);

    return texture;
}

Usage Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
private int current_texture;

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    current_texture = LoadTexture("texture.png", 1);

    GL.Enable(EnableCap.Texture2D);
    //Basically enables the alpha channel to be used in the color buffer
    GL.Enable(EnableCap.Blend);
    //The operation/order to blend
    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
    //Use for pixel depth comparing before storing in the depth buffer
    GL.Enable(EnableCap.DepthTest);
}

protected override void OnRenderFrame(FrameEventArgs e)
{
    base.OnRenderFrame(e);

    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
    GL.MatrixMode(MatrixMode.Modelview);
    GL.LoadIdentity();

    GL.PushMatrix();

    GL.Translate(0, 0, -5);

    GL.Color4(Color.White);

    GL.BindTexture(TextureTarget.Texture2D, current_texture);

    GL.Begin(BeginMode.Quads);

    //Bind texture coordinates to vertices in ccw order

    //Top-Right
    GL.TexCoord2(1.0f, 0.0f);
    GL.Vertex2(1.0f, 1.0f);

    //Top-Left
    GL.TexCoord2(0f, 0f);
    GL.Vertex2(-1.0f, 1.0f);

    //Bottom-Left
    GL.TexCoord2(0f, 1f);
    GL.Vertex2(-1.0f, -1.0f);

    //Bottom-Right
    GL.TexCoord2(1f, 1f);
    GL.Vertex2(1.0f, -1.0f);

    GL.End();

    GL.BindTexture(TextureTarget.Texture2D, 0);

    GL.PopMatrix();

    SwapBuffers();
}