Platformer in OpenGL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

545 lines
15 KiB

5 years ago
  1. //========================================================================
  2. // This is an example program for the GLFW library
  3. //
  4. // The program uses a "split window" view, rendering four views of the
  5. // same scene in one window (e.g. uesful for 3D modelling software). This
  6. // demo uses scissors to separete the four different rendering areas from
  7. // each other.
  8. //
  9. // (If the code seems a little bit strange here and there, it may be
  10. // because I am not a friend of orthogonal projections)
  11. //========================================================================
  12. #include <glad/glad.h>
  13. #include <GLFW/glfw3.h>
  14. #if defined(_MSC_VER)
  15. // Make MS math.h define M_PI
  16. #define _USE_MATH_DEFINES
  17. #endif
  18. #include <math.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <linmath.h>
  22. //========================================================================
  23. // Global variables
  24. //========================================================================
  25. // Mouse position
  26. static double xpos = 0, ypos = 0;
  27. // Window size
  28. static int width, height;
  29. // Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left,
  30. // 4 = lower right
  31. static int active_view = 0;
  32. // Rotation around each axis
  33. static int rot_x = 0, rot_y = 0, rot_z = 0;
  34. // Do redraw?
  35. static int do_redraw = 1;
  36. //========================================================================
  37. // Draw a solid torus (use a display list for the model)
  38. //========================================================================
  39. #define TORUS_MAJOR 1.5
  40. #define TORUS_MINOR 0.5
  41. #define TORUS_MAJOR_RES 32
  42. #define TORUS_MINOR_RES 32
  43. static void drawTorus(void)
  44. {
  45. static GLuint torus_list = 0;
  46. int i, j, k;
  47. double s, t, x, y, z, nx, ny, nz, scale, twopi;
  48. if (!torus_list)
  49. {
  50. // Start recording displaylist
  51. torus_list = glGenLists(1);
  52. glNewList(torus_list, GL_COMPILE_AND_EXECUTE);
  53. // Draw torus
  54. twopi = 2.0 * M_PI;
  55. for (i = 0; i < TORUS_MINOR_RES; i++)
  56. {
  57. glBegin(GL_QUAD_STRIP);
  58. for (j = 0; j <= TORUS_MAJOR_RES; j++)
  59. {
  60. for (k = 1; k >= 0; k--)
  61. {
  62. s = (i + k) % TORUS_MINOR_RES + 0.5;
  63. t = j % TORUS_MAJOR_RES;
  64. // Calculate point on surface
  65. x = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * cos(t * twopi / TORUS_MAJOR_RES);
  66. y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES);
  67. z = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * sin(t * twopi / TORUS_MAJOR_RES);
  68. // Calculate surface normal
  69. nx = x - TORUS_MAJOR * cos(t * twopi / TORUS_MAJOR_RES);
  70. ny = y;
  71. nz = z - TORUS_MAJOR * sin(t * twopi / TORUS_MAJOR_RES);
  72. scale = 1.0 / sqrt(nx*nx + ny*ny + nz*nz);
  73. nx *= scale;
  74. ny *= scale;
  75. nz *= scale;
  76. glNormal3f((float) nx, (float) ny, (float) nz);
  77. glVertex3f((float) x, (float) y, (float) z);
  78. }
  79. }
  80. glEnd();
  81. }
  82. // Stop recording displaylist
  83. glEndList();
  84. }
  85. else
  86. {
  87. // Playback displaylist
  88. glCallList(torus_list);
  89. }
  90. }
  91. //========================================================================
  92. // Draw the scene (a rotating torus)
  93. //========================================================================
  94. static void drawScene(void)
  95. {
  96. const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f};
  97. const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f};
  98. const GLfloat model_shininess = 20.0f;
  99. glPushMatrix();
  100. // Rotate the object
  101. glRotatef((GLfloat) rot_x * 0.5f, 1.0f, 0.0f, 0.0f);
  102. glRotatef((GLfloat) rot_y * 0.5f, 0.0f, 1.0f, 0.0f);
  103. glRotatef((GLfloat) rot_z * 0.5f, 0.0f, 0.0f, 1.0f);
  104. // Set model color (used for orthogonal views, lighting disabled)
  105. glColor4fv(model_diffuse);
  106. // Set model material (used for perspective view, lighting enabled)
  107. glMaterialfv(GL_FRONT, GL_DIFFUSE, model_diffuse);
  108. glMaterialfv(GL_FRONT, GL_SPECULAR, model_specular);
  109. glMaterialf(GL_FRONT, GL_SHININESS, model_shininess);
  110. // Draw torus
  111. drawTorus();
  112. glPopMatrix();
  113. }
  114. //========================================================================
  115. // Draw a 2D grid (used for orthogonal views)
  116. //========================================================================
  117. static void drawGrid(float scale, int steps)
  118. {
  119. int i;
  120. float x, y;
  121. mat4x4 view;
  122. glPushMatrix();
  123. // Set background to some dark bluish grey
  124. glClearColor(0.05f, 0.05f, 0.2f, 0.0f);
  125. glClear(GL_COLOR_BUFFER_BIT);
  126. // Setup modelview matrix (flat XY view)
  127. {
  128. vec3 eye = { 0.f, 0.f, 1.f };
  129. vec3 center = { 0.f, 0.f, 0.f };
  130. vec3 up = { 0.f, 1.f, 0.f };
  131. mat4x4_look_at(view, eye, center, up);
  132. }
  133. glLoadMatrixf((const GLfloat*) view);
  134. // We don't want to update the Z-buffer
  135. glDepthMask(GL_FALSE);
  136. // Set grid color
  137. glColor3f(0.0f, 0.5f, 0.5f);
  138. glBegin(GL_LINES);
  139. // Horizontal lines
  140. x = scale * 0.5f * (float) (steps - 1);
  141. y = -scale * 0.5f * (float) (steps - 1);
  142. for (i = 0; i < steps; i++)
  143. {
  144. glVertex3f(-x, y, 0.0f);
  145. glVertex3f(x, y, 0.0f);
  146. y += scale;
  147. }
  148. // Vertical lines
  149. x = -scale * 0.5f * (float) (steps - 1);
  150. y = scale * 0.5f * (float) (steps - 1);
  151. for (i = 0; i < steps; i++)
  152. {
  153. glVertex3f(x, -y, 0.0f);
  154. glVertex3f(x, y, 0.0f);
  155. x += scale;
  156. }
  157. glEnd();
  158. // Enable Z-buffer writing again
  159. glDepthMask(GL_TRUE);
  160. glPopMatrix();
  161. }
  162. //========================================================================
  163. // Draw all views
  164. //========================================================================
  165. static void drawAllViews(void)
  166. {
  167. const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f};
  168. const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  169. const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  170. const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f};
  171. float aspect;
  172. mat4x4 view, projection;
  173. // Calculate aspect of window
  174. if (height > 0)
  175. aspect = (float) width / (float) height;
  176. else
  177. aspect = 1.f;
  178. // Clear screen
  179. glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  180. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  181. // Enable scissor test
  182. glEnable(GL_SCISSOR_TEST);
  183. // Enable depth test
  184. glEnable(GL_DEPTH_TEST);
  185. glDepthFunc(GL_LEQUAL);
  186. // ** ORTHOGONAL VIEWS **
  187. // For orthogonal views, use wireframe rendering
  188. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  189. // Enable line anti-aliasing
  190. glEnable(GL_LINE_SMOOTH);
  191. glEnable(GL_BLEND);
  192. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  193. // Setup orthogonal projection matrix
  194. glMatrixMode(GL_PROJECTION);
  195. glLoadIdentity();
  196. glOrtho(-3.0 * aspect, 3.0 * aspect, -3.0, 3.0, 1.0, 50.0);
  197. // Upper left view (TOP VIEW)
  198. glViewport(0, height / 2, width / 2, height / 2);
  199. glScissor(0, height / 2, width / 2, height / 2);
  200. glMatrixMode(GL_MODELVIEW);
  201. {
  202. vec3 eye = { 0.f, 10.f, 1e-3f };
  203. vec3 center = { 0.f, 0.f, 0.f };
  204. vec3 up = { 0.f, 1.f, 0.f };
  205. mat4x4_look_at( view, eye, center, up );
  206. }
  207. glLoadMatrixf((const GLfloat*) view);
  208. drawGrid(0.5, 12);
  209. drawScene();
  210. // Lower left view (FRONT VIEW)
  211. glViewport(0, 0, width / 2, height / 2);
  212. glScissor(0, 0, width / 2, height / 2);
  213. glMatrixMode(GL_MODELVIEW);
  214. {
  215. vec3 eye = { 0.f, 0.f, 10.f };
  216. vec3 center = { 0.f, 0.f, 0.f };
  217. vec3 up = { 0.f, 1.f, 0.f };
  218. mat4x4_look_at( view, eye, center, up );
  219. }
  220. glLoadMatrixf((const GLfloat*) view);
  221. drawGrid(0.5, 12);
  222. drawScene();
  223. // Lower right view (SIDE VIEW)
  224. glViewport(width / 2, 0, width / 2, height / 2);
  225. glScissor(width / 2, 0, width / 2, height / 2);
  226. glMatrixMode(GL_MODELVIEW);
  227. {
  228. vec3 eye = { 10.f, 0.f, 0.f };
  229. vec3 center = { 0.f, 0.f, 0.f };
  230. vec3 up = { 0.f, 1.f, 0.f };
  231. mat4x4_look_at( view, eye, center, up );
  232. }
  233. glLoadMatrixf((const GLfloat*) view);
  234. drawGrid(0.5, 12);
  235. drawScene();
  236. // Disable line anti-aliasing
  237. glDisable(GL_LINE_SMOOTH);
  238. glDisable(GL_BLEND);
  239. // ** PERSPECTIVE VIEW **
  240. // For perspective view, use solid rendering
  241. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  242. // Enable face culling (faster rendering)
  243. glEnable(GL_CULL_FACE);
  244. glCullFace(GL_BACK);
  245. glFrontFace(GL_CW);
  246. // Setup perspective projection matrix
  247. glMatrixMode(GL_PROJECTION);
  248. mat4x4_perspective(projection,
  249. 65.f * (float) M_PI / 180.f,
  250. aspect,
  251. 1.f, 50.f);
  252. glLoadMatrixf((const GLfloat*) projection);
  253. // Upper right view (PERSPECTIVE VIEW)
  254. glViewport(width / 2, height / 2, width / 2, height / 2);
  255. glScissor(width / 2, height / 2, width / 2, height / 2);
  256. glMatrixMode(GL_MODELVIEW);
  257. {
  258. vec3 eye = { 3.f, 1.5f, 3.f };
  259. vec3 center = { 0.f, 0.f, 0.f };
  260. vec3 up = { 0.f, 1.f, 0.f };
  261. mat4x4_look_at( view, eye, center, up );
  262. }
  263. glLoadMatrixf((const GLfloat*) view);
  264. // Configure and enable light source 1
  265. glLightfv(GL_LIGHT1, GL_POSITION, light_position);
  266. glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
  267. glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
  268. glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
  269. glEnable(GL_LIGHT1);
  270. glEnable(GL_LIGHTING);
  271. // Draw scene
  272. drawScene();
  273. // Disable lighting
  274. glDisable(GL_LIGHTING);
  275. // Disable face culling
  276. glDisable(GL_CULL_FACE);
  277. // Disable depth test
  278. glDisable(GL_DEPTH_TEST);
  279. // Disable scissor test
  280. glDisable(GL_SCISSOR_TEST);
  281. // Draw a border around the active view
  282. if (active_view > 0 && active_view != 2)
  283. {
  284. glViewport(0, 0, width, height);
  285. glMatrixMode(GL_PROJECTION);
  286. glLoadIdentity();
  287. glOrtho(0.0, 2.0, 0.0, 2.0, 0.0, 1.0);
  288. glMatrixMode(GL_MODELVIEW);
  289. glLoadIdentity();
  290. glTranslatef((GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f);
  291. glColor3f(1.0f, 1.0f, 0.6f);
  292. glBegin(GL_LINE_STRIP);
  293. glVertex2i(0, 0);
  294. glVertex2i(1, 0);
  295. glVertex2i(1, 1);
  296. glVertex2i(0, 1);
  297. glVertex2i(0, 0);
  298. glEnd();
  299. }
  300. }
  301. //========================================================================
  302. // Framebuffer size callback function
  303. //========================================================================
  304. static void framebufferSizeFun(GLFWwindow* window, int w, int h)
  305. {
  306. width = w;
  307. height = h > 0 ? h : 1;
  308. do_redraw = 1;
  309. }
  310. //========================================================================
  311. // Window refresh callback function
  312. //========================================================================
  313. static void windowRefreshFun(GLFWwindow* window)
  314. {
  315. drawAllViews();
  316. glfwSwapBuffers(window);
  317. do_redraw = 0;
  318. }
  319. //========================================================================
  320. // Mouse position callback function
  321. //========================================================================
  322. static void cursorPosFun(GLFWwindow* window, double x, double y)
  323. {
  324. int wnd_width, wnd_height, fb_width, fb_height;
  325. double scale;
  326. glfwGetWindowSize(window, &wnd_width, &wnd_height);
  327. glfwGetFramebufferSize(window, &fb_width, &fb_height);
  328. scale = (double) fb_width / (double) wnd_width;
  329. x *= scale;
  330. y *= scale;
  331. // Depending on which view was selected, rotate around different axes
  332. switch (active_view)
  333. {
  334. case 1:
  335. rot_x += (int) (y - ypos);
  336. rot_z += (int) (x - xpos);
  337. do_redraw = 1;
  338. break;
  339. case 3:
  340. rot_x += (int) (y - ypos);
  341. rot_y += (int) (x - xpos);
  342. do_redraw = 1;
  343. break;
  344. case 4:
  345. rot_y += (int) (x - xpos);
  346. rot_z += (int) (y - ypos);
  347. do_redraw = 1;
  348. break;
  349. default:
  350. // Do nothing for perspective view, or if no view is selected
  351. break;
  352. }
  353. // Remember cursor position
  354. xpos = x;
  355. ypos = y;
  356. }
  357. //========================================================================
  358. // Mouse button callback function
  359. //========================================================================
  360. static void mouseButtonFun(GLFWwindow* window, int button, int action, int mods)
  361. {
  362. if ((button == GLFW_MOUSE_BUTTON_LEFT) && action == GLFW_PRESS)
  363. {
  364. // Detect which of the four views was clicked
  365. active_view = 1;
  366. if (xpos >= width / 2)
  367. active_view += 1;
  368. if (ypos >= height / 2)
  369. active_view += 2;
  370. }
  371. else if (button == GLFW_MOUSE_BUTTON_LEFT)
  372. {
  373. // Deselect any previously selected view
  374. active_view = 0;
  375. }
  376. do_redraw = 1;
  377. }
  378. static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
  379. {
  380. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  381. glfwSetWindowShouldClose(window, GLFW_TRUE);
  382. }
  383. //========================================================================
  384. // main
  385. //========================================================================
  386. int main(void)
  387. {
  388. GLFWwindow* window;
  389. // Initialise GLFW
  390. if (!glfwInit())
  391. {
  392. fprintf(stderr, "Failed to initialize GLFW\n");
  393. exit(EXIT_FAILURE);
  394. }
  395. glfwWindowHint(GLFW_SAMPLES, 4);
  396. // Open OpenGL window
  397. window = glfwCreateWindow(500, 500, "Split view demo", NULL, NULL);
  398. if (!window)
  399. {
  400. fprintf(stderr, "Failed to open GLFW window\n");
  401. glfwTerminate();
  402. exit(EXIT_FAILURE);
  403. }
  404. // Set callback functions
  405. glfwSetFramebufferSizeCallback(window, framebufferSizeFun);
  406. glfwSetWindowRefreshCallback(window, windowRefreshFun);
  407. glfwSetCursorPosCallback(window, cursorPosFun);
  408. glfwSetMouseButtonCallback(window, mouseButtonFun);
  409. glfwSetKeyCallback(window, key_callback);
  410. // Enable vsync
  411. glfwMakeContextCurrent(window);
  412. gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
  413. glfwSwapInterval(1);
  414. if (GLAD_GL_ARB_multisample || GLAD_GL_VERSION_1_3)
  415. glEnable(GL_MULTISAMPLE_ARB);
  416. glfwGetFramebufferSize(window, &width, &height);
  417. framebufferSizeFun(window, width, height);
  418. // Main loop
  419. for (;;)
  420. {
  421. // Only redraw if we need to
  422. if (do_redraw)
  423. windowRefreshFun(window);
  424. // Wait for new events
  425. glfwWaitEvents();
  426. // Check if the window should be closed
  427. if (glfwWindowShouldClose(window))
  428. break;
  429. }
  430. // Close OpenGL window and terminate GLFW
  431. glfwTerminate();
  432. exit(EXIT_SUCCESS);
  433. }