// // Display a color cube // // Colors are assigned to each vertex and then the rasterizer interpolates // those colors across the triangles. We us an orthographic projection // as the default projetion. #include "Angel.h" #include #include #include #include #include #define NORM true typedef Angel::vec4 color4; typedef Angel::vec4 point4; std::vector points; std::vector colors; inline vec4 multq(vec4 a, vec4 b) { // extract axes vec3 aa = vec3(a[1], a[2], a[3]); vec3 bb = vec3(b[1], b[2], b[3]); vec3 cc = a[0] * bb + b[0] * aa + cross(bb, aa); // reassemble quaternion in vec4 return (vec4(a[0] * b[0] - dot(aa, bb), cc[0], cc[1], cc[2])); } // Array of rotation angles (in degrees) for each coordinate axis int winWidth, winHeight; vec3 axis; vec4 rquat = vec4(1.0, 0.0, 0.0, 0.0); vec4 move = vec4(0.0, 0.0, 0.0, 0.0); GLfloat angle; bool trackingMouse = false; bool redrawContinue = false; bool trackballMove = false; float lastPos[3] = {0.0F, 0.0F, 0.0F}; int curx, cury; int startX, startY; GLuint vao; GLuint buffer; GLuint program; GLuint vPosition; GLuint vColor; GLuint rquat_loc; GLuint move_loc; const std::string models_file[] = { "bunny_color_HoleFill.obj", "gargoyle_color.obj", "v1_color.obj", }; //---------------------------------------------------------------------------- void load_model(const std::string &file_name) { /* assume model file is vaild vertices nums == vertex_color nums only contain triangles the triangles' vertices are in vertices */ std::vector vertices; std::vector vertex_colors; std::fstream s(file_name, std::fstream::in); if (!s.is_open()) { std::cerr << "failed to open" << file_name << std::endl; } else { std::string t; float x, y, z; float xmax = std::numeric_limits::min(), ymax = std::numeric_limits::min(), zmax = std::numeric_limits::min(); float xmin = std::numeric_limits::max(), ymin = std::numeric_limits::max(), zmin = std::numeric_limits::max(); int a, b, c; int num = 0; while (s >> t >> x >> y >> z) { if (t == "v") { num++; vertices.emplace_back(x, y, z, 1.0); xmax = std::max(x, xmax); xmin = std::min(x, xmin); ymax = std::max(y, ymax); ymin = std::min(y, ymin); zmax = std::max(z, zmax); zmin = std::min(z, zmin); } else { vertex_colors.emplace_back(x, y, z, 1.0); break; } } if (xmax > 1.0f || xmin < -1.0f || ymax > 1.0f || ymin < -1.0f || zmax > 1.0f || zmin < -1.0f || NORM) { float scale = 1.0f / std::max({xmax - xmin, ymax - ymin, zmax - zmin}); std::cout << "scale: " << scale << std::endl; float xmid = 0.5f * (xmax + xmin); float ymid = 0.5f * (ymax + ymin); float zmid = 0.5f * (zmax + zmin); for (point4 &p : vertices) { p[0] -= xmid; p[0] *= scale; p[1] -= ymid; p[1] *= scale; p[2] -= zmid; p[2] *= scale; } } std::cout << "there are " << num << " vertex(ices)" << std::endl; for (int i = 1; i < num; ++i) { s >> t >> x >> y >> z; vertex_colors.emplace_back(x, y, z, 1.0); } num = 0; points.clear(); colors.clear(); while (s >> t >> a >> b >> c) { points.push_back(vertices[a - 1]); points.push_back(vertices[b - 1]); points.push_back(vertices[c - 1]); colors.push_back(vertex_colors[a - 1]); colors.push_back(vertex_colors[b - 1]); colors.push_back(vertex_colors[c - 1]); num++; } std::cout << "there are " << num << " triangle(s)" << std::endl; } } // OpenGL initialization void init(const std::string &file_name) { load_model(file_name); // Create a vertex array object glGenVertexArrays(1, &vao); glBindVertexArray(vao); // Create and initialize a buffer object glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vec4) * (points.size() + colors.size()), NULL, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vec4) * points.size(), points.data()); glBufferSubData(GL_ARRAY_BUFFER, sizeof(vec4) * points.size(), sizeof(vec4) * colors.size(), colors.data()); // Load shaders and use the resulting shader program program = InitShader("vshader36.glsl", "fshader36.glsl"); glUseProgram(program); // set up vertex arrays vPosition = glGetAttribLocation(program, "vPosition"); glEnableVertexAttribArray(vPosition); glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); vColor = glGetAttribLocation(program, "vColor"); glEnableVertexAttribArray(vColor); glVertexAttribPointer(vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(vec4) * points.size())); rquat_loc = glGetUniformLocation(program, "rquat"); move_loc = glGetUniformLocation(program, "move"); glEnable(GL_DEPTH_TEST); glClearColor(1.0, 1.0, 1.0, 1.0); } //---------------------------------------------------------------------------- void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (trackballMove) { rquat = multq(vec4(cos(angle * 0.5f), sin(angle * 0.5f) * axis[0], sin(angle * 0.5) * axis[1], sin(angle * 0.5f) * axis[2]), rquat); } glUniform4fv(rquat_loc, 1, rquat); glUniform4fv(move_loc, 1, move); glDrawArrays(GL_TRIANGLES, 0, points.size()); glutSwapBuffers(); } //---------------------------------------------------------------------------- void keyboard(unsigned char key, int x, int y) { switch (key) { case 033: // Escape Key case 'q': case 'Q': exit(EXIT_SUCCESS); break; case 'd': move[0] += 0.1; glutPostRedisplay(); break; case 'a': move[0] -= 0.1; glutPostRedisplay(); break; case 'w': move[1] += 0.1; glutPostRedisplay(); break; case 's': move[1] -= 0.1; glutPostRedisplay(); break; case 'z': move[3] += 0.1; glutPostRedisplay(); break; case 'Z': move[3] -= 0.1; glutPostRedisplay(); break; } } /*----------------------------------------------------------------------*/ /* ** These functions implement a simple trackball-like motion control. */ void trackball_ptov(int x, int y, int width, int height, float v[3]) { float d, a; /* project x,y onto a hemi-sphere centered within width, height */ v[0] = (2.0F * x - width) / width; v[1] = (height - 2.0F * y) / height; d = (float)sqrt(v[0] * v[0] + v[1] * v[1]); v[2] = (float)cos((M_PI / 2.0F) * ((d < 1.0F) ? d : 1.0F)); a = 1.0F / (float)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); v[0] *= a; v[1] *= a; v[2] *= a; } void mouseMotion(int x, int y) { float curPos[3], dx, dy, dz; trackball_ptov(x, y, winWidth, winHeight, curPos); if (trackingMouse) { dx = curPos[0] - lastPos[0]; dy = curPos[1] - lastPos[1]; dz = curPos[2] - lastPos[2]; if (dx || dy || dz) { angle = 1.1 * M_PI * 0.5 * sqrt(dx * dx + dy * dy + dz * dz); axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1]; axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2]; axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0]; float z = 1.0f / sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]); axis[0] *= z; axis[1] *= z; axis[2] *= z; lastPos[0] = curPos[0]; lastPos[1] = curPos[1]; lastPos[2] = curPos[2]; } } glutPostRedisplay(); } void startMotion(int x, int y) { trackingMouse = true; redrawContinue = false; startX = x; startY = y; curx = x; cury = y; trackball_ptov(x, y, winWidth, winHeight, lastPos); trackballMove = true; } void stopMotion(int x, int y) { trackingMouse = false; if (startX != x || startY != y) { redrawContinue = true; } else { angle = 0.0F; redrawContinue = false; trackballMove = false; } } void mouseButton(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON) switch (state) { case GLUT_DOWN: y = winHeight - y; startMotion(x, y); break; case GLUT_UP: stopMotion(x, y); break; } } void myReshape(int w, int h) { glViewport(0, 0, w, h); winWidth = w; winHeight = h; } void spinCube() { if (redrawContinue) glutPostRedisplay(); } void mymenu(int value) { if (value == 3) { exit(EXIT_SUCCESS); } } void select(int value) { init(models_file[value]); glutPostRedisplay(); } /*----------------------------------------------------------------------*/ int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(512, 512); glutInitContextVersion(3, 1); glutInitContextProfile(GLUT_CORE_PROFILE); glutCreateWindow("model viewer"); if (glewInit() != GLEW_OK) { std::cerr << "Failed to initialize GLEW ... exiting" << std::endl; exit(EXIT_FAILURE); } int menu = glutCreateMenu(select); glutAddMenuEntry("bunny_color_HoleFill.obj", 0); glutAddMenuEntry("gargoyle_color.obj.obj", 1); glutAddMenuEntry("v1_color.obj", 2); glutCreateMenu(mymenu); glutAddSubMenu("select model", menu); glutAddMenuEntry("Exit", 3); glutAttachMenu(GLUT_RIGHT_BUTTON); init("v1_color.obj"); glutReshapeFunc(myReshape); glutIdleFunc(spinCube); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutMouseFunc(mouseButton); glutMotionFunc(mouseMotion); glutMainLoop(); return 0; }