123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- //
- // 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 <algorithm>
- #include <fstream>
- #include <iostream>
- #include <limits>
- #include <vector>
- #define NORM true
- typedef Angel::vec4 color4;
- typedef Angel::vec4 point4;
- std::vector<point4> points;
- std::vector<color4> 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;
- //----------------------------------------------------------------------------
- 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<point4> vertices;
- std::vector<color4> 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<float>::min(),
- ymax = std::numeric_limits<float>::min(),
- zmax = std::numeric_limits<float>::min();
- float xmin = std::numeric_limits<float>::max(),
- ymin = std::numeric_limits<float>::max(),
- zmin = std::numeric_limits<float>::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_RIGHT_BUTTON)
- exit(0);
- 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();
- }
- /*----------------------------------------------------------------------*/
- 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);
- }
- init("v1_color.obj");
- glutReshapeFunc(myReshape);
- glutIdleFunc(spinCube);
- glutDisplayFunc(display);
- glutKeyboardFunc(keyboard);
- glutMouseFunc(mouseButton);
- glutMotionFunc(mouseMotion);
- glutMainLoop();
- return 0;
- }
|