Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

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