Skip to content

Instantly share code, notes, and snippets.

@dlivingstone
Created October 19, 2010 00:22
Show Gist options
  • Save dlivingstone/633350 to your computer and use it in GitHub Desktop.
Save dlivingstone/633350 to your computer and use it in GitHub Desktop.
A loaddata program for OpenGL that will load and render a model stored in a particular matching format. Example model data and fragment shader available here: http://gist.github.com/629763 . This gist includes the main cpp file and the vertex shader only.
// Vertex Shader – default light
// This is based (very closely!) on code extracted from the GLShaderManager provided
// by Richard Wright for the OpenGL SuperBible, 5th Edition
// The SuperBible source code is available http://www.starstonesoftware.com/OpenGL/
///* GLShaderManager.h
//
//Copyright (c) 2009, Richard S. Wright Jr.
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification,
//are permitted provided that the following conditions are met:
//
//Redistributions of source code must retain the above copyright notice, this list
//of conditions and the following disclaimer.
//
//Redistributions in binary form must reproduce the above copyright notice, this list
//of conditions and the following disclaimer in the documentation and/or other
//materials provided with the distribution.
//
//Neither the name of Richard S. Wright Jr. nor the names of other contributors may be used
//to endorse or promote products derived from this software without specific prior
//written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
//BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//*/
#version 130
uniform mat4 mvMatrix;
uniform mat4 pMatrix;
in vec3 in_Position;
in vec3 in_Normal;
in vec3 in_Color;
out vec3 ex_Color;
void main(void) {
mat3 mNormalMatrix;
mNormalMatrix[0] = mvMatrix[0].xyz;
mNormalMatrix[1] = mvMatrix[1].xyz;
mNormalMatrix[2] = mvMatrix[2].xyz;
vec3 vNorm = normalize(mNormalMatrix * in_Normal);
vec3 vLightDir = vec3(0.0, 0.0, 1.0);
float fDot = max(0.0, dot(vNorm, vLightDir));
ex_Color.rgb = in_Color.rgb * fDot;
mat4 mvpMatrix;
mvpMatrix = pMatrix * mvMatrix;
gl_Position = mvpMatrix * vec4(in_Position,1.0);
}
// loaddata
// A simple app that loads model data from a custom data format
// the format is a (relatively) simple one based on how an individual
// mesh may be saved in a Collada file - currently the easiest way
// to make models, is with Google Sketchup, export to Collada, then
// manually hack the data and save.
// Daniel Livingstone, Oct 2010
//
// On Windows, the following define can remove some compiler problems,
// but remove the line if compiling for other platforms!
// #ifdef WIN32 doesn't seem to always work under VS2010 otherwise
#define WIN32
#include <GLTools.h> // OpenGL toolkit
// If you have math3d, glew & freeglut installed - but not GLTools, use the following
// two lines instead of the two above
//#include <math3d.h>
//#include <GL/glew.h>
#include <iostream>
#include <fstream>
#include <sstream>
#define FREEGLUT_STATIC
#include <GL/glut.h>
using namespace std;
// * Global Variables *
GLuint vertexArrayObjID[1]; // Just the one vertex array object
GLuint vertexBufferObjID[3];// 3 vertex buffer objects in this example
GLuint numVerts; // How many vertices in array?
GLfloat angle = 0.0f; // going to animate the object
GLuint program; // Global handle for shader program
// Functions
// loadFile - loads text file into char* fname (for loading shader programs)
// allocates memory - so will need to delete after use, size of file returned in fSize
char* loadFile(char *fname, GLint &fSize)
{
ifstream::pos_type size;
char * memblock;
string text;
ifstream file (fname, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
fSize = (GLuint) size;
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "file " << fname << " loaded" << endl;
text.assign(memblock);
}
else
{
cout << "Unable to open file " << fname << endl;
exit(1);
}
return memblock;
}
// printShaderInfoLog
// From OpenGL Shading Language 3rd Edition, p215-216
// Display (hopefully) useful error messages if shader fails to compile
void printShaderInfoLog(GLint shader)
{
int infoLogLen = 0;
int charsWritten = 0;
GLchar *infoLog;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
// should additionally check for OpenGL errors here
if (infoLogLen > 0)
{
infoLog = new GLchar[infoLogLen];
// error check for fail to allocate memory omitted
glGetShaderInfoLog(shader,infoLogLen, &charsWritten, infoLog);
cout << "InfoLog:" << endl << infoLog << endl;
delete [] infoLog;
}
// should additionally check for OpenGL errors here
}
GLuint initShaders(void)
{
GLuint p, f, v;
char *vs,*fs;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
// load shaders & get length of each
GLint vlen;
GLint flen;
vs = loadFile("default_light.vert",vlen);
fs = loadFile("minimal.frag",flen);
const char * vv = vs;
const char * ff = fs;
glShaderSource(v, 1, &vv,&vlen);
glShaderSource(f, 1, &ff,&flen);
GLint compiled;
glCompileShader(v);
glGetShaderiv(v, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
cout << "Vertex shader not compiled." << endl;
printShaderInfoLog(v);
}
glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
cout << "Fragment shader not compiled." << endl;
printShaderInfoLog(f);
}
p = glCreateProgram();
glAttachShader(p,v);
glAttachShader(p,f);
glBindAttribLocation(p,0, "in_Position");
glBindAttribLocation(p,1, "in_Normal");
glBindAttribLocation(p,2, "in_Color");
glLinkProgram(p);
GLint params[1];
glGetProgramiv(p,GL_LINK_STATUS,params);
if (params[0] == GL_FALSE)
{
cout << "Shader programs not linked" << endl;
printShaderInfoLog(f);
}
glUseProgram(p);
delete [] vs; // dont forget to free allocated memory
delete [] fs; // we allocated this in the loadFile function...
return p;
}
// loadData function
// this function *assumes* that the data matches the particular
// format expected, and will blow-up if it does not
void loadData(char* fname)
{
ifstream::pos_type size;
char * memblock;
ifstream file (fname, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "file " << fname << " loaded" << endl;
}
else
{ // Would be desireable to load dummy data or something else instead
// to prevent program from simply closing or blowing up
cout << "Unable to open file " << fname << endl;
exit(1);
}
stringstream strstream(memblock); // Copy file into a stringstream
string magicnumber; // Basic check: is this a uwsm file?
strstream >> magicnumber;
if (magicnumber.compare(0,4,"uwsm")!=0)
{ // could also use the version number, but not doing that just now
cerr << "File " << fname << " is not a uwsm file." << endl;
exit (1);
}
// Allocate Vertex Array Object(s)
glGenVertexArrays(1, &vertexArrayObjID[0]);
// Setup first Vertex Array Object
glBindVertexArray(vertexArrayObjID[0]);
glGenBuffers(3, vertexBufferObjID);
// Read geometry
int i, count; //count is number of floats, ie verts x 3
strstream >> count;
M3DVector3f *vertices = new M3DVector3f[count/3];
for (i=0;i<count/3;i++)
strstream >> vertices[i][0] >> vertices[i][1] >> vertices[i][2];
// VBO for vertex data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[0]);
glBufferData(GL_ARRAY_BUFFER, count*3*sizeof(GLfloat),
vertices, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// Read normals
strstream >> count; // how many normals? need not be same as vertices
M3DVector3f *normals = new M3DVector3f[count/3];
if (count > 0) // model has normals
for (i=0;i<count/3;i++)
strstream >> normals[i][0] >> normals[i][1] >> normals[i][2];
// VBO for normal data
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[1]);
glBufferData(GL_ARRAY_BUFFER, count*3*sizeof(GLfloat),
normals, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
// Read texture coordinates
strstream >> count; // how many texture coords? need not be same as vertices
GLfloat nul;
if (count > 0) // model has texture coordinates
for (i=0;i<count;i++)
strstream >> nul; // not using these just now!
// Finished setting up the vertex array
glBindVertexArray(0);
// Now to fill the index array - another buffer object
int triangles;
strstream >> triangles; // how many *triangles* in mesh?
numVerts = triangles * 3;
GLuint *meshIndices = new GLuint[numVerts];
for (i=0;i<numVerts;i++)
strstream >> meshIndices[i];
// Note, the next buffer object is of type ELEMENT_ARRAY_BUFFER
// This is for storing the indices for drawing the geometry
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBufferObjID[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numVerts*sizeof(GLuint),
meshIndices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
delete [] memblock;
delete [] vertices;
delete [] normals;
delete [] meshIndices;
}
void reshape(GLint w, GLint h)
{
glViewport(0, 0, w, h);
}
void display(void)
{
// clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
M3DMatrix44f projection;
m3dLoadIdentity44(projection);
M3DMatrix44f modelview;
m3dLoadIdentity44(modelview);
M3DMatrix44f temp;
// set up the projection matrix
m3dMakePerspectiveMatrix(projection, m3dDegToRad(60), 1.0f, 0.5f, 100.0f);
// create a translation matrix
M3DMatrix44f translation;
m3dTranslationMatrix44(translation,0.0f,0.0f,-10.0f);
m3dCopyMatrix44(temp, modelview);
m3dMatrixMultiply44(modelview, temp, translation);
// create a rotation matrix
M3DMatrix44f rotation;
m3dRotationMatrix44(rotation, m3dDegToRad(-45), 1.0f, 0.0f, 0.0f);
m3dCopyMatrix44(temp, modelview);
m3dMatrixMultiply44(modelview, temp, rotation);
m3dRotationMatrix44(rotation, angle, 0.0f, 0.0f, 1.0f);
m3dCopyMatrix44(temp, modelview);
m3dMatrixMultiply44(modelview, temp, rotation);
angle += 0.01;
// create a scale matrix
M3DMatrix44f scale;
m3dScaleMatrix44(scale, 0.1f, 0.1f, 0.1f);
m3dCopyMatrix44(temp, modelview);
m3dMatrixMultiply44(modelview, temp, scale);
// Set up the uniform inputs
glUniformMatrix4fv(glGetUniformLocation(program,"mvMatrix"),
1,GL_FALSE,modelview);
glUniformMatrix4fv(glGetUniformLocation(program,"pMatrix"),
1,GL_FALSE,projection);
glBindVertexArray(vertexArrayObjID[0]); // First VAO
glEnableVertexAttribArray(0); // enable position attribue array
glEnableVertexAttribArray(1); // enable normal attribute array
glVertexAttrib3f((GLuint)2, 1.0, 0.0, 0.0); // set constant color attribute
// using index list, so use DrawElements instead of Draw Array
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBufferObjID[2]);
glDrawElements(GL_TRIANGLES, numVerts, GL_UNSIGNED_INT, 0);
//If indices were *not* in a buffer, but in an array, the following would
//be used instead of the above two lines:
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// glDrawElements(GL_TRIANGLES, numVerts, GL_UNSIGNED_INT, meshIndices);
glBindVertexArray(0);
glutPostRedisplay();
glutSwapBuffers();
}
void init(void)
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f ); // white background
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
loadData("blocks.uwsm");
}
// Main function - program entry point
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("simple3Dapp");
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
cerr << "Error: " << glewGetErrorString(err) << endl;
return 1;
}
glutReshapeFunc(reshape);
glutDisplayFunc(display);
init();
program = initShaders();
glutPostRedisplay(); // draw the scene once
glutMainLoop();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment