OpenTK Textures - Loading

Application, C# Code:
using System;
using System.IO;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using MDLN.GLTools;

namespace OpenTKTest {
 public class GLForm : Form {
  protected GLControl cglGLView;
  protected Label clblLog;
  protected bool cbGLReady;
  protected GLShader cShader;
  protected GLModel cModel;
  protected int ciUniformBuffer;

  public static void Main() {
   GLForm frmGL;

   //Create the form and give it control
   frmGL = new GLForm();
   Application.Run(frmGL);

   return;
  }

   public GLForm() {
   //Initialize Log label
   clblLog = new Label();

   clblLog.Top = 485;
   clblLog.Left = 0;
   clblLog.Width = 800;
   clblLog.Height = 125;
   clblLog.Text = "";

   Controls.Add(clblLog);

   cbGLReady = false;

   cglGLView = new GLControl();

   //Position and configure the controls
   cglGLView.Top = 0;
   cglGLView.Left = 0;
   cglGLView.Width = 640;
   cglGLView.Height = 480;

   //Define callbacks for the controls
   cglGLView.Load += new EventHandler(GLViewLoading);  
   cglGLView.Paint += new PaintEventHandler(GLViewPainting); 
   Controls.Add(cglGLView);

   //Position and configure the form
   this.Width = 775;
   this.Height = 670;
   this.FormBorderStyle = FormBorderStyle.FixedSingle;

   return;
  }

  public int WriteLog(string strText) {
   string strCurrText, strNewText;
   string[] astrList;
   int iCtr;

   strCurrText = clblLog.Text;
   astrList = strCurrText.Split('\n');

   if (astrList.Length > 9) { //log shows too man lines, truncate
    strCurrText = "";
    for (iCtr = 0; iCtr < 10; iCtr++) {
     strCurrText = astrList[astrList.Length - iCtr - 1] + "\n" + strCurrText;
    }
   } else { //Array has space, just add line
    strCurrText = clblLog.Text;
   }

   strNewText = strCurrText + "\n" + strText;

   //Remove extraneous new lines
   strNewText = strNewText.Replace("\n\n", "\n");
   while (strNewText.Substring(0, 1) == "\n") {
    strNewText = strNewText.Substring(1, strNewText.Length - 2);
   }

   //Put the log in the label
   clblLog.Text = strNewText;
   return 0;
   }

  private void GLViewLoading(object oSender, EventArgs eaArgs) {
   //The GLControl is now loading
   Matrix4 pmatMatrix;
   float fAspect;
   float[] afUniform;
   int[] aiBuffers;

   WriteLog("GLControl: Loading...");
   WriteLog("OpenGL Version: " + GL.GetString(StringName.Version));

   //Setup GL
   GL.ClearColor(0.0f, 0.0f, 0.2f, 0.0f);
   GL.Enable(EnableCap.DepthTest);

   //Setup the viewport
   GL.Viewport(0, 0, cglGLView.Width, cglGLView.Height);
   fAspect = cglGLView.Width / cglGLView.Height;
   pmatMatrix = Matrix4.CreatePerspectiveFieldOfView(45 * (MathHelper.Pi / 180), fAspect, 0.1f, 100.0f);
   GL.MatrixMode(MatrixMode.Projection);
   GL.LoadMatrix(ref pmatMatrix);
   GL.MatrixMode(MatrixMode.Modelview);

   //Load shader
   cShader = new GLShader();
   cShader.AddUniform("Data", 0);
   cShader.AddUniform("ModelData", 1);
   cShader.AddAttribute("v3Location", 5);
   cShader.AddAttribute("v2UVCoord", 6);
   cShader.VertexFile = "Vertex.glsl";
   cShader.FragmentFile = "Fragment.glsl";
   if (cShader.BuildShader() == false) {
    WriteLog(cShader.ErrorDescription);
   }

   //Load model
   cModel = new GLModel();
   cModel.LoadOBJFile("Cube.obj");
   cModel.SetBaseColor(1.0f, 0.0f, 1.0f, 1.0f);
   cModel.LoadTexture("DiceTexture.png");
   cModel.UniformID = cShader.FindUniformID("ModelData");
   cModel.VertexAttributeID = cShader.FindAttributeID("v3Location");
   cModel.UVCoordsAttributeID = cShader.FindAttributeID("v2UVCoord");

   //Setup our uniform data
   afUniform = new float[20];

   afUniform[0] = pmatMatrix.Row0.X;
   afUniform[1] = pmatMatrix.Row1.X;
   afUniform[2] = pmatMatrix.Row2.X;
   afUniform[3] = pmatMatrix.Row3.X;
   afUniform[4] = pmatMatrix.Row0.Y;
   afUniform[5] = pmatMatrix.Row1.Y;
   afUniform[6] = pmatMatrix.Row2.Y;
   afUniform[7] = pmatMatrix.Row3.Y;
   afUniform[8] = pmatMatrix.Row0.Z;
   afUniform[9] = pmatMatrix.Row1.Z;
   afUniform[10] = pmatMatrix.Row2.Z;
   afUniform[11] = pmatMatrix.Row3.Z;
   afUniform[12] = pmatMatrix.Row0.W;
   afUniform[13] = pmatMatrix.Row1.W;
   afUniform[14] = pmatMatrix.Row2.W;
   afUniform[15] = pmatMatrix.Row3.W;

   afUniform[16] = 0.5f;
   afUniform[17] = 0.5f;
   afUniform[18] = 1.0f;
   afUniform[19] = 1.0f;

   //Load uniform data
   aiBuffers = new int[1];
   GL.GenBuffers(aiBuffers.Length, aiBuffers);
   ciUniformBuffer = aiBuffers[0];

   GL.BindBuffer(BufferTarget.UniformBuffer, ciUniformBuffer);
   GL.BufferData(BufferTarget.UniformBuffer, (IntPtr)(afUniform.Length * sizeof(float)), afUniform, BufferUsageHint.DynamicDraw);
   GL.BindBufferBase(BufferTarget.UniformBuffer, cShader.FindUniformID("Data"), ciUniformBuffer);

   //Done setting up GL for use
   cbGLReady = true;

   return;
  }

