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, cbMoveLeft, cbMoveUp;
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() {
//Create redraw timer
Timer tmrRedraw;
tmrRedraw = new Timer();
tmrRedraw.Interval = 20; //20 ms timer
tmrRedraw.Tick += new EventHandler(RedrawTimer);
tmrRedraw.Start();
//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;
//Initiailize variables
cbMoveLeft = false;
cbMoveUp = true;
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");
cModel.TranslateZ = -10;
//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;
}
//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;
}
private void RedrawTimer(object oSender, EventArgs eaArgs) {
if (cbMoveLeft == true) {
cModel.TranslateX -= 0.05f;
if (cModel.TranslateX < -3) {
cbMoveLeft = false;
}
} else {
cModel.TranslateX += 0.05f;
if (cModel.TranslateX > 3) {
cbMoveLeft = true;
}
}
if (cbMoveUp == false) {
cModel.TranslateY -= 0.05f;
if (cModel.TranslateY < -2.5) {
cbMoveUp = true;
}
} else {
cModel.TranslateY += 0.05f;
if (cModel.TranslateY > 2.5) {
cbMoveUp = false;
}
}
cModel.RotateX += 1.0f;
if (cModel.RotateX >= 360) {
cModel.RotateX = 0.0f;
}
cModel.RotateY += 0.5f;
if (cModel.RotateY >= 360) {
cModel.RotateY = 0.0f;
}
cModel.RotateZ += 1.5f;
if (cModel.RotateZ >= 360) {
cModel.RotateZ = 0.0f;
}
cModel.ScaleX = (cModel.TranslateY + 3.5f) / 4.0f;
cModel.ScaleY = (cModel.TranslateY + 3.5f) / 4.0f;
cModel.ScaleZ = (cModel.TranslateY + 3.5f) / 4.0f;
GLViewPainting(null, null);
}
}
}
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.3")]
[assembly: AssemblyFileVersion("0.1.0.3")]
namespace MDLN {
namespace GLTools {
public static class GLUtil{
public static bool PackDataIntoUniformBuffer(ref float[] afBuffer, ref int iBaseIndex, Matrix4 m4Data) {
afBuffer[iBaseIndex + 0] = m4Data.Row0.X;
afBuffer[iBaseIndex + 1] = m4Data.Row1.X;
afBuffer[iBaseIndex + 2] = m4Data.Row2.X;
afBuffer[iBaseIndex + 3] = m4Data.Row3.X;
afBuffer[iBaseIndex + 4] = m4Data.Row0.Y;
afBuffer[iBaseIndex + 5] = m4Data.Row1.Y;
afBuffer[iBaseIndex + 6] = m4Data.Row2.Y;
afBuffer[iBaseIndex + 7] = m4Data.Row3.Y;
afBuffer[iBaseIndex + 8] = m4Data.Row0.Z;
afBuffer[iBaseIndex + 9] = m4Data.Row1.Z;
afBuffer[iBaseIndex + 10] = m4Data.Row2.Z;
afBuffer[iBaseIndex + 11] = m4Data.Row3.Z;
afBuffer[iBaseIndex + 12] = m4Data.Row0.W;
afBuffer[iBaseIndex + 13] = m4Data.Row1.W;
afBuffer[iBaseIndex + 14] = m4Data.Row2.W;
afBuffer[iBaseIndex + 15] = m4Data.Row3.W;
iBaseIndex += 16;
return true;
}
public static bool PackDataIntoUniformBuffer(ref float[] afBuffer, ref int iBaseIndex, Vector3 v3Data) {
afBuffer[iBaseIndex + 0] = v3Data.X;
afBuffer[iBaseIndex + 1] = v3Data.Y;
afBuffer[iBaseIndex + 2] = v3Data.Z;
afBuffer[iBaseIndex + 3] = 0.0f;
iBaseIndex += 4;
return true;
}
}
public class GLShader {
public enum ErrorCodes {None, CompileFail, LinkFail, InvalidAttrName};
private int ciProgram;
private ErrorCodes ceErrCode;
private string cstrErrDesc, cstrVertexFile, cstrFragmentFile, cstrName;
private List<ShaderVar> clUniformList, clAttribList;
public GLShader() {
//Initilize class variables
ciProgram = -1;
ceErrCode = ErrorCodes.None;
cstrErrDesc = "";
clUniformList = new List<ShaderVar>();
clAttribList = new List<ShaderVar>();
}
public string VertexFile {
get {
return cstrVertexFile;
}
set {
cstrVertexFile = value;
return;
}
}
public string FragmentFile {
get {
return cstrFragmentFile;
}
set {
cstrFragmentFile = value;
return;
}
}
public string Name {
get {
return cstrName;
}
set {
cstrName = value;
return;
}
}
public int Program {
get {
if (ciProgram == -1) {
BuildShader();
}
return ciProgram;
}
}
public string ErrorDescription {
get {
return cstrErrDesc;
}
}
public ErrorCodes ErrorCode {
get {
return ceErrCode;
}
}
public bool AddUniform(string strName, int iID) {
ShaderVar oNewVar;
oNewVar = new ShaderVar(iID, strName);
clUniformList.Add(oNewVar);
return true;
}
public bool AddAttribute(string strName, int iID) {
ShaderVar oNewVar;
oNewVar = new ShaderVar(iID, strName);
clAttribList.Add(oNewVar);
return true;
}
public int FindUniformID(string strName) {
foreach (ShaderVar oUniform in clUniformList) {
if (oUniform.VariableName == strName) {
return oUniform.VariableID;
}
}
return -1;
}
public int FindAttributeID(string strName) {
ceErrCode = ErrorCodes.None;
cstrErrDesc = "";
foreach (ShaderVar oAttr in clAttribList) {
if (oAttr.VariableName == strName) {
return oAttr.VariableID;
}
}
ceErrCode = ErrorCodes.InvalidAttrName;
cstrErrDesc = "Unable to find an attribute with the name " + strName;
return -1;
}
public bool BuildShader() {
int iUniformID, iStatus, iVertShader, iFragShader, iNewProgram;
bool bRetVal = true;
cstrErrDesc = "";
ceErrCode = ErrorCodes.None;
//Create Vertex shader
iVertShader = GL.CreateShader(ShaderType.VertexShader);
using (StreamReader srShader = new StreamReader(cstrVertexFile)) {
GL.ShaderSource(iVertShader, srShader.ReadToEnd());
}
GL.CompileShader(iVertShader);
GL.GetShader(iVertShader, ShaderParameter.CompileStatus, out iStatus);
if (iStatus != 1) { //Failed to compile
bRetVal = false;
ceErrCode = ErrorCodes.CompileFail;
cstrErrDesc = "Vertex Shader failed to compile.\n" + GL.GetShaderInfoLog(iVertShader) + "\n";
}
//Create Fragment shader
iFragShader = GL.CreateShader(ShaderType.FragmentShader);
using (StreamReader srShader = new StreamReader(cstrFragmentFile)) {
GL.ShaderSource(iFragShader, srShader.ReadToEnd());
}
GL.CompileShader(iFragShader);
GL.GetShader(iFragShader, ShaderParameter.CompileStatus, out iStatus);
if (iStatus != 1) { //Failed to compile
bRetVal = false;
ceErrCode = ErrorCodes.CompileFail;
cstrErrDesc = cstrErrDesc + "Fragment Shader failed to compile.\n" + GL.GetShaderInfoLog(iFragShader);
}
if (bRetVal != true) { //If a compile error happens, stop
return bRetVal;
}
//Build the program
iNewProgram = GL.CreateProgram();
GL.AttachShader(iNewProgram, iVertShader);
GL.AttachShader(iNewProgram, iFragShader);
//Assign attribute buffers]
foreach (ShaderVar oAttr in clAttribList) {
GL.BindAttribLocation(iNewProgram, oAttr.VariableID, oAttr.VariableName);
}
//Link the program
GL.LinkProgram(iNewProgram);
GL.GetProgram(iNewProgram, ProgramParameter.LinkStatus, out iStatus);
if (iStatus != 1) { //Failed to link
bRetVal = false;
ceErrCode = ErrorCodes.LinkFail;
cstrErrDesc = "Shading program failed to link.\n" + GL.GetProgramInfoLog(iNewProgram);
}
if (bRetVal != true) { //If a link error happens, stop
return bRetVal;
}
//Define uniform blocks
foreach (ShaderVar oUniform in clUniformList) {
iUniformID = GL.GetUniformBlockIndex(iNewProgram, oUniform.VariableName);
GL.UniformBlockBinding(iNewProgram, iUniformID, oUniform.VariableID);
}
ciProgram = iNewProgram;
//Cleanup
GL.DeleteShader(iVertShader);
GL.DeleteShader(iFragShader);
return true;
}
private class ShaderVar {
private int ciVarID;
private string cstrVarName;
public ShaderVar() : this(0, "") {} //Chained constructor
public ShaderVar(int iID, string strName) {
ciVarID = iID;
cstrVarName = strName;
}
public string VariableName {
get {
return cstrVarName;
}
set {
cstrVarName = value;
}
}
public int VariableID {
get {
return ciVarID;
}
set {
ciVarID = value;
}
}
}
}
public class GLModel {
private Vector3[] cav3Vertexes, cav3Normals, cav3Transforms;
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;
cav3Transforms = new Vector3[3]; //0 = scale, 1 = rotation, 2 = translate
cav3Transforms[0].X = 1.0f;
cav3Transforms[0].Y = 1.0f;
cav3Transforms[0].Z = 1.0f;
cav3Transforms[1].X = 0.0f;
cav3Transforms[1].Y = 0.0f;
cav3Transforms[1].Z = 0.0f;
cav3Transforms[2].X = 0.0f;
cav3Transforms[2].Y = 0.0f;
cav3Transforms[2].Z = 0.0f;
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 float TranslateX {
get {
return cav3Transforms[2].X;
}
set {
cbNormalChange = true;
cav3Transforms[2].X = value;
}
}
public float TranslateY {
get {
return cav3Transforms[2].Y;
}
set {
cbNormalChange = true;
cav3Transforms[2].Y = value;
}
}
public float TranslateZ {
get {
return cav3Transforms[2].Z;
}
set {
cbNormalChange = true;
cav3Transforms[2].Z = value;
}
}
public float ScaleX {
get {
return cav3Transforms[0].X;
}
set {
cbNormalChange = true;
cav3Transforms[0].X = value;
}
}
public float ScaleY {
get {
return cav3Transforms[0].Y;
}
set {
cbNormalChange = true;
cav3Transforms[0].Y = value;
}
}
public float ScaleZ {
get {
return cav3Transforms[0].Z;
}
set {
cbNormalChange = true;
cav3Transforms[0].Z = value;
}
}
public float RotateX {
get {
return cav3Transforms[1].X * (180 / MathHelper.Pi);
}
set {
cbNormalChange = true;
cav3Transforms[1].X = value * (MathHelper.Pi / 180);
}
}
public float RotateY {
get {
return cav3Transforms[1].Y * (180 / MathHelper.Pi);
}
set {
cbNormalChange = true;
cav3Transforms[1].Y = value * (MathHelper.Pi / 180);
}
}
public float RotateZ {
get {
return cav3Transforms[1].Z * (180 / MathHelper.Pi);
}
set {
cbNormalChange = true;
cav3Transforms[1].Z = value * (MathHelper.Pi / 180);
}
}
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<Vector3> lv3Vertexes, lv3Normals;
List<Vector2> lv2UVCoords;
Vector3 v3New;
Vector2 v2New;
StreamReader srModel;
cstrErrDesc = "";
iFaceCount = 0;
lv3Vertexes = new List<Vector3>();
lv3Normals = new List<Vector3>();
v3New = new Vector3();
lv2UVCoords = new List<Vector2>();
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() {
float[] afUniformData;
int iIndex;
cstrErrDesc = "";
//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 * 4];
afUniformData[0] = cv4BaseColor.X;
afUniformData[1] = cv4BaseColor.Y;
afUniformData[2] = cv4BaseColor.Z;
afUniformData[3] = cv4BaseColor.W;
iIndex = 4;
GLUtil.PackDataIntoUniformBuffer(ref afUniformData, ref iIndex, cav3Transforms[0]);
GLUtil.PackDataIntoUniformBuffer(ref afUniformData, ref iIndex, cav3Transforms[1]);
GLUtil.PackDataIntoUniformBuffer(ref afUniformData, ref iIndex, cav3Transforms[2]);
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;
vec4 v3ModelScale;
vec4 v3ModelRotate;
vec4 v3ModelTranslate;
};
attribute vec3 v3Location;
attribute vec2 v2UVCoord;
varying vec4 v4FragColor;
varying vec2 v2UV;
void main() {
mat4 m4Scale, m4Translate, m4RotateX, m4RotateY, m4RotateZ;
m4Translate = mat4(1.0);
m4Translate[0][3] = v3ModelTranslate.x;
m4Translate[1][3] = v3ModelTranslate.y;
m4Translate[2][3] = v3ModelTranslate.z;
m4Scale = mat4(1.0);
m4Scale[0][0] = v3ModelScale.x;
m4Scale[1][1] = v3ModelScale.y;
m4Scale[2][2] = v3ModelScale.z;
m4RotateX = mat4(1.0);
m4RotateX[1][1] = cos(v3ModelRotate.x);
m4RotateX[1][2] = -1 * sin(v3ModelRotate.x);
m4RotateX[2][1] = sin(v3ModelRotate.x);
m4RotateX[2][2] = cos(v3ModelRotate.x);
m4RotateY = mat4(1.0);
m4RotateY[0][0] = cos(v3ModelRotate.y);
m4RotateY[0][2] = sin(v3ModelRotate.y);
m4RotateY[2][0] = -1 * sin(v3ModelRotate.y);
m4RotateY[2][2] = cos(v3ModelRotate.y);
m4RotateZ = mat4(1.0);
m4RotateZ[0][0] = cos(v3ModelRotate.z);
m4RotateZ[0][1] = -1 * sin(v3ModelRotate.z);
m4RotateZ[1][0] = sin(v3ModelRotate.z);
m4RotateZ[1][1] = cos(v3ModelRotate.z);
gl_Position = vec4(v3Location, 1.0) * m4Scale * m4RotateX * m4RotateY * m4RotateZ * m4Translate * 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;
vec4 v3ModelScale;
vec4 v3ModelRotate;
vec4 v3ModelTranslate;
};
varying vec4 v4FragColor;
varying vec2 v2UV;
void main() {
gl_FragColor = texture(sSampler, v2UV).rgba;
}
Model Data, OBJ File:
# Blender v2.69 (sub 0) OBJ File: ''
# www.blender.org
mtllib Cube.mtl
o Cube_Cube.001
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
#1 face
vt 0.000000 0.000000
vt 0.000000 0.222656
vt 0.222656 0.000000
vt 0.222656 0.222656
#2 face
vt 0.225900 0.000000
vt 0.225900 0.222656
vt 0.444900 0.000000
vt 0.444900 0.222656
#3 face
vt 0.449900 0.000000
vt 0.449900 0.222656
vt 0.669400 0.000000
vt 0.669400 0.222656
#4 face
vt 0.674400 0.000000
vt 0.674400 0.222656
vt 0.893500 0.000000
vt 0.893500 0.222656
#5 face
vt 0.000000 0.225900
vt 0.000000 0.444900
vt 0.222656 0.225900
vt 0.222656 0.444900
#6 face
vt 0.225900 0.225900
vt 0.225900 0.444900
vt 0.444900 0.225900
vt 0.444900 0.444900
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000001 0.000000 1.000000
vn 1.000000 -0.000000 0.000000
vn 1.000000 0.000000 0.000001
vn 0.000000 1.000000 -0.000000
vn -0.000000 -1.000000 0.000000
usemtl None
s off
#left/1 face
f 3/4/2 7/3/2 8/1/2
f 3/4/2 8/1/2 4/2/2
#bottom/2 face
f 1/8/8 2/7/8 3/5/8
f 1/8/8 3/5/8 4/6/8
#back/3 face
f 5/9/1 1/10/1 4/12/1
f 5/9/1 4/12/1 8/11/1
#right/4 face
f 1/16/5 5/15/5 2/14/5
f 5/15/6 6/13/6 2/14/6
#top/5 face
f 5/19/7 8/17/7 6/20/7
f 8/17/7 7/18/7 6/20/7
#front/6 face
f 2/24/3 6/23/3 3/22/3
f 6/23/4 7/21/4 3/22/4
No comments:
Post a Comment