402 rivejä
11 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 HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstdlib>
  14. #if WIN32
  15. # define WIN32_LEAN_AND_MEAN 1
  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. /*
  25. * The global g_scene object, initialised by Video::Init
  26. */
  27. Scene *g_scene = nullptr;
  28. /*
  29. * A quick and dirty Tile structure for 2D blits
  30. */
  31. struct Tile
  32. {
  33. TileSet *tileset;
  34. uint32_t prio;
  35. vec3 pos;
  36. vec2 scale;
  37. int id, o;
  38. };
  39. /*
  40. * Scene implementation class
  41. */
  42. class SceneData
  43. {
  44. friend class Scene;
  45. private:
  46. /* New scenegraph */
  47. Array<Primitive> m_primitives;
  48. /* Old API <P0, P1, COLOR, TIME, MASK> */
  49. float m_new_line_time;
  50. int m_new_line_mask;
  51. Array<vec3, vec3, vec4, float, int> m_lines;
  52. int m_debug_mask;
  53. Shader *m_line_shader;
  54. VertexDeclaration *m_line_vdecl;
  55. Array<Tile> m_tiles;
  56. Array<Light *> m_lights;
  57. Shader *m_tile_shader;
  58. VertexDeclaration *m_tile_vdecl;
  59. Array<VertexBuffer *> m_tile_bufs;
  60. Camera *m_default_cam;
  61. Array<Camera *> m_camera_stack;
  62. };
  63. /*
  64. * Public Scene class
  65. */
  66. Scene::Scene(ivec2 size)
  67. : data(new SceneData())
  68. {
  69. /* Create a default orthographic camera, in case the user doesn’t. */
  70. data->m_default_cam = new Camera();
  71. mat4 proj = mat4::ortho(0.f, size.x, 0.f, size.y, -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. data->m_debug_mask = 1;
  80. SetLineTime();
  81. SetLineMask();
  82. }
  83. Scene::~Scene()
  84. {
  85. PopCamera(data->m_default_cam);
  86. /* FIXME: this must be done while the GL context is still active.
  87. * Change the code architecture to make sure of that. */
  88. /* FIXME: also, make sure we do not add code to Reset() that will
  89. * reallocate stuff */
  90. Reset();
  91. delete data->m_line_vdecl;
  92. delete data->m_tile_vdecl;
  93. delete data;
  94. }
  95. void Scene::PushCamera(Camera *cam)
  96. {
  97. ASSERT(this, "trying to push a camera before g_scene is ready");
  98. Ticker::Ref(cam);
  99. data->m_camera_stack.Push(cam);
  100. }
  101. void Scene::PopCamera(Camera *cam)
  102. {
  103. ASSERT(this, "trying to pop a camera before g_scene is ready");
  104. /* Parse from the end because that’s probably where we’ll find
  105. * our camera first. */
  106. for (int i = data->m_camera_stack.Count(); i--; )
  107. {
  108. if (data->m_camera_stack[i] == cam)
  109. {
  110. Ticker::Unref(cam);
  111. data->m_camera_stack.Remove(i);
  112. return;
  113. }
  114. }
  115. ASSERT(false, "trying to pop a nonexistent camera from the scene");
  116. }
  117. Camera *Scene::GetCamera()
  118. {
  119. return data->m_camera_stack.Last();
  120. }
  121. void Scene::Reset()
  122. {
  123. for (int i = 0; i < data->m_tile_bufs.Count(); i++)
  124. delete data->m_tile_bufs[i];
  125. data->m_tile_bufs.Empty();
  126. data->m_lights.Empty();
  127. }
  128. void Scene::AddPrimitive(Mesh *mesh, Shader *shader, mat4 const &matrix)
  129. {
  130. data->m_primitives.Push(Primitive(mesh, shader, matrix));
  131. }
  132. void Scene::AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale)
  133. {
  134. ASSERT(id < tileset->GetTileCount());
  135. Tile t;
  136. /* FIXME: this sorting only works for a 45-degree camera */
  137. t.prio = -pos.y - 2 * 32 * pos.z + ((float)o ? 0 : 32);
  138. t.tileset = tileset;
  139. t.id = id;
  140. t.pos = pos;
  141. t.o = o;
  142. t.scale = scale;
  143. data->m_tiles.Push(t);
  144. }
  145. void Scene::SetLineTime(float new_time)
  146. {
  147. data->m_new_line_time = new_time;
  148. }
  149. void Scene::SetLineMask(int new_mask)
  150. {
  151. data->m_new_line_mask = new_mask;
  152. }
  153. void Scene::AddLine(vec3 a, vec3 b, vec4 color)
  154. {
  155. data->m_lines.Push(a, b, color, data->m_new_line_time, data->m_new_line_mask);
  156. }
  157. void Scene::AddLight(Light *l)
  158. {
  159. data->m_lights.Push(l);
  160. }
  161. Array<Light *> const &Scene::GetLights() const
  162. {
  163. return data->m_lights;
  164. }
  165. void Scene::RenderPrimitives()
  166. {
  167. /* TODO: this should be the main entry for rendering of all
  168. * primitives found in the scene graph. When we have one. */
  169. Shader *shader = nullptr;
  170. ShaderUniform u_model, uni_tex, uni_texsize;
  171. ShaderAttrib a_pos, a_tex;
  172. for (int i = 0; i < data->m_primitives.Count(); ++i)
  173. {
  174. Primitive &p = data->m_primitives[i];
  175. /* If this primitive uses a new shader, update attributes */
  176. if (p.m_shader != shader)
  177. {
  178. shader = p.m_shader;
  179. a_pos = shader->GetAttribLocation(VertexUsage::Position, 0);
  180. a_tex = shader->GetAttribLocation(VertexUsage::TexCoord, 0);
  181. shader->Bind();
  182. ShaderUniform u_mat;
  183. u_mat = shader->GetUniformLocation("u_projection");
  184. shader->SetUniform(u_mat, GetCamera()->GetProjection());
  185. u_mat = shader->GetUniformLocation("u_view");
  186. shader->SetUniform(u_mat, GetCamera()->GetView());
  187. u_model = shader->GetUniformLocation("u_model");
  188. }
  189. shader->SetUniform(u_model, p.m_matrix);
  190. }
  191. }
  192. void Scene::RenderTiles() // XXX: rename to Blit()
  193. {
  194. RenderContext rc;
  195. /* Early test if nothing needs to be rendered */
  196. if (!data->m_tiles.Count())
  197. return;
  198. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  199. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  200. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  201. #if defined USE_D3D9 || defined _XBOX
  202. #elif !defined HAVE_GLES_2X
  203. glEnable(GL_TEXTURE_2D);
  204. #endif
  205. if (!data->m_tile_shader)
  206. data->m_tile_shader = Shader::Create(LOLFX_RESOURCE_NAME(tile));
  207. ShaderUniform uni_mat, uni_tex, uni_texsize;
  208. ShaderAttrib attr_pos, attr_tex;
  209. attr_pos = data->m_tile_shader->GetAttribLocation(VertexUsage::Position, 0);
  210. attr_tex = data->m_tile_shader->GetAttribLocation(VertexUsage::TexCoord, 0);
  211. data->m_tile_shader->Bind();
  212. uni_mat = data->m_tile_shader->GetUniformLocation("u_projection");
  213. data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  214. uni_mat = data->m_tile_shader->GetUniformLocation("u_view");
  215. data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetView());
  216. uni_mat = data->m_tile_shader->GetUniformLocation("u_model");
  217. data->m_tile_shader->SetUniform(uni_mat, mat4(1.f));
  218. uni_tex = data->m_tile_shader->GetUniformLocation("u_texture");
  219. data->m_tile_shader->SetUniform(uni_tex, 0);
  220. uni_texsize = data->m_tile_shader->GetUniformLocation("u_texsize");
  221. for (int buf = 0, i = 0, n; i < data->m_tiles.Count(); i = n, buf += 2)
  222. {
  223. /* Count how many quads will be needed */
  224. for (n = i + 1; n < data->m_tiles.Count(); n++)
  225. if (data->m_tiles[i].tileset != data->m_tiles[n].tileset)
  226. break;
  227. /* Create a vertex array object */
  228. VertexBuffer *vb1 = new VertexBuffer(6 * 3 * (n - i) * sizeof(float));
  229. float *vertex = (float *)vb1->Lock(0, 0);
  230. VertexBuffer *vb2 = new VertexBuffer(6 * 2 * (n - i) * sizeof(float));
  231. float *texture = (float *)vb2->Lock(0, 0);
  232. data->m_tile_bufs.Push(vb1);
  233. data->m_tile_bufs.Push(vb2);
  234. for (int j = i; j < n; j++)
  235. {
  236. data->m_tiles[i].tileset->BlitTile(data->m_tiles[j].id,
  237. data->m_tiles[j].pos, data->m_tiles[j].o,
  238. data->m_tiles[j].scale,
  239. vertex + 18 * (j - i), texture + 12 * (j - i));
  240. }
  241. vb1->Unlock();
  242. vb2->Unlock();
  243. /* Bind texture */
  244. data->m_tiles[i].tileset->Bind();
  245. data->m_tile_shader->SetUniform(uni_texsize,
  246. (vec2)data->m_tiles[i].tileset->GetTextureSize());
  247. /* Bind vertex and texture coordinate buffers */
  248. data->m_tile_vdecl->Bind();
  249. data->m_tile_vdecl->SetStream(vb1, attr_pos);
  250. data->m_tile_vdecl->SetStream(vb2, attr_tex);
  251. /* Draw arrays */
  252. data->m_tile_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6);
  253. data->m_tile_vdecl->Unbind();
  254. data->m_tiles[i].tileset->Unbind();
  255. }
  256. data->m_tiles.Empty();
  257. data->m_tile_shader->Unbind();
  258. #if defined USE_D3D9 || defined _XBOX
  259. /* TODO */
  260. #elif !defined HAVE_GLES_2X
  261. glDisable(GL_TEXTURE_2D);
  262. #endif
  263. }
  264. void Scene::RenderLines(float seconds) // XXX: rename to Blit()
  265. {
  266. RenderContext rc;
  267. if (!data->m_lines.Count())
  268. return;
  269. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  270. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  271. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  272. int linecount = data->m_lines.Count();
  273. if (!data->m_line_shader)
  274. data->m_line_shader = Shader::Create(LOLFX_RESOURCE_NAME(line));
  275. Array<vec3, vec4, vec3, vec4> buff;
  276. buff.Resize(linecount);
  277. int real_linecount = 0;
  278. for (int i = 0; i < linecount; i++)
  279. {
  280. if (data->m_lines[i].m5 & data->m_debug_mask)
  281. {
  282. buff[real_linecount].m1 = data->m_lines[i].m1;
  283. buff[real_linecount].m2 = data->m_lines[i].m3;
  284. buff[real_linecount].m3 = data->m_lines[i].m2;
  285. buff[real_linecount].m4 = data->m_lines[i].m3;
  286. real_linecount++;
  287. }
  288. data->m_lines[i].m4 -= seconds;
  289. if (data->m_lines[i].m4 < 0.f)
  290. {
  291. data->m_lines.RemoveSwap(i--);
  292. linecount--;
  293. }
  294. }
  295. int vb_size = (sizeof(vec3) + sizeof(vec4)) * 2 * real_linecount;
  296. VertexBuffer *vb = new VertexBuffer(vb_size);
  297. float *vertex = (float *)vb->Lock(0, 0);
  298. memcpy(vertex, buff.Data(), vb_size);
  299. vb->Unlock();
  300. data->m_line_shader->Bind();
  301. ShaderUniform uni_mat, uni_tex;
  302. ShaderAttrib attr_pos, attr_col;
  303. attr_pos = data->m_line_shader->GetAttribLocation(VertexUsage::Position, 0);
  304. attr_col = data->m_line_shader->GetAttribLocation(VertexUsage::Color, 0);
  305. data->m_line_shader->Bind();
  306. uni_mat = data->m_line_shader->GetUniformLocation("u_projection");
  307. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  308. uni_mat = data->m_line_shader->GetUniformLocation("u_view");
  309. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetView());
  310. data->m_line_vdecl->Bind();
  311. data->m_line_vdecl->SetStream(vb, attr_pos, attr_col);
  312. data->m_line_vdecl->DrawElements(MeshPrimitive::Lines, 0, 2 * real_linecount);
  313. data->m_line_vdecl->Unbind();
  314. data->m_line_shader->Unbind();
  315. //data->m_lines.Empty();
  316. delete vb;
  317. }
  318. } /* namespace lol */