// created by Thorsten Thormaehlen for educational purpose //#define USE_GLEW #ifdef USE_GLEW // using glew is recommended #include static void initExtensions() { glewInit(); } #else // if glew is not used, the function // addresses of OpenGL extensions // need to be resolved here #include "glextensions.h" #endif #include #include #include #include #include #include #include #include using namespace std; #include class Renderer { private: struct Vertex { float position[3]; float texCoord[2]; float normal[3]; }; struct ShaderID { GLuint progID; GLuint vertID; GLuint fragID; }; public: float t; float loc; float loc2; int modeVal; private: enum {Scene, Debug, numVAOs}; enum {SceneAll, DebugAll, numVBOs}; GLuint texID; GLuint vaoID[numVAOs]; GLuint bufID[numVBOs]; int sceneVertNo; GLint vertexLoc; GLint texCoordLoc; GLint normalLoc; GLint projectionLoc; GLint viewLoc; GLint modelTransLoc; GLint normalMatrixLoc; GLint eyePosLoc; GLint modeLoc; GLint texLoc; float projection[16]; // projection matrix float view[16]; // camera view matrix std::string filename; int file; std::vector shaders; // for debug visualizations GLint vertexDebugLoc; GLint texCoordDebugLoc; GLint colorDebugLoc; GLint projectionDebugLoc; GLint viewDebugLoc; GLint modelTransDebugLoc; GLint modeDebugLoc; GLint texDebugLoc; public: // constructor Renderer() : t(0.0), loc(-90.0), loc2(0.0), modeVal(1), texID(0), sceneVertNo(0), vertexLoc(0), texCoordLoc(0), normalLoc(0), projectionLoc(0), viewLoc(0), modelTransLoc(0), normalMatrixLoc(0), eyePosLoc(0), modeLoc(0), texLoc(0), filename("../teapot.txt"), file(0), vertexDebugLoc(0), texCoordDebugLoc(0), colorDebugLoc(0), projectionDebugLoc(0), viewDebugLoc(0), modelTransDebugLoc(0), modeDebugLoc(0), texDebugLoc(0) { } //destructor ~Renderer() { deleteAll(); } public: void nextModel() { file++; if(file > 4) file = 0; if(file == 0) filename = "../teapot.txt"; if(file == 1) filename = "../sphere.txt"; if(file == 2) filename = "../cube.txt"; if(file == 3) filename = "../knot.txt"; if(file == 4) filename = "../hose.txt"; deleteAll(); init(); } void init() { initExtensions(); glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH); // enabling this feature reduced the seam that // occures because all faces of the cube // are filtered separately glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); setupShaders(); // create the Vertex Array Objects (VAO) glGenVertexArrays(numVAOs, vaoID); // generate the Vertex Buffer Objects (VBO) glGenBuffers(numVBOs, bufID); // binding the scene VAO glBindVertexArray(vaoID[Scene]); std::vector data; loadVertexData(filename, data); sceneVertNo = data.size() / (3+2+3); glBindBuffer(GL_ARRAY_BUFFER, bufID[SceneAll]); glBufferData(GL_ARRAY_BUFFER, sceneVertNo*sizeof(Vertex), &data[0], GL_STATIC_DRAW); int stride = sizeof(Vertex); char *offset = (char*)NULL; // position glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, GL_FALSE, stride, offset); glEnableVertexAttribArray(vertexLoc); // texCoord offset = (char*)NULL + 3*sizeof(float); glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, stride, offset); glEnableVertexAttribArray(texCoordLoc); // normal offset = (char*)NULL + (3+2)*sizeof(float); glVertexAttribPointer(normalLoc, 3, GL_FLOAT, GL_FALSE, stride, offset); glEnableVertexAttribArray(normalLoc); // the following is only to display debug information // binding the debug VAO glBindVertexArray(vaoID[Debug]); float debugData[] = { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, // bottom -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, //top 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, // right 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, // left -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, // near 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, // far -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; glBindBuffer(GL_ARRAY_BUFFER, bufID[DebugAll]); // note that this is a "DYNAMIC_DRAW" buffer which gets // automatically updated when the input changes glBufferData(GL_ARRAY_BUFFER, 24*sizeof(Vertex), &debugData[0], GL_STATIC_DRAW); // position offset = (char*)NULL; glVertexAttribPointer(vertexDebugLoc, 3, GL_FLOAT, GL_FALSE, stride, offset); glEnableVertexAttribArray(vertexDebugLoc); // texCoord offset = (char*)NULL + 3*sizeof(float); glVertexAttribPointer(texCoordDebugLoc, 2, GL_FLOAT, GL_FALSE, stride, offset); glEnableVertexAttribArray(texCoordDebugLoc); // color offset = (char*)NULL + (3+2)*sizeof(float); glVertexAttribPointer(colorDebugLoc, 3, GL_FLOAT, GL_FALSE, stride, offset); glEnableVertexAttribArray(colorDebugLoc); glBindVertexArray(0); std::vector fileNames; fileNames.push_back("../cubemap_RT.ppm"); fileNames.push_back("../cubemap_LF.ppm"); fileNames.push_back("../cubemap_UP.ppm"); fileNames.push_back("../cubemap_DN.ppm"); fileNames.push_back("../cubemap_BK.ppm"); fileNames.push_back("../cubemap_FR.ppm"); texID = loadCubeMap(fileNames); } void resize(int w, int h) { glViewport(0, 0, w, h); // this function replaces gluPerspective mat4Perspective(projection, 30.0f, (float)w/(float)h, 0.5f, 40.0f); // mat4Print(projection); } void display() { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); double angle = M_PI / 180.0f * t; float modelTrans[16], rotx[16], rotz[16]; mat4RotateX(rotx, M_PI/2.0f); mat4RotateZ(rotz, angle); mat4Multiply(rotx, rotz, modelTrans); float modelTransInv[16], normalmatrix[16]; mat4Invert(modelTrans, modelTransInv); mat4Transpose(modelTransInv, normalmatrix); // camera orbits in the y=3 plane // and looks at the origin // mat4LookAt replaces gluLookAt double rad = M_PI / 180.0f * loc; float eye[3]; eye[0] = -3.0f*cos(rad); eye[1] = loc2; eye[2] = -3.0f*sin(rad); mat4LookAt(view, eye[0], eye[1], eye[2], 0.0f, 0.0f, 0.0f, // look at 0.0f, 1.0f, 0.0f); // up glUseProgram(shaders[0].progID); // load the current projection and modelview matrix into the // corresponding UNIFORM variables of the shader glUniformMatrix4fv(projectionLoc, 1, false, projection); glUniformMatrix4fv(viewLoc, 1, false, view); glUniformMatrix4fv(modelTransLoc, 1, false, modelTrans); glUniformMatrix4fv(normalMatrixLoc, 1, false, normalmatrix); glUniform3fv(eyePosLoc, 1, eye); glUniform1i(modeLoc, modeVal); // activate texture unit 0 glActiveTexture(GL_TEXTURE0); // bind texture glBindTexture(GL_TEXTURE_CUBE_MAP, texID); // inform the shader to use texture unit 0 glUniform1i(texLoc, 0); // bind scene VAO glBindVertexArray(vaoID[Scene]); // render data glDrawArrays(GL_TRIANGLES, 0, sceneVertNo); drawCubeMapDebug(); } private: void drawCubeMapDebug() { // activate texture unit 0 glActiveTexture(GL_TEXTURE0); // bind texture glBindTexture(GL_TEXTURE_CUBE_MAP, texID); // inform the shader to use texture unit 0 glUniform1i(texDebugLoc, 0); // bind debug VAO glBindVertexArray(vaoID[Debug]); glUseProgram(shaders[1].progID); glUniformMatrix4fv(projectionDebugLoc, 1, false, projection); float a[16]; mat4Identity(a); mat4Scale(a, 20.0, 20.0, 20.0); glUniformMatrix4fv(modelTransDebugLoc, 1, false, a); glUniformMatrix4fv(viewDebugLoc, 1, false, view); if(modeDebugLoc != -1) glUniform1i(modeDebugLoc, modeVal); // render data glDrawArrays(GL_QUADS, 0, 24); glUseProgram(0); } void setupShaders() { // blinn phong shader ShaderID s = createShader(string("../EnvLighting.vert"),string("../EnvLighting.frag")); // retrieve the location of the IN variables of the vertex shaders vertexLoc = glGetAttribLocation(s.progID,"inputPosition"); texCoordLoc = glGetAttribLocation(s.progID,"inputTexCoord"); normalLoc = glGetAttribLocation(s.progID, "inputNormal"); // retrieve the location of the UNIFORM variables of the shaders projectionLoc = glGetUniformLocation(s.progID, "projection"); viewLoc = glGetUniformLocation(s.progID, "view"); modelTransLoc = glGetUniformLocation(s.progID, "modelTrans"); normalMatrixLoc = glGetUniformLocation(s.progID, "normalMat"); eyePosLoc = glGetUniformLocation(s.progID, "eyePos"); modeLoc = glGetUniformLocation(s.progID, "mode"); texLoc = glGetUniformLocation(s.progID, "myTexture"); shaders.push_back(s); // debug information shader ShaderID d = createShader(string("../debug.vert"),string("../debug.frag")); // retrieve the location of the IN variables of the vertex shaders vertexDebugLoc = glGetAttribLocation(d.progID,"inputPosition"); texCoordDebugLoc = glGetAttribLocation(d.progID,"inputTexCoord"); colorDebugLoc = glGetAttribLocation(d.progID, "inputColor"); // retrieve the location of the UNIFORM variables of the shaders projectionDebugLoc = glGetUniformLocation(d.progID, "projection"); viewDebugLoc = glGetUniformLocation(d.progID, "view"); modelTransDebugLoc = glGetUniformLocation(d.progID, "modelTrans"); modeDebugLoc = glGetUniformLocation(d.progID, "mode"); texDebugLoc = glGetUniformLocation(d.progID, "myTexture"); shaders.push_back(d); } ShaderID createShader(string vertSrc, string fragSrc) { ShaderID s; // create shader s.vertID = glCreateShader(GL_VERTEX_SHADER); s.fragID = glCreateShader(GL_FRAGMENT_SHADER); // load shader source from file GLint vlen, flen; const char* vs = loadShaderSrc(vertSrc.c_str(), vlen); const char* fs = loadShaderSrc(fragSrc.c_str(), flen); // specify shader source glShaderSource(s.vertID, 1, &vs, &vlen); glShaderSource(s.fragID, 1, &fs, &flen); free((char*)vs); free((char*)fs); // compile the shader glCompileShader(s.vertID); glCompileShader(s.fragID); // check for errors printShaderInfoLog(s.vertID); printShaderInfoLog(s.fragID); // create program and attach shaders s.progID = glCreateProgram(); glAttachShader(s.progID, s.vertID); glAttachShader(s.progID, s.fragID); // "outColor" is a user-provided OUT variable // of the fragment shader. // Its output is bound to the first color buffer // in the framebuffer glBindFragDataLocation(s.progID, 0, "outputColor"); // link the program glLinkProgram(s.progID); // output error messages printProgramInfoLog(s.progID); return s; } void deleteAll() { glDeleteVertexArrays(numVAOs, vaoID); glDeleteBuffers(numVBOs, bufID); for(unsigned i=0; i < shaders.size(); i++) { glDeleteProgram(shaders[i].progID); glDeleteShader(shaders[i].vertID); glDeleteShader(shaders[i].fragID); } } void printShaderInfoLog(GLuint obj) { int infoLogLength = 0; int returnLength = 0; char *infoLog; glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength); if (infoLogLength > 0) { infoLog = (char *)malloc(infoLogLength); glGetShaderInfoLog(obj, infoLogLength, &returnLength, infoLog); printf("%s\n",infoLog); free(infoLog); } } void printProgramInfoLog(GLuint obj) { int infoLogLength = 0; int returnLength = 0; char *infoLog; glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infoLogLength); if (infoLogLength > 0) { infoLog = (char *)malloc(infoLogLength); glGetProgramInfoLog(obj, infoLogLength, &returnLength, infoLog); printf("%s\n",infoLog); free(infoLog); } } // Loads text file into char* fname. // Caller needs to free the allocated memory const char* loadShaderSrc(const 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; } // returns a valid textureID on success, otherwise 0 GLuint loadCubeMap(std::vector &filenames) { if(filenames.size() < 6) return 0; unsigned width; unsigned height; int level = 0; int border = 0; unsigned char *imgData = NULL; // data is aligned in byte order glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //request textureID GLuint textureID; glGenTextures( 1, &textureID); // bind texture glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); // parameters that define how to warp the texture glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // parameters that define how to filter the texture glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE); unsigned int cubeTargets[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; for(int i = 0; i < 6; i++) { // load image data if(!loadPPMImage(filenames[i], width, height, imgData)) return 0; // specify the 2D texture map glTexImage2D(cubeTargets[i], level, GL_RGB, width, height, border, GL_RGB, GL_UNSIGNED_BYTE, imgData); //the texture data is now handled by opengl, we can free the local copy free(imgData); } // return unique texture identifier return textureID; } bool loadPPMImage(std::string &filename, unsigned &width, unsigned &height, unsigned char *&imgData) { FILE *file = fopen(filename.c_str(), "rb"); if (file == NULL ) { QMessageBox msgBox; msgBox.setText(QString("Can not find texture data file ")+QString(filename.c_str())); msgBox.exec(); return false; } char line[256]; fgets(line, 256, file); if(strncmp(line, "P6", 2)) { QMessageBox msgBox; msgBox.setText("File is not PPM P6 raw format"); msgBox.exec(); fclose(file); return false; } width = 0; height = 0; unsigned depth = 0; unsigned readItems =0; while (!feof(file) && readItems < 3) { fscanf(file, "%s", line); if (line[0] != '#' ) { if ( readItems == 0 ) readItems += sscanf(line, "%d", &width); else if ( readItems == 1 ) readItems += sscanf(line, "%d", &height); else if ( readItems == 2 ) { readItems += sscanf(line, "%d", &depth); while (!feof(file) && fgetc(file) != '\n') ; } }else{ // skip comments while (!feof(file) && fgetc(file) != '\n') ; } } if(depth >= 256) { QMessageBox msgBox; msgBox.setText("Only 8-bit PPM format is supported"); msgBox.exec(); fclose(file); return false; } unsigned byteCount = width * height * 3; imgData = (unsigned char *)malloc( width * height * 3 * sizeof(unsigned char)); fread(imgData, byteCount, sizeof(unsigned char), file); fclose(file); return true; } // the following functions are some matrix and vector helpers, // which work for this demo but in general it is recommended // to use more advanced matrix libaries, // e.g. OpenGL Mathematics (GLM) float vec3Dot( float *a, float *b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } void vec3Add( float *a, float *b, float *res) { res[0] = a[0]+b[0]; res[1] = a[1]+b[1]; res[2] = a[2]+b[2]; } void vec3Cross( float *a, float *b, float *res) { res[0] = a[1] * b[2] - b[1] * a[2]; res[1] = a[2] * b[0] - b[2] * a[0]; res[2] = a[0] * b[1] - b[0] * a[1]; } void vec3Normalize(float *a) { float mag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); a[0] /= mag; a[1] /= mag; a[2] /= mag; } void mat4Identity( float *a) { for (int i = 0; i < 16; ++i) a[i] = 0.0f; for (int i = 0; i < 4; ++i) a[i + i * 4] = 1.0f; } void mat4Scale(float *a, float sx, float sy, float sz) { for (int i = 0; i < 16; ++i) a[i] = 0.0f; a[0 + 0 * 4] = sx; a[1 + 1 * 4] = sy; a[2 + 2 * 4] = sz; a[3 + 3 * 4] = 1.0; } void mat4Multiply(float *a, float *b, float *res) { for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { res[j*4 + i] = 0.0f; for (int k = 0; k < 4; ++k) { res[j*4 + i] += a[k*4 + i] * b[j*4 + k]; } } } } void mat4MultVec3(float *mat, float *vec, float *res) { for (int i = 0; i < 3; ++i) { res[i] = 0.0f; for (int k = 0; k < 3; ++k) { res[i] += mat[i + k*4] * vec[k]; } res[i] += mat[i + 3*4] * 1.0; } } void mat4RotateZ(float *a, float rad) { float c = cos(rad); float s = sin(rad); mat4Identity(a); a[0 * 4 + 0] = c; a[0 * 4 + 1] = -s; a[1 * 4 + 0] = s; a[1 * 4 + 1] = c; } void mat4RotateX(float *a, float rad) { float c = cos(rad); float s = sin(rad); mat4Identity(a); a[1 * 4 + 1] = c; a[1 * 4 + 2] = -s; a[2 * 4 + 1] = s; a[2 * 4 + 2] = c; } void mat4RotateY(float *a, float rad) { float c = cos(rad); float s = sin(rad); mat4Identity(a); a[0 * 4 + 0] = c; a[0 * 4 + 2] = s; a[2 * 4 + 0] = -s; a[2 * 4 + 2] = c; } void mat4Perspective(float *a, float fov, float aspect, float zNear, float zFar) { float f = 1.0f / float(tan (fov/2.0f * (M_PI / 180.0f))); mat4Identity(a); a[0] = f / aspect; a[1 * 4 + 1] = f; a[2 * 4 + 2] = (zFar + zNear) / (zNear - zFar); a[3 * 4 + 2] = (2.0f * zFar * zNear) / (zNear - zFar); a[2 * 4 + 3] = -1.0f; a[3 * 4 + 3] = 0.0f; } void mat4LookAt(float *viewMatrix, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { float dir[3], right[3], up[3], eye[3]; up[0]=upX; up[1]=upY; up[2]=upZ; eye[0]=eyeX; eye[1]=eyeY; eye[2]=eyeZ; dir[0]=centerX-eyeX; dir[1]=centerY-eyeY; dir[2]=centerZ-eyeZ; vec3Normalize(dir); vec3Cross(dir,up,right); vec3Normalize(right); vec3Cross(right,dir,up); vec3Normalize(up); // first row viewMatrix[0] = right[0]; viewMatrix[4] = right[1]; viewMatrix[8] = right[2]; viewMatrix[12] = -vec3Dot(right, eye); // second row viewMatrix[1] = up[0]; viewMatrix[5] = up[1]; viewMatrix[9] = up[2]; viewMatrix[13] = -vec3Dot(up, eye); // third row viewMatrix[2] = -dir[0]; viewMatrix[6] = -dir[1]; viewMatrix[10] = -dir[2]; viewMatrix[14] = vec3Dot(dir, eye); // forth row viewMatrix[3] = 0.0f; viewMatrix[7] = 0.0f; viewMatrix[11] = 0.0f; viewMatrix[15] = 1.0f; } void mat4Print(float* a) { // opengl uses column major order for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { cout << a[j * 4 + i] << " "; } cout << endl; } } void mat4Transpose(float* a, float *transposed) { int t = 0; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { transposed[t++] = a[j * 4 + i]; } } } bool mat4Invert(float* m, float *inverse) { float inv[16]; inv[0] = m[5]*m[10]*m[15]-m[5]*m[11]*m[14]-m[9]*m[6]*m[15]+ m[9]*m[7]*m[14]+m[13]*m[6]*m[11]-m[13]*m[7]*m[10]; inv[4] = -m[4]*m[10]*m[15]+m[4]*m[11]*m[14]+m[8]*m[6]*m[15]- m[8]*m[7]*m[14]-m[12]*m[6]*m[11]+m[12]*m[7]*m[10]; inv[8] = m[4]*m[9]*m[15]-m[4]*m[11]*m[13]-m[8]*m[5]*m[15]+ m[8]*m[7]*m[13]+m[12]*m[5]*m[11]-m[12]*m[7]*m[9]; inv[12]= -m[4]*m[9]*m[14]+m[4]*m[10]*m[13]+m[8]*m[5]*m[14]- m[8]*m[6]*m[13]-m[12]*m[5]*m[10]+m[12]*m[6]*m[9]; inv[1] = -m[1]*m[10]*m[15]+m[1]*m[11]*m[14]+m[9]*m[2]*m[15]- m[9]*m[3]*m[14]-m[13]*m[2]*m[11]+m[13]*m[3]*m[10]; inv[5] = m[0]*m[10]*m[15]-m[0]*m[11]*m[14]-m[8]*m[2]*m[15]+ m[8]*m[3]*m[14]+m[12]*m[2]*m[11]-m[12]*m[3]*m[10]; inv[9] = -m[0]*m[9]*m[15]+m[0]*m[11]*m[13]+m[8]*m[1]*m[15]- m[8]*m[3]*m[13]-m[12]*m[1]*m[11]+m[12]*m[3]*m[9]; inv[13]= m[0]*m[9]*m[14]-m[0]*m[10]*m[13]-m[8]*m[1]*m[14]+ m[8]*m[2]*m[13]+m[12]*m[1]*m[10]-m[12]*m[2]*m[9]; inv[2] = m[1]*m[6]*m[15]-m[1]*m[7]*m[14]-m[5]*m[2]*m[15]+ m[5]*m[3]*m[14]+m[13]*m[2]*m[7]-m[13]*m[3]*m[6]; inv[6] = -m[0]*m[6]*m[15]+m[0]*m[7]*m[14]+m[4]*m[2]*m[15]- m[4]*m[3]*m[14]-m[12]*m[2]*m[7]+m[12]*m[3]*m[6]; inv[10]= m[0]*m[5]*m[15]-m[0]*m[7]*m[13]-m[4]*m[1]*m[15]+ m[4]*m[3]*m[13]+m[12]*m[1]*m[7]-m[12]*m[3]*m[5]; inv[14]= -m[0]*m[5]*m[14]+m[0]*m[6]*m[13]+m[4]*m[1]*m[14]- m[4]*m[2]*m[13]-m[12]*m[1]*m[6]+m[12]*m[2]*m[5]; inv[3] = -m[1]*m[6]*m[11]+m[1]*m[7]*m[10]+m[5]*m[2]*m[11]- m[5]*m[3]*m[10]-m[9]*m[2]*m[7]+m[9]*m[3]*m[6]; inv[7] = m[0]*m[6]*m[11]-m[0]*m[7]*m[10]-m[4]*m[2]*m[11]+ m[4]*m[3]*m[10]+m[8]*m[2]*m[7]-m[8]*m[3]*m[6]; inv[11]= -m[0]*m[5]*m[11]+m[0]*m[7]*m[9]+m[4]*m[1]*m[11]- m[4]*m[3]*m[9]-m[8]*m[1]*m[7]+m[8]*m[3]*m[5]; inv[15]= m[0]*m[5]*m[10]-m[0]*m[6]*m[9]-m[4]*m[1]*m[10]+ m[4]*m[2]*m[9]+m[8]*m[1]*m[6]-m[8]*m[2]*m[5]; float det = m[0]*inv[0]+m[1]*inv[4]+m[2]*inv[8]+m[3]*inv[12]; if (det == 0) return false; det = 1.0f / det; for (int i = 0; i < 16; i++) inverse[i] = inv[i] * det; return true; } bool loadVertexData(std::string &filename, std::vector &data) { // read vertex data from file ifstream input(filename.c_str()); if(!input) { QMessageBox msgBox; msgBox.setText("Can not find vertex data file"); msgBox.exec(); return false; } else { int vertSize; double vertData; if(input >> vertSize) { if(vertSize > 0) { data.resize(vertSize); int i = 0; while(input >> vertData && i < vertSize) { // store it in the vector. data[i] = vertData; i++; } if(i != vertSize || vertSize % (3+2+3)) data.resize(0); } } input.close(); } return false; } }; class MyWidget : public QGLWidget { private: Renderer *renderer; QTimer *timer; public: MyWidget(QWidget *parent = NULL) : QGLWidget(parent) { this->setWindowTitle("Shader Envmap Lighting"); this->resize(640, 360); renderer = new Renderer(); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(updateGL())); timer->start(30); } ~MyWidget() { delete renderer; } protected: void initializeGL() { renderer->init(); } void resizeGL(int w, int h){ renderer->resize(w, h); } void paintGL() { float offset = 1.0f; renderer->t += offset; renderer->display(); } void keyPressEvent(QKeyEvent* event){ bool redraw = false; QString modeStr; switch(event->key()) { case '1': renderer->modeVal = 1; redraw = true; modeStr = QString("mode = 1"); break; case '2': renderer->modeVal = 2; redraw = true; modeStr = QString("mode = 2"); break; case '3': renderer->modeVal = 3; redraw = true; modeStr = QString("mode = 3"); break; case '4': renderer->modeVal = 4; redraw = true; modeStr = QString("mode = 4"); break; case '5': renderer->modeVal = 5; redraw = true; modeStr = QString("mode = 5"); break; case '0': renderer->nextModel(); redraw = true; modeStr = QString("Environment-Lighting"); break; case 'a': case 'A': renderer->loc -= 1.5; redraw = true; modeStr = QString("Environment-Lighting"); break; case 'd': case 'D': renderer->loc += 1.5; redraw = true; modeStr = QString("Environment-Lighting"); break; case 'w': case 'W': renderer->loc2 += 0.3; redraw = true; modeStr = QString("Environment-Lighting"); break; case 's': case 'S': renderer->loc2 -= 0.3; redraw = true; modeStr = QString("Environment-Lighting"); break; } if(redraw) { this->updateGL(); this->setWindowTitle(modeStr); } } }; int main (int argc, char* argv[]) { // create a QApplication object that handles initialization, // finalization, and the main event loop QApplication appl(argc, argv); MyWidget widget; // create a widget widget.show(); //show the widget and its children return appl.exec(); // execute the application }