  private void GLViewPainting(object oSender, EventArgs eaArgs) {
   if (cbGLReady == false) {//Control is not loaded, do nothing
    return;
   }
   WriteLog("Painting...");

   //Specify Shader
   GL.UseProgram(cShader.Program);

   //Clear the GL View
   GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
   GL.MatrixMode(MatrixMode.Modelview);

   //Render the model
   cModel.RenderObject();

   //Drawing complete
   cglGLView.SwapBuffers();

   return;
  }
 }
}

GLTools Library, C# Code:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

[assembly: AssemblyProduct("OpenTK/OpenGL Library")]
[assembly: AssemblyCopyright("Copyright © Jason Beighel")]
[assembly: AssemblyTrademark("Mindlence")]
[assembly: AssemblyVersion("0.1.0.2")]
[assembly: AssemblyFileVersion("0.1.0.2")]

namespace MDLN {
 namespace GLTools {
  public class GLModel {
   private Vector3[] cav3Vertexes, cav3Normals;
   private Vector2[] cav2UVCoords;
   private bool cbUniformChange, cbVertexChange, cbNormalChange, cbUVCoordsChange;
   private Vector4 cv4BaseColor;
   private int ciUniformBuffer, ciUniformID, ciVertexBuffer, ciVertexID, ciTextureID, ciUVCoordsBuffer, ciUVCoordsID;
   private string cstrErrDesc;

   public GLModel() {
    int[] aiBuffList;

    cbVertexChange = true;
    cbNormalChange = true;
    cbUVCoordsChange = true;
    cbUniformChange = true;

    ciUniformBuffer = -1;
    ciUniformID = -1;
    ciVertexBuffer = -1;
    ciVertexID = -1;
    ciTextureID = -1;
    ciUVCoordsID = -1;

    aiBuffList = new int[4];
    GL.GenBuffers(aiBuffList.Length, aiBuffList);
    ciVertexBuffer = aiBuffList[0];
    ciUniformBuffer = aiBuffList[1];
    ciUVCoordsBuffer = aiBuffList[2];
   }

   public Vector4 BaseColor {
    get {
     return cv4BaseColor;
    }
   }

   public int UniformBuffer {
    get {
     return ciUniformBuffer;
    }

    set {
     ciUniformBuffer = value;
    }
   }

   public int UniformID {
    get {
     return ciUniformID;
    }

    set {
     ciUniformID = value;
    }
   }

   public int VertexAttributeID {
    get {
     return ciVertexID;
    }

    set {
     ciVertexID = value;
    }
   }

   public int UVCoordsAttributeID {
    get {
     return ciUVCoordsID;
    }

    set {
     ciUVCoordsID = value;
    }
   }

   public string ErrorDescription {
    get {
     return cstrErrDesc;
    }
   }

   public bool SetBaseColor(float fRed, float fGreen, float fBlue, float fAlpha) {
    cv4BaseColor.X = fRed;
    cv4BaseColor.Y = fGreen;
    cv4BaseColor.Z = fBlue;
    cv4BaseColor.W = fAlpha;

    return true;
   }

