main.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. //
  2. // Display a color cube
  3. //
  4. // Colors are assigned to each vertex and then the rasterizer interpolates
  5. // those colors across the triangles. We us an orthographic projection
  6. // as the default projetion.
  7. #include "Angel.h"
  8. #include <algorithm>
  9. #include <fstream>
  10. #include <iostream>
  11. #include <limits>
  12. #include <vector>
  13. #define NORM true
  14. typedef Angel::vec4 color4;
  15. typedef Angel::vec4 point4;
  16. std::vector<point4> points;
  17. std::vector<color4> colors;
  18. inline vec4 multq(vec4 a, vec4 b) {
  19. // extract axes
  20. vec3 aa = vec3(a[1], a[2], a[3]);
  21. vec3 bb = vec3(b[1], b[2], b[3]);
  22. vec3 cc = a[0] * bb + b[0] * aa + cross(bb, aa);
  23. // reassemble quaternion in vec4
  24. return (vec4(a[0] * b[0] - dot(aa, bb), cc[0], cc[1], cc[2]));
  25. }
  26. // Array of rotation angles (in degrees) for each coordinate axis
  27. int winWidth, winHeight;
  28. vec3 axis;
  29. vec4 rquat = vec4(1.0, 0.0, 0.0, 0.0);
  30. vec4 move = vec4(0.0, 0.0, 0.0, 0.0);
  31. GLfloat angle;
  32. bool trackingMouse = false;
  33. bool redrawContinue = false;
  34. bool trackballMove = false;
  35. float lastPos[3] = {0.0F, 0.0F, 0.0F};
  36. int curx, cury;
  37. int startX, startY;
  38. GLuint vao;
  39. GLuint buffer;
  40. GLuint program;
  41. GLuint vPosition;
  42. GLuint vColor;
  43. GLuint rquat_loc;
  44. GLuint move_loc;
  45. const std::string models_file[] = {
  46. "bunny_color_HoleFill.obj",
  47. "gargoyle_color.obj",
  48. "v1_color.obj",
  49. };
  50. //----------------------------------------------------------------------------
  51. void load_model(const std::string &file_name) {
  52. /* assume model file is vaild
  53. vertices nums == vertex_color nums
  54. only contain triangles
  55. the triangles' vertices are in vertices
  56. */
  57. std::vector<point4> vertices;
  58. std::vector<color4> vertex_colors;
  59. std::fstream s(file_name, std::fstream::in);
  60. if (!s.is_open()) {
  61. std::cerr << "failed to open" << file_name << std::endl;
  62. } else {
  63. std::string t;
  64. float x, y, z;
  65. float xmax = std::numeric_limits<float>::min(),
  66. ymax = std::numeric_limits<float>::min(),
  67. zmax = std::numeric_limits<float>::min();
  68. float xmin = std::numeric_limits<float>::max(),
  69. ymin = std::numeric_limits<float>::max(),
  70. zmin = std::numeric_limits<float>::max();
  71. int a, b, c;
  72. int num = 0;
  73. while (s >> t >> x >> y >> z) {
  74. if (t == "v") {
  75. num++;
  76. vertices.emplace_back(x, y, z, 1.0);
  77. xmax = std::max(x, xmax);
  78. xmin = std::min(x, xmin);
  79. ymax = std::max(y, ymax);
  80. ymin = std::min(y, ymin);
  81. zmax = std::max(z, zmax);
  82. zmin = std::min(z, zmin);
  83. } else {
  84. vertex_colors.emplace_back(x, y, z, 1.0);
  85. break;
  86. }
  87. }
  88. if (xmax > 1.0f || xmin < -1.0f || ymax > 1.0f || ymin < -1.0f ||
  89. zmax > 1.0f || zmin < -1.0f || NORM) {
  90. float scale = 1.0f / std::max({xmax - xmin, ymax - ymin, zmax - zmin});
  91. std::cout << "scale: " << scale << std::endl;
  92. float xmid = 0.5f * (xmax + xmin);
  93. float ymid = 0.5f * (ymax + ymin);
  94. float zmid = 0.5f * (zmax + zmin);
  95. for (point4 &p : vertices) {
  96. p[0] -= xmid;
  97. p[0] *= scale;
  98. p[1] -= ymid;
  99. p[1] *= scale;
  100. p[2] -= zmid;
  101. p[2] *= scale;
  102. }
  103. }
  104. std::cout << "there are " << num << " vertex(ices)" << std::endl;
  105. for (int i = 1; i < num; ++i) {
  106. s >> t >> x >> y >> z;
  107. vertex_colors.emplace_back(x, y, z, 1.0);
  108. }
  109. num = 0;
  110. points.clear();
  111. colors.clear();
  112. while (s >> t >> a >> b >> c) {
  113. points.push_back(vertices[a - 1]);
  114. points.push_back(vertices[b - 1]);
  115. points.push_back(vertices[c - 1]);
  116. colors.push_back(vertex_colors[a - 1]);
  117. colors.push_back(vertex_colors[b - 1]);
  118. colors.push_back(vertex_colors[c - 1]);
  119. num++;
  120. }
  121. std::cout << "there are " << num << " triangle(s)" << std::endl;
  122. }
  123. }
  124. // OpenGL initialization
  125. void init(const std::string &file_name) {
  126. load_model(file_name);
  127. // Create a vertex array object
  128. glGenVertexArrays(1, &vao);
  129. glBindVertexArray(vao);
  130. // Create and initialize a buffer object
  131. glGenBuffers(1, &buffer);
  132. glBindBuffer(GL_ARRAY_BUFFER, buffer);
  133. glBufferData(GL_ARRAY_BUFFER, sizeof(vec4) * (points.size() + colors.size()),
  134. NULL, GL_STATIC_DRAW);
  135. glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vec4) * points.size(),
  136. points.data());
  137. glBufferSubData(GL_ARRAY_BUFFER, sizeof(vec4) * points.size(),
  138. sizeof(vec4) * colors.size(), colors.data());
  139. // Load shaders and use the resulting shader program
  140. program = InitShader("vshader36.glsl", "fshader36.glsl");
  141. glUseProgram(program);
  142. // set up vertex arrays
  143. vPosition = glGetAttribLocation(program, "vPosition");
  144. glEnableVertexAttribArray(vPosition);
  145. glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
  146. vColor = glGetAttribLocation(program, "vColor");
  147. glEnableVertexAttribArray(vColor);
  148. glVertexAttribPointer(vColor, 4, GL_FLOAT, GL_FALSE, 0,
  149. BUFFER_OFFSET(sizeof(vec4) * points.size()));
  150. rquat_loc = glGetUniformLocation(program, "rquat");
  151. move_loc = glGetUniformLocation(program, "move");
  152. glEnable(GL_DEPTH_TEST);
  153. glClearColor(1.0, 1.0, 1.0, 1.0);
  154. }
  155. //----------------------------------------------------------------------------
  156. void display(void) {
  157. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  158. if (trackballMove) {
  159. rquat = multq(vec4(cos(angle * 0.5f), sin(angle * 0.5f) * axis[0],
  160. sin(angle * 0.5) * axis[1], sin(angle * 0.5f) * axis[2]),
  161. rquat);
  162. }
  163. glUniform4fv(rquat_loc, 1, rquat);
  164. glUniform4fv(move_loc, 1, move);
  165. glDrawArrays(GL_TRIANGLES, 0, points.size());
  166. glutSwapBuffers();
  167. }
  168. //----------------------------------------------------------------------------
  169. void keyboard(unsigned char key, int x, int y) {
  170. switch (key) {
  171. case 033: // Escape Key
  172. case 'q':
  173. case 'Q':
  174. exit(EXIT_SUCCESS);
  175. break;
  176. case 'd':
  177. move[0] += 0.1;
  178. glutPostRedisplay();
  179. break;
  180. case 'a':
  181. move[0] -= 0.1;
  182. glutPostRedisplay();
  183. break;
  184. case 'w':
  185. move[1] += 0.1;
  186. glutPostRedisplay();
  187. break;
  188. case 's':
  189. move[1] -= 0.1;
  190. glutPostRedisplay();
  191. break;
  192. case 'z':
  193. move[3] += 0.1;
  194. glutPostRedisplay();
  195. break;
  196. case 'Z':
  197. move[3] -= 0.1;
  198. glutPostRedisplay();
  199. break;
  200. }
  201. }
  202. /*----------------------------------------------------------------------*/
  203. /*
  204. ** These functions implement a simple trackball-like motion control.
  205. */
  206. void trackball_ptov(int x, int y, int width, int height, float v[3]) {
  207. float d, a;
  208. /* project x,y onto a hemi-sphere centered within width, height */
  209. v[0] = (2.0F * x - width) / width;
  210. v[1] = (height - 2.0F * y) / height;
  211. d = (float)sqrt(v[0] * v[0] + v[1] * v[1]);
  212. v[2] = (float)cos((M_PI / 2.0F) * ((d < 1.0F) ? d : 1.0F));
  213. a = 1.0F / (float)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  214. v[0] *= a;
  215. v[1] *= a;
  216. v[2] *= a;
  217. }
  218. void mouseMotion(int x, int y) {
  219. float curPos[3], dx, dy, dz;
  220. trackball_ptov(x, y, winWidth, winHeight, curPos);
  221. if (trackingMouse) {
  222. dx = curPos[0] - lastPos[0];
  223. dy = curPos[1] - lastPos[1];
  224. dz = curPos[2] - lastPos[2];
  225. if (dx || dy || dz) {
  226. angle = 1.1 * M_PI * 0.5 * sqrt(dx * dx + dy * dy + dz * dz);
  227. axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
  228. axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
  229. axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
  230. float z = 1.0f /
  231. sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
  232. axis[0] *= z;
  233. axis[1] *= z;
  234. axis[2] *= z;
  235. lastPos[0] = curPos[0];
  236. lastPos[1] = curPos[1];
  237. lastPos[2] = curPos[2];
  238. }
  239. }
  240. glutPostRedisplay();
  241. }
  242. void startMotion(int x, int y) {
  243. trackingMouse = true;
  244. redrawContinue = false;
  245. startX = x;
  246. startY = y;
  247. curx = x;
  248. cury = y;
  249. trackball_ptov(x, y, winWidth, winHeight, lastPos);
  250. trackballMove = true;
  251. }
  252. void stopMotion(int x, int y) {
  253. trackingMouse = false;
  254. if (startX != x || startY != y) {
  255. redrawContinue = true;
  256. } else {
  257. angle = 0.0F;
  258. redrawContinue = false;
  259. trackballMove = false;
  260. }
  261. }
  262. void mouseButton(int button, int state, int x, int y) {
  263. if (button == GLUT_LEFT_BUTTON)
  264. switch (state) {
  265. case GLUT_DOWN:
  266. y = winHeight - y;
  267. startMotion(x, y);
  268. break;
  269. case GLUT_UP:
  270. stopMotion(x, y);
  271. break;
  272. }
  273. }
  274. void myReshape(int w, int h) {
  275. glViewport(0, 0, w, h);
  276. winWidth = w;
  277. winHeight = h;
  278. }
  279. void spinCube() {
  280. if (redrawContinue)
  281. glutPostRedisplay();
  282. }
  283. void mymenu(int value) {
  284. if (value == 3) {
  285. exit(EXIT_SUCCESS);
  286. }
  287. }
  288. void select(int value) {
  289. init(models_file[value]);
  290. glutPostRedisplay();
  291. }
  292. /*----------------------------------------------------------------------*/
  293. int main(int argc, char **argv) {
  294. glutInit(&argc, argv);
  295. glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
  296. glutInitWindowSize(512, 512);
  297. glutInitContextVersion(3, 1);
  298. glutInitContextProfile(GLUT_CORE_PROFILE);
  299. glutCreateWindow("model viewer");
  300. if (glewInit() != GLEW_OK) {
  301. std::cerr << "Failed to initialize GLEW ... exiting" << std::endl;
  302. exit(EXIT_FAILURE);
  303. }
  304. int menu = glutCreateMenu(select);
  305. glutAddMenuEntry("bunny_color_HoleFill.obj", 0);
  306. glutAddMenuEntry("gargoyle_color.obj.obj", 1);
  307. glutAddMenuEntry("v1_color.obj", 2);
  308. glutCreateMenu(mymenu);
  309. glutAddSubMenu("select model", menu);
  310. glutAddMenuEntry("Exit", 3);
  311. glutAttachMenu(GLUT_RIGHT_BUTTON);
  312. init("v1_color.obj");
  313. glutReshapeFunc(myReshape);
  314. glutIdleFunc(spinCube);
  315. glutDisplayFunc(display);
  316. glutKeyboardFunc(keyboard);
  317. glutMouseFunc(mouseButton);
  318. glutMotionFunc(mouseMotion);
  319. glutMainLoop();
  320. return 0;
  321. }