main.cpp 9.0 KB

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