   public bool LoadOBJFile(string strFile) {
    string strChunk;
    string[] astrLines, astrLineParts, astrFaceParts;
    int iCtr, iCnt, iFaceCount, iCurrVert, iSrcIndex;
    List lv3Vertexes, lv3Normals;
    List lv2UVCoords;
    Vector3 v3New;
    Vector2 v2New;
    StreamReader srModel;

    cstrErrDesc = "";

    iFaceCount = 0;

    lv3Vertexes = new List();
    lv3Normals = new List();
    v3New = new Vector3();

    lv2UVCoords = new List();
    v2New = new Vector2();

    srModel = new StreamReader(strFile);
    strChunk = srModel.ReadToEnd();
    srModel.Close();

    astrLines = strChunk.Split('\n');

    //First pass through the file: Load all vertex information
    for (iCtr = 0; iCtr < astrLines.Length; iCtr++) {
     astrLineParts = astrLines[iCtr].Split(' ');

     switch (astrLineParts[0]) {
      case "v" : //Vertex coordinates
       v3New.X = float.Parse(astrLineParts[1], CultureInfo.InvariantCulture.NumberFormat);
       v3New.Y = float.Parse(astrLineParts[2], CultureInfo.InvariantCulture.NumberFormat);
       v3New.Z = float.Parse(astrLineParts[3], CultureInfo.InvariantCulture.NumberFormat);

       lv3Vertexes.Add(v3New);
       break;
      case "vt" : //Vertex texture coordinates (UV Coordinates)
       v2New.X = float.Parse(astrLineParts[1], CultureInfo.InvariantCulture.NumberFormat);
       v2New.Y = float.Parse(astrLineParts[2], CultureInfo.InvariantCulture.NumberFormat);

       lv2UVCoords.Add(v2New);
       break;
      case "vn" : //Vertex normal
       v3New.X = float.Parse(astrLineParts[1], CultureInfo.InvariantCulture.NumberFormat);
       v3New.Y = float.Parse(astrLineParts[2], CultureInfo.InvariantCulture.NumberFormat);
       v3New.Z = float.Parse(astrLineParts[3], CultureInfo.InvariantCulture.NumberFormat);

       lv3Normals.Add(v3New);
       break;
      case "f" : //Face information, just count them
       iFaceCount++;
       break;
      default : //Unknown line information, skip it
       break;
     }
    }

    //Resize the class data arrays based on the number of faces
    cav3Vertexes = new Vector3[iFaceCount * 3]; //1FaceCount has the number of faces
    cav3Normals  = new Vector3[iFaceCount * 3]; //Each face has 3 vertexes

    cav2UVCoords = new Vector2[iFaceCount * 3];

    //Second pass through the file: process all faces
    iCurrVert = 0;
    for (iCtr = 0; iCtr < astrLines.Length; iCtr++) {
     astrLineParts = astrLines[iCtr].Split(' ');

     switch (astrLineParts[0]) {
      case "f" : //Face information
       for (iCnt = 1; iCnt <= 3; iCnt++) {
        astrFaceParts = astrLineParts[iCnt].Split('/');

        //Copy vertex coordinates
        iSrcIndex = Convert.ToInt32(astrFaceParts[0]) - 1; //Obj indexes start at 1, C# arrays start at 0
        cav3Vertexes[iCurrVert].X = lv3Vertexes[iSrcIndex].X;
        cav3Vertexes[iCurrVert].Y = lv3Vertexes[iSrcIndex].Y;
        cav3Vertexes[iCurrVert].Z = lv3Vertexes[iSrcIndex].Z;

        //Copy UV Coordinates
        iSrcIndex = Convert.ToInt32(astrFaceParts[1]) - 1;
        cav2UVCoords[iCurrVert].X = lv2UVCoords[iSrcIndex].X;
        cav2UVCoords[iCurrVert].Y = lv2UVCoords[iSrcIndex].Y;

        //Copy Normal values
        iSrcIndex = Convert.ToInt32(astrFaceParts[2]) - 1;
        cav3Normals[iCurrVert].X = lv3Normals[iSrcIndex].X;
        cav3Normals[iCurrVert].Y = lv3Normals[iSrcIndex].Y;
        cav3Normals[iCurrVert].Z = lv3Normals[iSrcIndex].Z;

        iCurrVert++;
       }
       break;
      default : //Ignore all other lines
       break;
     }
    }

    //Mark the arrays as needing updated
    cbVertexChange = true;
    cbNormalChange = true;
    cbUVCoordsChange = true;

    return true;
   }

