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.
 
 
 

360 line
9.9 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 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://www.wtfpl.net/ for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstdlib>
  14. #ifdef WIN32
  15. # define WIN32_LEAN_AND_MEAN
  16. # include <windows.h>
  17. #endif
  18. #include "core.h"
  19. #include "lolgl.h"
  20. LOLFX_RESOURCE_DECLARE(tile);
  21. LOLFX_RESOURCE_DECLARE(line);
  22. namespace lol
  23. {
  24. struct Tile
  25. {
  26. TileSet *tileset;
  27. uint32_t prio;
  28. vec3 pos;
  29. vec2 scale;
  30. int id, o;
  31. };
  32. /*
  33. * Scene implementation class
  34. */
  35. class SceneData
  36. {
  37. friend class Scene;
  38. private:
  39. static int Compare(void const *p1, void const *p2)
  40. {
  41. Tile const *t1 = (Tile const *)p1;
  42. Tile const *t2 = (Tile const *)p2;
  43. if (t1->pos.z > t2->pos.z)
  44. return 1;
  45. if (t1->pos.z < t2->pos.z)
  46. return -1;
  47. return 0;
  48. }
  49. Array<vec3, vec3, vec4> m_lines;
  50. Shader *m_line_shader;
  51. VertexDeclaration *m_line_vdecl;
  52. Array<Tile> m_tiles;
  53. Array<Light *> m_lights;
  54. Shader *m_tile_shader;
  55. VertexDeclaration *m_tile_vdecl;
  56. Array<VertexBuffer *> m_tile_bufs;
  57. Camera *m_default_cam;
  58. Array<Camera *> m_camera_stack;
  59. static Scene *scene;
  60. };
  61. Scene *SceneData::scene = nullptr;
  62. /*
  63. * Public Scene class
  64. */
  65. Scene::Scene()
  66. : data(new SceneData())
  67. {
  68. /* Create a default orthographic camera, in case the user doesn’t. */
  69. data->m_default_cam = new Camera();
  70. mat4 proj = mat4::ortho(0, Video::GetSize().x, 0, Video::GetSize().y,
  71. -1000.f, 1000.f);
  72. data->m_default_cam->SetProjection(proj);
  73. PushCamera(data->m_default_cam);
  74. data->m_tile_shader = 0;
  75. data->m_tile_vdecl = new VertexDeclaration(VertexStream<vec3>(VertexUsage::Position),
  76. VertexStream<vec2>(VertexUsage::TexCoord));
  77. data->m_line_shader = 0;
  78. data->m_line_vdecl = new VertexDeclaration(VertexStream<vec3,vec4>(VertexUsage::Position, VertexUsage::Color));
  79. }
  80. Scene::~Scene()
  81. {
  82. PopCamera(data->m_default_cam);
  83. /* FIXME: this must be done while the GL context is still active.
  84. * Change the code architecture to make sure of that. */
  85. /* FIXME: also, make sure we do not add code to Reset() that will
  86. * reallocate stuff */
  87. Reset();
  88. delete data->m_line_vdecl;
  89. delete data->m_tile_vdecl;
  90. delete data;
  91. }
  92. Scene *Scene::GetDefault()
  93. {
  94. if (!SceneData::scene)
  95. SceneData::scene = new Scene();
  96. return SceneData::scene;
  97. }
  98. void Scene::PushCamera(Camera *cam)
  99. {
  100. Ticker::Ref(cam);
  101. data->m_camera_stack.Push(cam);
  102. }
  103. void Scene::PopCamera(Camera *cam)
  104. {
  105. /* Parse from the end because that’s probably where we’ll find
  106. * our camera first. */
  107. for (int i = data->m_camera_stack.Count(); i--; )
  108. {
  109. if (data->m_camera_stack[i] == cam)
  110. {
  111. Ticker::Unref(cam);
  112. data->m_camera_stack.Remove(i);
  113. return;
  114. }
  115. }
  116. ASSERT(false, "trying to pop a nonexistent camera from the scene");
  117. }
  118. Camera *Scene::GetCamera()
  119. {
  120. return data->m_camera_stack.Last();
  121. }
  122. void Scene::Reset()
  123. {
  124. for (int i = 0; i < data->m_tile_bufs.Count(); i++)
  125. delete data->m_tile_bufs[i];
  126. data->m_tile_bufs.Empty();
  127. data->m_lights.Empty();
  128. }
  129. void Scene::AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale)
  130. {
  131. ASSERT(id < tileset->GetTileCount());
  132. Tile t;
  133. /* FIXME: this sorting only works for a 45-degree camera */
  134. t.prio = -pos.y - 2 * 32 * pos.z + (o ? 0 : 32);
  135. t.tileset = tileset;
  136. t.id = id;
  137. t.pos = pos;
  138. t.o = o;
  139. t.scale = scale;
  140. data->m_tiles.Push(t);
  141. }
  142. void Scene::AddLine(vec3 a, vec3 b, vec4 color)
  143. {
  144. data->m_lines.Push(a, b, color);
  145. }
  146. void Scene::AddLight(Light *l)
  147. {
  148. data->m_lights.Push(l);
  149. }
  150. Array<Light *> const &Scene::GetLights() const
  151. {
  152. return data->m_lights;
  153. }
  154. void Scene::Render() // XXX: rename to Blit()
  155. {
  156. #if defined USE_D3D9 || defined _XBOX
  157. #else
  158. glEnable(GL_DEPTH_TEST);
  159. glDepthFunc(GL_LEQUAL);
  160. #if defined HAVE_GL_2X && !defined __APPLE__
  161. glEnable(GL_ALPHA_TEST);
  162. glAlphaFunc(GL_GEQUAL, 0.01f);
  163. #endif
  164. glEnable(GL_BLEND);
  165. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  166. #endif
  167. /* Early test if nothing needs to be rendered */
  168. if (data->m_tiles.Count())
  169. {
  170. #if defined USE_D3D9 || defined _XBOX
  171. #elif !defined HAVE_GLES_2X
  172. glEnable(GL_TEXTURE_2D);
  173. #endif
  174. if (!data->m_tile_shader)
  175. data->m_tile_shader = Shader::Create(LOLFX_RESOURCE_NAME(tile));
  176. #if 0
  177. // Randomise, then sort.
  178. for (int i = 0; i < data->m_tiles.Count(); i++)
  179. {
  180. Tile tmp = data->m_tiles[i];
  181. int j = rand<int>() % data->m_tiles.Count();
  182. data->m_tiles[i] = data->m_tiles[j];
  183. data->m_tiles[j] = tmp;
  184. }
  185. #endif
  186. qsort(&data->m_tiles[0], data->m_tiles.Count(),
  187. sizeof(Tile), SceneData::Compare);
  188. ShaderUniform uni_mat, uni_tex, uni_texsize;
  189. ShaderAttrib attr_pos, attr_tex;
  190. attr_pos = data->m_tile_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0);
  191. attr_tex = data->m_tile_shader->GetAttribLocation("in_TexCoord", VertexUsage::TexCoord, 0);
  192. data->m_tile_shader->Bind();
  193. uni_mat = data->m_tile_shader->GetUniformLocation("proj_matrix");
  194. data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  195. uni_mat = data->m_tile_shader->GetUniformLocation("view_matrix");
  196. data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetView());
  197. uni_mat = data->m_tile_shader->GetUniformLocation("model_matrix");
  198. data->m_tile_shader->SetUniform(uni_mat, mat4(1.f));
  199. uni_tex = data->m_tile_shader->GetUniformLocation("in_Texture");
  200. data->m_tile_shader->SetUniform(uni_tex, 0);
  201. uni_texsize = data->m_tile_shader->GetUniformLocation("in_TexSize");
  202. for (int buf = 0, i = 0, n; i < data->m_tiles.Count(); i = n, buf += 2)
  203. {
  204. /* Count how many quads will be needed */
  205. for (n = i + 1; n < data->m_tiles.Count(); n++)
  206. if (data->m_tiles[i].tileset != data->m_tiles[n].tileset)
  207. break;
  208. /* Create a vertex array object */
  209. VertexBuffer *vb1 = new VertexBuffer(6 * 3 * (n - i) * sizeof(float));
  210. float *vertex = (float *)vb1->Lock(0, 0);
  211. VertexBuffer *vb2 = new VertexBuffer(6 * 2 * (n - i) * sizeof(float));
  212. float *texture = (float *)vb2->Lock(0, 0);
  213. data->m_tile_bufs.Push(vb1);
  214. data->m_tile_bufs.Push(vb2);
  215. for (int j = i; j < n; j++)
  216. {
  217. data->m_tiles[i].tileset->BlitTile(data->m_tiles[j].id,
  218. data->m_tiles[j].pos, data->m_tiles[j].o,
  219. data->m_tiles[j].scale,
  220. vertex + 18 * (j - i), texture + 12 * (j - i));
  221. }
  222. vb1->Unlock();
  223. vb2->Unlock();
  224. /* Bind texture */
  225. data->m_tiles[i].tileset->Bind();
  226. data->m_tile_shader->SetUniform(uni_texsize,
  227. (vec2)data->m_tiles[i].tileset->GetTextureSize());
  228. /* Bind vertex and texture coordinate buffers */
  229. data->m_tile_vdecl->Bind();
  230. data->m_tile_vdecl->SetStream(vb1, attr_pos);
  231. data->m_tile_vdecl->SetStream(vb2, attr_tex);
  232. /* Draw arrays */
  233. data->m_tile_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6);
  234. data->m_tile_vdecl->Unbind();
  235. data->m_tiles[i].tileset->Unbind();
  236. }
  237. data->m_tiles.Empty();
  238. data->m_tile_shader->Unbind();
  239. #if defined USE_D3D9 || defined _XBOX
  240. /* TODO */
  241. #elif !defined HAVE_GLES_2X
  242. glDisable(GL_TEXTURE_2D);
  243. #endif
  244. }
  245. if (data->m_lines.Count())
  246. {
  247. int linecount = data->m_lines.Count();
  248. if (!data->m_line_shader)
  249. data->m_line_shader = Shader::Create(LOLFX_RESOURCE_NAME(line));
  250. VertexBuffer *vb = new VertexBuffer((sizeof(vec3) + sizeof(vec4)) * 2 * linecount);
  251. float *vertex = (float *)vb->Lock(0, 0);
  252. for (int i = 0; i < linecount; i++)
  253. {
  254. memcpy(vertex, &data->m_lines[i].m1, sizeof(vec3));
  255. vertex += 3;
  256. memcpy(vertex, &data->m_lines[i].m3, sizeof(vec4));
  257. vertex += 4;
  258. memcpy(vertex, &data->m_lines[i].m2, sizeof(vec3));
  259. vertex += 3;
  260. memcpy(vertex, &data->m_lines[i].m3, sizeof(vec4));
  261. vertex += 4;
  262. }
  263. vb->Unlock();
  264. data->m_line_shader->Bind();
  265. ShaderUniform uni_mat, uni_tex;
  266. ShaderAttrib attr_pos, attr_col;
  267. attr_pos = data->m_line_shader->GetAttribLocation("in_Position", VertexUsage::Position, 0);
  268. attr_col = data->m_line_shader->GetAttribLocation("in_Color", VertexUsage::Color, 0);
  269. data->m_line_shader->Bind();
  270. uni_mat = data->m_line_shader->GetUniformLocation("proj_matrix");
  271. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  272. uni_mat = data->m_line_shader->GetUniformLocation("view_matrix");
  273. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetView());
  274. data->m_line_vdecl->Bind();
  275. data->m_line_vdecl->SetStream(vb, attr_pos, attr_col);
  276. data->m_line_vdecl->DrawElements(MeshPrimitive::Lines, 0, 2 * linecount);
  277. data->m_line_vdecl->Unbind();
  278. data->m_line_shader->Unbind();
  279. data->m_lines.Empty();
  280. delete vb;
  281. }
  282. #if defined USE_D3D9 || defined _XBOX
  283. /* TODO */
  284. #else
  285. glDisable(GL_DEPTH_TEST);
  286. # if defined HAVE_GL_2X && !defined __APPLE__
  287. glDisable(GL_ALPHA_TEST);
  288. # endif
  289. glDisable(GL_BLEND);
  290. #endif
  291. }
  292. } /* namespace lol */