278 lines
7.4 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstdlib>
  14. #include <cstdio>
  15. #include <cmath>
  16. #ifdef WIN32
  17. # define WIN32_LEAN_AND_MEAN
  18. # include <windows.h>
  19. #endif
  20. #if defined __APPLE__ && defined __MACH__
  21. # include <OpenGL/gl.h>
  22. #else
  23. # define GL_GLEXT_PROTOTYPES
  24. # include <GL/gl.h>
  25. #endif
  26. #include "core.h"
  27. struct Tile
  28. {
  29. uint32_t prio, code;
  30. int x, y, z, o;
  31. };
  32. #if LOL_EXPERIMENTAL
  33. extern Shader *stdshader;
  34. #endif
  35. extern mat4 model_matrix;
  36. /*
  37. * Scene implementation class
  38. */
  39. class SceneData
  40. {
  41. friend class Scene;
  42. private:
  43. static int Compare(void const *p1, void const *p2)
  44. {
  45. Tile const *t1 = (Tile const *)p1;
  46. Tile const *t2 = (Tile const *)p2;
  47. return t2->prio - t1->prio;
  48. }
  49. Tile *tiles;
  50. int ntiles;
  51. float angle;
  52. GLuint *bufs;
  53. int nbufs;
  54. static Scene *scene;
  55. };
  56. Scene *SceneData::scene = NULL;
  57. /*
  58. * Public Scene class
  59. */
  60. Scene::Scene(float angle)
  61. : data(new SceneData())
  62. {
  63. data->tiles = 0;
  64. data->ntiles = 0;
  65. data->angle = angle;
  66. data->bufs = 0;
  67. data->nbufs = 0;
  68. }
  69. Scene::~Scene()
  70. {
  71. /* FIXME: this must be done while the GL context is still active.
  72. * Change the architecture to make sure of that. */
  73. glDeleteBuffers(data->nbufs, data->bufs);
  74. delete data;
  75. }
  76. Scene *Scene::GetDefault()
  77. {
  78. if (!SceneData::scene)
  79. SceneData::scene = new Scene(0.0f);
  80. return SceneData::scene;
  81. }
  82. void Scene::Reset()
  83. {
  84. if (SceneData::scene)
  85. delete SceneData::scene;
  86. SceneData::scene = NULL;
  87. }
  88. void Scene::AddTile(uint32_t code, int x, int y, int z, int o)
  89. {
  90. if ((data->ntiles % 1024) == 0)
  91. data->tiles = (Tile *)realloc(data->tiles,
  92. (data->ntiles + 1024) * sizeof(Tile));
  93. /* FIXME: this sorting only works for a 45-degree camera */
  94. data->tiles[data->ntiles].prio = -y - 2 * 32 * z + (o ? 0 : 32);
  95. data->tiles[data->ntiles].code = code;
  96. data->tiles[data->ntiles].x = x;
  97. data->tiles[data->ntiles].y = y;
  98. data->tiles[data->ntiles].z = z;
  99. data->tiles[data->ntiles].o = o;
  100. data->ntiles++;
  101. }
  102. void Scene::Render() // XXX: rename to Blit()
  103. {
  104. #if 0
  105. // Randomise, then sort.
  106. for (int i = 0; i < data->ntiles; i++)
  107. {
  108. Tile tmp = data->tiles[i];
  109. int j = rand() % data->ntiles;
  110. data->tiles[i] = data->tiles[j];
  111. data->tiles[j] = tmp;
  112. }
  113. #endif
  114. qsort(data->tiles, data->ntiles, sizeof(Tile), SceneData::Compare);
  115. // XXX: debug stuff
  116. model_matrix = mat4::translate(320.0f, 240.0f, 0.0f);
  117. model_matrix *= mat4::rotate(-data->angle, 1.0f, 0.0f, 0.0f);
  118. #if 0
  119. static float f = 0.0f;
  120. f += 0.01f;
  121. model_matrix *= mat4::rotate(0.1f * sinf(f), 1.0f, 0.0f, 0.0f);
  122. model_matrix *= mat4::rotate(0.3f * cosf(f), 0.0f, 0.0f, 1.0f);
  123. #endif
  124. model_matrix *= mat4::translate(-320.0f, -240.0f, 0.0f);
  125. // XXX: end of debug stuff
  126. #if LOL_EXPERIMENTAL
  127. GLuint uni;
  128. uni = stdshader->GetUniformLocation("model_matrix");
  129. glUniformMatrix4fv(uni, 1, GL_FALSE, &model_matrix[0][0]);
  130. float *vertices = new float[18];
  131. vertices[0] = 0.0f; vertices[1] = 480.0f; vertices[2] = 0.0f;
  132. vertices[3] = 640.0f; vertices[4] = 480.0f; vertices[5] = 0.0f;
  133. vertices[6] = 0.0f; vertices[7] = 0.0f; vertices[8] = 0.0f;
  134. vertices[9] = 640.0f; vertices[10] = 0.0f; vertices[11] = 0.0f;
  135. vertices[12] = 0.0f; vertices[13] = 0.0f; vertices[14] = 0.0f;
  136. vertices[15] = 640.0f; vertices[16] = 480.0f; vertices[17] = 0.0f;
  137. const GLfloat colors[6][3] = {
  138. { 0.0, 0.0, 1.0 },
  139. { 1.0, 0.0, 0.0 },
  140. { 0.0, 1.0, 0.0 },
  141. { 1.0, 1.0, 0.0 },
  142. { 0.0, 1.0, 0.0 },
  143. { 1.0, 0.0, 0.0 } };
  144. const GLfloat tex[6][2] = {
  145. { 0.0, 0.0 },
  146. { 1.0, 0.0 },
  147. { 0.0, 1.0 },
  148. { 1.0, 1.0 },
  149. { 0.0, 1.0 },
  150. { 1.0, 0.0 } };
  151. GLuint vao, vbo[3], attr;
  152. glGenVertexArrays(1, &vao);
  153. glBindVertexArray(vao);
  154. glGenBuffers(3, &vbo[0]);
  155. attr = stdshader->GetAttribLocation("in_Position");
  156. glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
  157. glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
  158. glVertexAttribPointer(attr, 3, GL_FLOAT, GL_FALSE, 0, 0);
  159. glEnableVertexAttribArray(attr);
  160. attr = stdshader->GetAttribLocation("in_Color");
  161. glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
  162. glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), colors, GL_STATIC_DRAW);
  163. glVertexAttribPointer(attr, 3, GL_FLOAT, GL_FALSE, 0, 0);
  164. glEnableVertexAttribArray(attr);
  165. attr = stdshader->GetAttribLocation("in_TexCoord");
  166. glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
  167. glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), tex, GL_STATIC_DRAW);
  168. glVertexAttribPointer(attr, 2, GL_FLOAT, GL_FALSE, 0, 0);
  169. glEnableVertexAttribArray(attr);
  170. delete[] vertices;
  171. stdshader->Bind();
  172. glBindVertexArray(vao);
  173. Tiler::Bind(1 << 16);
  174. glDrawArrays(GL_TRIANGLES, 0, 6);
  175. glBindVertexArray(0);
  176. #else
  177. glEnable(GL_DEPTH_TEST);
  178. glDepthFunc(GL_LEQUAL);
  179. glEnable(GL_ALPHA_TEST);
  180. glAlphaFunc(GL_GEQUAL, 0.01f);
  181. glEnable(GL_BLEND);
  182. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  183. glLoadIdentity();
  184. glMultMatrixf(&model_matrix[0][0]);
  185. for (int buf = 0, i = 0, n; i < data->ntiles; i = n, buf += 2)
  186. {
  187. /* Generate new vertex / texture coord buffers if necessary */
  188. if (buf + 2 > data->nbufs)
  189. {
  190. data->bufs = (GLuint *)realloc(data->bufs, (buf + 2) * sizeof(GLuint));
  191. glGenBuffers(buf + 2 - data->nbufs, data->bufs + data->nbufs);
  192. data->nbufs = buf + 2;
  193. }
  194. /* Count how many quads will be needed */
  195. for (n = i + 1; n < data->ntiles; n++)
  196. if (data->tiles[i].code >> 16 != data->tiles[n].code >> 16)
  197. break;
  198. /* Create a vertex array object */
  199. float *vertex = (float *)malloc(6 * 3 * (n - i) * sizeof(float));
  200. float *texture = (float *)malloc(6 * 2 * (n - i) * sizeof(float));
  201. for (int j = i; j < n; j++)
  202. {
  203. Tiler::BlitTile(data->tiles[j].code, data->tiles[j].x,
  204. data->tiles[j].y, data->tiles[j].z, data->tiles[j].o,
  205. vertex + 18 * (j - i), texture + 12 * (j - i));
  206. }
  207. glEnableClientState(GL_VERTEX_ARRAY);
  208. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  209. glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf]);
  210. glBufferData(GL_ARRAY_BUFFER, 6 * 3 * (n - i) * sizeof(float),
  211. vertex, GL_DYNAMIC_DRAW);
  212. glVertexPointer(3, GL_FLOAT, 0, NULL);
  213. glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf + 1]);
  214. glBufferData(GL_ARRAY_BUFFER, 6 * 2 * (n - i) * sizeof(float),
  215. texture, GL_DYNAMIC_DRAW);
  216. glTexCoordPointer(2, GL_FLOAT, 0, NULL);
  217. Tiler::Bind(data->tiles[i].code);
  218. glDrawArrays(GL_TRIANGLES, 0, (n - i) * 6);
  219. glDisableClientState(GL_VERTEX_ARRAY);
  220. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  221. free(vertex);
  222. free(texture);
  223. }
  224. #endif
  225. free(data->tiles);
  226. data->tiles = 0;
  227. data->ntiles = 0;
  228. }