   public bool LoadTexture(string strFile) {
    Bitmap bmpTexture;
    System.Drawing.Imaging.BitmapData oTextureData;
    Rectangle rctImageBounds;

    //Load the image from file
    bmpTexture = new Bitmap(strFile);

    //Convert the image to a form compatible with openGL
    rctImageBounds = new Rectangle(0, 0, bmpTexture.Width, bmpTexture.Height);

    oTextureData = bmpTexture.LockBits(rctImageBounds, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

    //Generate a new texture
    ciTextureID = GL.GenTexture();

    //Copy the image data into the texture
    GL.BindTexture(TextureTarget.Texture2D, ciTextureID);

    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmpTexture.Width, bmpTexture.Height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, oTextureData.Scan0);

    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear);

    bmpTexture.UnlockBits(oTextureData);

    return true;
   }

   public bool RenderObject() {
    cstrErrDesc = "";
    float[] afUniformData;

    //Be sure the buffer objects have been specified
    if ((ciUniformID == -1)||(ciUniformBuffer == -1)) {
     cstrErrDesc = "Unable to render with no Uniform Buffer or ID specified.";
     return false;
    }

    if ((ciVertexBuffer == -1)||(ciVertexID == -1)) {
     cstrErrDesc = "Unable to render with no Vertex Buffer or ID specified.";
     return false; 
    }

    //Check if buffer data needs refreshed
    if (cbVertexChange == true) {
     GL.BindBuffer(BufferTarget.ArrayBuffer, ciVertexBuffer);
     GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(cav3Vertexes.Length * Vector3.SizeInBytes), cav3Vertexes, BufferUsageHint.DynamicDraw);
     cbVertexChange = false;
    }

    if (cbUVCoordsChange == true) {
     GL.BindBuffer(BufferTarget.ArrayBuffer, ciUVCoordsBuffer);
     GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(cav2UVCoords.Length * Vector2.SizeInBytes), cav2UVCoords, BufferUsageHint.DynamicDraw);
     cbVertexChange = false;
    }

    if (cbNormalChange == true) {

     cbNormalChange = false;
    }

    if (cbUniformChange == true) {
     //Set Uniform buffer data
     afUniformData = new float[4];

     afUniformData[0] = cv4BaseColor.X;
     afUniformData[1] = cv4BaseColor.Y;
     afUniformData[2] = cv4BaseColor.Z;
     afUniformData[3] = cv4BaseColor.W;

     GL.BindBuffer(BufferTarget.UniformBuffer, ciUniformBuffer);
     GL.BufferData(BufferTarget.UniformBuffer, (IntPtr)(afUniformData.Length * sizeof(float)), afUniformData, BufferUsageHint.DynamicDraw);
    }

    //Draw the model
    if (ciTextureID != -1) {//A texture is loaded, use it
     GL.BindTexture(TextureTarget.Texture2D, ciTextureID);
    }

    GL.BindBuffer(BufferTarget.UniformBuffer, ciUniformBuffer);
    GL.BindBufferBase(BufferTarget.UniformBuffer, ciUniformID, ciUniformBuffer);

    GL.BindBuffer(BufferTarget.ArrayBuffer, ciVertexBuffer);
    GL.EnableVertexAttribArray(ciVertexID);
    GL.VertexAttribPointer(ciVertexID, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);

    GL.BindBuffer(BufferTarget.ArrayBuffer, ciUVCoordsBuffer);
    GL.EnableVertexAttribArray(ciUVCoordsID);
    GL.VertexAttribPointer(ciUVCoordsID, 2, VertexAttribPointerType.Float, false, Vector2.SizeInBytes, 0);

    GL.DrawArrays(BeginMode.Triangles, 0, cav3Vertexes.Length);
    GL.DisableVertexAttribArray(ciVertexID);
    GL.DisableVertexAttribArray(ciUVCoordsID);

    return true;
   }
  }
 }
}

Vertex Shader, GLSL Code:
#version 130
#extension GL_ARB_uniform_buffer_object : enable

uniform Data {
 mat4 m4Projection;
 vec4 v4BaseColor;
};

uniform ModelData {
 vec4 v4ModelColor;
};

attribute vec3 v3Location;
attribute vec2 v2UVCoord;

varying vec4 v4FragColor;
varying vec2 v2UV;

void main() {
 gl_Position = vec4(v3Location, 1.0) * m4Projection;

 v4FragColor = v4ModelColor;

 v2UV = v2UVCoord;
}

Fragment Shader, GLSL Code:
#version 130
#extension GL_ARB_uniform_buffer_object : enable

uniform Data {
 mat4 m4Projection;
 vec4 v4BaseColor;
};

uniform sampler2D sSampler;

uniform ModelData {
 vec4 v4ModelColor;
};

varying vec4 v4FragColor;
varying vec2 v2UV;

void main() {
 gl_FragColor = texture(sSampler, v2UV).rgba;;
}

No comments:

Post a Comment