CS116b/CS216
Chris Pollett
Feb 5, 2014
ifeq ($(OS), Darwin) # Assume OS X CPPFLAGS += -D__MAC__ -I/usr/local/Cellar/glew/1.10.0/include/ --stdlib=libstdc++ -Wno-deprecated LDFLAGS += -framework GLUT -framework OpenGL -L/usr/local/Cellar/glew/1.10.0/lib/ endifNotice I used brew to install the glew library and used the exact path to it above.
static const bool g_Gl2Compatible = true; //only need to do this on a Mac
uniform mat4 uProjMatrix; uniform mat4 uModelViewMatrix; uniform mat4 uNormalMatrix; attribute vec3 aPosition; attribute vec3 aNormal; attribute vec2 aTexCoord0; varying vec3 vNormal; varying vec3 vPosition; varying vec2 vTexCoord0; void main() { vNormal = vec3(uNormalMatrix * vec4(aNormal, 0.0)); // send position (eye coordinates) to fragment shader vec4 tPosition = uModelViewMatrix * vec4(aPosition, 1.0); vPosition = vec3(tPosition); vTexCoord0 = aTexCoord0; gl_Position = uProjMatrix * tPosition; }
#version 130 uniform mat4 uProjMatrix; uniform mat4 uModelViewMatrix; uniform mat4 uNormalMatrix; in vec3 aPosition; in vec3 aNormal; in vec2 aTexCoord0; out vec3 vNormal; out vec3 vPosition; out vec2 vTexCoord0; void main() { vNormal = vec3(uNormalMatrix * vec4(aNormal, 0.0)); // send position (eye coordinates) to fragment shader vec4 tPosition = uModelViewMatrix * vec4(aPosition, 1.0); vTexCoord0 = aTexCoord0; vPosition = vec3(tPosition); gl_Position = uProjMatrix * tPosition; }
uniform vec3 uLight; uniform sampler2D uTexUnit0; varying vec3 vNormal; varying vec3 vPosition; varying vec2 vTexCoord0; void main() { vec3 tolight = normalize(uLight - vPosition); vec3 normal = normalize(vNormal); vec4 texColor0 = texture2D(uTexUnit0, vTexCoord0); float diffuse = max(0.0, dot(normal, tolight)); gl_FragColor = texColor0 * diffuse; }
#version 130 uniform vec3 uLight; uniform sampler2D uTexUnit0; in vec3 vNormal; in vec3 vPosition; in vec2 vTexCoord0; out vec4 fragColor; void main() { vec3 tolight = normalize(uLight - vPosition); vec3 normal = normalize(vNormal); vec4 texColor0 = texture2D(uTexUnit0, vTexCoord0); float diffuse = max(0.0, dot(normal, tolight)); fragColor = texColor0 * diffuse; }
main() is the first thing that is executed by our program, in the original Hello World program it sets things up, and then call glutMainLoop(). This creates the window, does the initial drawing, and waits for keyboard and mouse events. I added the line initTextures() below.
int main(int argc, char * argv[]) { try { initGlutState(argc,argv); glewInit(); // load the OpenGL extensions cout << (g_Gl2Compatible ? "Will use OpenGL 2.x / GLSL 1.0" : "Will use OpenGL 3.x / GLSL 1.3") << endl; if ((!g_Gl2Compatible) && !GLEW_VERSION_3_0) throw runtime_error( "Error: card/driver does not support OpenGL Shading Language v1.3"); else if (g_Gl2Compatible && !GLEW_VERSION_2_0) throw runtime_error( "Error: card/driver does not support OpenGL Shading Language v1.0"); initGLState(); initShaders(); initGeometry(); initTextures(); // added to Hello World 3D glutMainLoop(); return 0; } catch (const runtime_error& e) { cout << "Exception caught: " << e.what() << endl; return -1; } }
Below is the code for initTextures which loads and initializes the textures. I also modified the original initGeometry so that the scene now only has a cube and no ground (this allowed me to simplify my shaders earlier/not have to have another pair of shaders for the ground).
static void initGeometry() { initCubes(); } static void loadTexture(GLuint texHandle, const char *ppmFilename) { int texWidth, texHeight; vector<PackedPixel> pixData; ppmRead(ppmFilename, texWidth, texHeight, pixData); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texHandle); glTexImage2D(GL_TEXTURE_2D, 0, g_Gl2Compatible ? GL_RGB : GL_SRGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixData[0]); checkGlErrors(); } static void initTextures() { g_tex0.reset(new GlTexture()); loadTexture(*g_tex0, "myphoto.ppm"); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, *g_tex0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); }
This is done in initShader and makes use of a ShaderState struct. I modified this as below to now have textures.
struct ShaderState { GlProgram program; // Handles to uniform variables GLint h_uLight; GLint h_uProjMatrix; GLint h_uModelViewMatrix; GLint h_uNormalMatrix; GLint h_uTexUnit0; // Handles to vertex attributes GLint h_aPosition; GLint h_aNormal; GLint h_aTexCoord0; ShaderState(const char* vsfn, const char* fsfn) { readAndCompileShader(program, vsfn, fsfn); const GLuint h = program; // short hand // Retrieve handles to uniform variables h_uLight = safe_glGetUniformLocation(h, "uLight"); h_uProjMatrix = safe_glGetUniformLocation(h, "uProjMatrix"); h_uModelViewMatrix = safe_glGetUniformLocation(h, "uModelViewMatrix"); h_uNormalMatrix = safe_glGetUniformLocation(h, "uNormalMatrix"); h_uTexUnit0 = safe_glGetUniformLocation(h, "uTexUnit0"); // Retrieve handles to vertex attributes h_aPosition = safe_glGetAttribLocation(h, "aPosition"); h_aNormal = safe_glGetAttribLocation(h, "aNormal"); h_aTexCoord0 = safe_glGetAttribLocation(h, "aTexCoord0"); if (!g_Gl2Compatible) glBindFragDataLocation(h, 0, "fragColor"); checkGlErrors(); } };
static const int g_numShaders = 1; static const char * const g_shaderFiles[g_numShaders][2] = { {"./shaders/basic-gl3.vshader", "./shaders/texture-gl3.fshader"} }; static const char * const g_shaderFilesGl2[g_numShaders][2] = { {"./shaders/basic-gl2.vshader", "./shaders/texture-gl2.fshader"} }; static vector<shared_ptr<ShaderState> > g_shaderStates; // our global shader states static shared_ptr<GlTexture> g_tex0; // --------- Geometry // Macro used to obtain relative offset of a field within a struct #define FIELD_OFFSET(StructType, field) &(((StructType *)0)->field) struct Geometry { GlBufferObject vbo, texVbo, ibo; int vboLen, iboLen; Geometry(GenericVertex *vtx, unsigned short *idx, int vboLen, int iboLen) { this->vboLen = vboLen; this->iboLen = iboLen; // Now create the VBO and IBO glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(GenericVertex) * vboLen, vtx, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * iboLen, idx, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, texVbo); glBufferData(GL_ARRAY_BUFFER, sizeof(GenericVertex) * vboLen, vtx, GL_STATIC_DRAW); } void draw(const ShaderState& curSS) { // Enable the attributes used by our shader safe_glEnableVertexAttribArray(curSS.h_aPosition); safe_glEnableVertexAttribArray(curSS.h_aNormal); safe_glEnableVertexAttribArray(curSS.h_aTexCoord0); // bind vbo glBindBuffer(GL_ARRAY_BUFFER, vbo); safe_glVertexAttribPointer(curSS.h_aPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GenericVertex), FIELD_OFFSET(GenericVertex, pos)); safe_glVertexAttribPointer(curSS.h_aNormal, 3, GL_FLOAT, GL_FALSE, sizeof(GenericVertex), FIELD_OFFSET(GenericVertex, normal)); glBindBuffer(GL_ARRAY_BUFFER, texVbo); safe_glVertexAttribPointer(curSS.h_aTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GenericVertex), FIELD_OFFSET(GenericVertex, tex)); // bind ibo glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); // draw! glDrawElements(GL_TRIANGLES, iboLen, GL_UNSIGNED_SHORT, 0); // Disable the attributes used by our shader safe_glDisableVertexAttribArray(curSS.h_aPosition); safe_glDisableVertexAttribArray(curSS.h_aNormal); safe_glDisableVertexAttribArray(curSS.h_aTexCoord0); } }; // Vertex buffer and index buffer associated with the ground and cube geometry static shared_ptr<Geometry> g_cube; // --------- Scene static const Cvec3 g_light1(2.0, 3.0, 14.0); // define light positions in world space
The original GenericVertex did not have a copy constructor and assignment operator wasn't defined. So it could not be used in a vector. I added these. This was the last change I made.
struct GenericVertex { Cvec3f pos; Cvec3f normal; Cvec2f tex; Cvec3f tangent, binormal; GenericVertex() {} GenericVertex( float x, float y, float z, float nx, float ny, float nz, float tu, float tv, float tx, float ty, float tz, float bx, float by, float bz) : pos(x,y,z), normal(nx,ny,nz), tex(tu, tv), tangent(tx, ty, tz), binormal(bx, by, bz) {} GenericVertex(const GenericVertex& v) { *this = v; } GenericVertex& operator = (const GenericVertex& v) { pos = v.pos; normal = v.normal; tex = v.tex; tangent = v.tangent; binormal = v.binormal; return *this; } };