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