diff --git a/f_shader.glsl b/f_shader.glsl new file mode 100644 index 0000000..e1fdafb --- /dev/null +++ b/f_shader.glsl @@ -0,0 +1,31 @@ + +varying vec3 eye_pos_i; +varying vec3 normal_i; +varying vec4 diffuse_i; + +void main(void) +{ + vec3 n, lightDir; + vec4 color; + float NdotL, RdotEye; + + lightDir = vec3(-0.1, 0, -0.9); + color = vec4(0.2, 0.2, 0.2, 1.0); /* ambient light */ + n = normalize(normal_i); + + NdotL = max(dot(n, -lightDir), 0.0); + + if (NdotL > 0.0) + { + /* diffuse component */ + color += diffuse_i * NdotL; + /* specular component */ + RdotEye = dot(normalize(eye_pos_i), normalize(reflect(-lightDir, n))); + if (RdotEye > 0.0) + { + color += pow(RdotEye, 96.5); + } + } + + gl_FragColor = color; +} diff --git a/v_shader.glsl b/v_shader.glsl new file mode 100644 index 0000000..4881a17 --- /dev/null +++ b/v_shader.glsl @@ -0,0 +1,16 @@ + +attribute vec3 pos; +attribute vec3 color; +attribute vec3 normal; + +varying vec3 eye_pos_i; +varying vec3 normal_i; +varying vec4 diffuse_i; + +void main(void) +{ + gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1); + eye_pos_i = vec3(gl_Position.x, gl_Position.y, gl_Position.z); + normal_i = gl_NormalMatrix * normal; + diffuse_i = vec4(color, 1); +} diff --git a/wfobj-view.cc b/wfobj-view.cc index ace16ec..59df81e 100644 --- a/wfobj-view.cc +++ b/wfobj-view.cc @@ -1,5 +1,9 @@ /* Libraries we use */ +#define GL_GLEXT_PROTOTYPES +#include +#include +#include #include #include #include @@ -12,6 +16,11 @@ using namespace std; #define HEIGHT 800 #define TITLE "Josh's Wavefront Object Viewer" +enum Locations { + LOC_POSITION, + LOC_NORMAL +}; + class Viewer { public: @@ -30,8 +39,93 @@ private: int m_startx, m_starty; bool m_dragging; float m_dist; + GLuint m_program, m_vs, m_fs; }; +char * loadFile(const char *fname) +{ + struct stat st; + if (stat(fname, &st) != 0) + return NULL; + if (st.st_size <= 0) + return NULL; + char * buff = new char[st.st_size + 1]; + int fd = open(fname, O_RDONLY); + read(fd, buff, st.st_size); + close(fd); + buff[st.st_size] = '\0'; + return buff; +} + +char *getShaderLog(GLuint id) +{ + GLint log_length; + glGetShaderiv(id, GL_INFO_LOG_LENGTH, &log_length); + if (log_length > 0) + { + char *log = new char[log_length]; + glGetShaderInfoLog(id, log_length, &log_length, log); + return log; + } + return NULL; +} + +char *getProgramLog(GLuint id) +{ + GLint log_length; + glGetProgramiv(id, GL_INFO_LOG_LENGTH, &log_length); + if (log_length > 0) + { + char *log = new char[log_length]; + glGetProgramInfoLog(id, log_length, &log_length, log); + return log; + } + return NULL; +} + +GLuint makeShader(GLenum shaderType, const char *fname) +{ + GLuint id; + const char *source; + GLint status; + + id = glCreateShader(shaderType); + if (id <= 0) + { + cerr << "Error creating shader object" << endl; + goto out; + } + + source = loadFile(fname); + if (source == NULL) + { + fprintf(stderr, "Error reading file '%s'\n", fname); + goto cleanup_shader; + } + + glShaderSource(id, 1, &source, NULL); + delete[] source; + + glCompileShader(id); + + glGetShaderiv(id, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) + { + cerr << "Error compiling shader" << endl; + char *log = getShaderLog(id); + cerr << "Shader Log:" << endl << log << endl; + delete[] log; + goto cleanup_shader; + } + + return id; + +cleanup_shader: + glDeleteShader(id); +out: + return 0; +} + /* The program's main entry point */ int main(int argc, char * argv[]) { @@ -75,6 +169,30 @@ Viewer::Viewer(const char * filename) exit(1); } + m_vs = makeShader(GL_VERTEX_SHADER, "v_shader.glsl"); + m_fs = makeShader(GL_FRAGMENT_SHADER, "f_shader.glsl"); + + m_program = glCreateProgram(); + glAttachShader(m_program, m_vs); + glAttachShader(m_program, m_fs); + + glBindAttribLocation(m_program, LOC_POSITION, "pos"); + glBindAttribLocation(m_program, LOC_NORMAL, "normal"); + + glLinkProgram(m_program); + + GLint link_status; + glGetProgramiv(m_program, GL_LINK_STATUS, &link_status); + if (link_status != GL_TRUE) + { + char *log = getProgramLog(m_program); + cerr << "Program log:" << endl << log << endl; + delete[] log; + glDeleteShader(m_vs); + glDeleteShader(m_fs); + exit(1); + } + /* Print out the object's size */ const float * aabb = m_obj.getAABB(); cout << "Object width: " << (aabb[3]-aabb[0]) << endl; @@ -86,20 +204,10 @@ void Viewer::initgl() { glClearColor(0.0, 0.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); - glShadeModel(GL_SMOOTH); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_CULL_FACE); glViewport(0, 0, WIDTH, HEIGHT); setProjection(); glLoadIdentity(); glGetFloatv(GL_MODELVIEW_MATRIX, m_rotationMatrix); -// float pos[] = {0.0, -1.0, 0.0, 0.0}; -// glLightfv(GL_LIGHT0, GL_POSITION, pos); - GLfloat lightAmbient[] = {0.2, 0.2, 0.2, 1}; - glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient); - GLfloat ambient[] = {0.0, 0.0, 0.0, 1.0}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); } void Viewer::setProjection() @@ -117,18 +225,22 @@ void Viewer::display() glLoadIdentity(); gluLookAt(0, -m_dist, 0, 0, 0, 0, 0, 0, 1); glMultMatrixf(m_rotationMatrix); + m_obj.bindBuffers(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); + glUseProgram(m_program); + glEnableVertexAttribArray(LOC_POSITION); + glEnableVertexAttribArray(LOC_NORMAL); int stride = m_obj.getStride(); - glVertexPointer(3, GL_FLOAT, stride, (GLvoid *) m_obj.getVertexOffset()); - glNormalPointer(GL_FLOAT, stride, (GLvoid *) m_obj.getNormalOffset()); + glVertexAttribPointer(LOC_POSITION, 3, GL_FLOAT, GL_FALSE, + stride, (GLvoid *) m_obj.getVertexOffset()); + glVertexAttribPointer(LOC_NORMAL, 3, GL_FLOAT, GL_FALSE, + stride, (GLvoid *) m_obj.getNormalOffset()); if (m_obj.doTextures()) { - glTexCoordPointer(2, GL_FLOAT, stride, - (GLvoid *) m_obj.getTextureCoordOffset()); + /* TODO */ } - for (map::iterator it = m_obj.getMaterials().begin(); + for (map::iterator it = + m_obj.getMaterials().begin(); it != m_obj.getMaterials().end(); it++) {