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.
 
 
 

486 lines
15 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2014 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. #include <lol/engine-internal.h>
  11. #include <cstdlib>
  12. #if defined(_WIN32)
  13. # define WIN32_LEAN_AND_MEAN 1
  14. # include <windows.h>
  15. #endif
  16. #include "lolgl.h"
  17. LOLFX_RESOURCE_DECLARE(tile);
  18. LOLFX_RESOURCE_DECLARE(palette);
  19. LOLFX_RESOURCE_DECLARE(line);
  20. namespace lol
  21. {
  22. /*
  23. * The global g_scene object, initialised by Video::Init
  24. */
  25. Scene *g_scene = nullptr;
  26. /*
  27. * A quick and dirty Tile structure for 2D blits
  28. */
  29. struct Tile
  30. {
  31. TileSet *tileset;
  32. uint32_t prio;
  33. vec3 pos;
  34. vec2 scale;
  35. float angle;
  36. int id, o;
  37. };
  38. /*
  39. * Scene implementation class
  40. */
  41. class SceneData
  42. {
  43. friend class Scene;
  44. private:
  45. /* New scenegraph */
  46. array<Primitive> m_primitives;
  47. /* Old API <P0, P1, COLOR, TIME, MASK> */
  48. float m_new_line_time;
  49. int m_new_line_mask;
  50. float m_new_line_segment_size;
  51. vec4 m_new_line_color;
  52. array<vec3, vec3, vec4, float, int, bool, bool> m_lines;
  53. int m_debug_mask;
  54. Shader *m_line_shader;
  55. VertexDeclaration *m_line_vdecl;
  56. int m_tile_cam;
  57. array<Tile> m_tiles;
  58. array<Tile> m_palettes;
  59. array<Light *> m_lights;
  60. Shader *m_tile_shader;
  61. Shader *m_palette_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_palette_shader = 0;
  81. data->m_tile_vdecl = new VertexDeclaration(VertexStream<vec3>(VertexUsage::Position),
  82. VertexStream<vec2>(VertexUsage::TexCoord));
  83. data->m_line_shader = 0;
  84. data->m_line_vdecl = new VertexDeclaration(VertexStream<vec4,vec4>(VertexUsage::Position, VertexUsage::Color));
  85. data->m_debug_mask = 1;
  86. SetLineTime();
  87. SetLineMask();
  88. SetLineSegmentSize();
  89. SetLineColor();
  90. }
  91. Scene::~Scene()
  92. {
  93. PopCamera(data->m_default_cam);
  94. /* FIXME: this must be done while the GL context is still active.
  95. * Change the code architecture to make sure of that. */
  96. /* FIXME: also, make sure we do not add code to Reset() that will
  97. * reallocate stuff */
  98. Reset();
  99. delete data->m_line_vdecl;
  100. delete data->m_tile_vdecl;
  101. delete data;
  102. }
  103. int Scene::PushCamera(Camera *cam)
  104. {
  105. ASSERT(this, "trying to push a camera before g_scene is ready");
  106. Ticker::Ref(cam);
  107. data->m_camera_stack.Push(cam);
  108. return data->m_camera_stack.Count() - 1;
  109. }
  110. void Scene::PopCamera(Camera *cam)
  111. {
  112. ASSERT(this, "trying to pop a camera before g_scene is ready");
  113. /* Parse from the end because that’s probably where we’ll find
  114. * our camera first. */
  115. for (int i = data->m_camera_stack.Count(); i--; )
  116. {
  117. if (data->m_camera_stack[i] == cam)
  118. {
  119. Ticker::Unref(cam);
  120. data->m_camera_stack.Remove(i);
  121. return;
  122. }
  123. }
  124. ASSERT(false, "trying to pop a nonexistent camera from the scene");
  125. }
  126. void Scene::SetTileCam(int cam_idx)
  127. {
  128. data->m_tile_cam = cam_idx;
  129. }
  130. Camera *Scene::GetCamera(int cam_idx)
  131. {
  132. return (0 <= cam_idx && cam_idx < data->m_camera_stack.Count()) ?
  133. data->m_camera_stack[cam_idx] :
  134. data->m_camera_stack.Last();
  135. }
  136. void Scene::Reset()
  137. {
  138. for (int i = 0; i < data->m_tile_bufs.Count(); i++)
  139. delete data->m_tile_bufs[i];
  140. data->m_tile_bufs.Empty();
  141. data->m_lights.Empty();
  142. data->m_primitives.Empty();
  143. }
  144. void Scene::AddPrimitive(Mesh const &mesh, mat4 const &matrix)
  145. {
  146. for (int i = 0; i < mesh.m_submeshes.Count(); ++i)
  147. {
  148. data->m_primitives.Push(Primitive(mesh.m_submeshes[i],
  149. matrix));
  150. }
  151. }
  152. void Scene::AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale, float angle)
  153. {
  154. ASSERT(id < tileset->GetTileCount());
  155. Tile t;
  156. /* FIXME: this sorting only works for a 45-degree camera */
  157. t.prio = -pos.y - (int)(2 * 32 * pos.z) + (o ? 0 : 32);
  158. t.tileset = tileset;
  159. t.id = id;
  160. t.pos = pos;
  161. t.o = o;
  162. t.scale = scale;
  163. t.angle = angle;
  164. if (tileset->GetPalette())
  165. data->m_palettes.Push(t);
  166. else
  167. data->m_tiles.Push(t);
  168. }
  169. void Scene::SetLineTime(float new_time) { data->m_new_line_time = new_time; }
  170. void Scene::SetLineMask(int new_mask) { data->m_new_line_mask = new_mask; }
  171. void Scene::SetLineSegmentSize(float new_segment_size) { data->m_new_line_segment_size = new_segment_size; }
  172. float Scene::GetLineSegmentSize() { return data->m_new_line_segment_size; }
  173. void Scene::SetLineColor(vec4 new_color) { data->m_new_line_color = new_color; }
  174. vec4 Scene::GetLineColor() { return data->m_new_line_color; }
  175. void Scene::AddLine(vec3 a, vec3 b, vec4 color)
  176. {
  177. data->m_lines.Push(a, b, color, data->m_new_line_time, data->m_new_line_mask, false, false);
  178. }
  179. void Scene::AddLine(vec2 a, vec3 b, vec4 color, float az)
  180. {
  181. data->m_lines.Push(vec3(a, az), b, color, data->m_new_line_time, data->m_new_line_mask, true, false);
  182. }
  183. void Scene::AddLine(vec2 a, vec2 b, vec4 color, float az, float bz)
  184. {
  185. data->m_lines.Push(vec3(a, az), vec3(b, bz), color, data->m_new_line_time, data->m_new_line_mask, true, true);
  186. }
  187. void Scene::AddLight(Light *l)
  188. {
  189. data->m_lights.Push(l);
  190. }
  191. array<Light *> const &Scene::GetLights() const
  192. {
  193. return data->m_lights;
  194. }
  195. void Scene::RenderPrimitives()
  196. {
  197. /* TODO: this should be the main entry for rendering of all
  198. * primitives found in the scene graph. When we have one. */
  199. Shader *shader = nullptr;
  200. ShaderUniform u_model, u_modelview, u_normalmat, uni_tex, uni_texsize;
  201. ShaderAttrib a_pos, a_tex;
  202. for (Primitive const &p : data->m_primitives)
  203. {
  204. /* If this primitive uses a new shader, update attributes */
  205. if (p.m_submesh->GetShader() != shader)
  206. {
  207. shader = p.m_submesh->GetShader();
  208. a_pos = shader->GetAttribLocation(VertexUsage::Position, 0);
  209. a_tex = shader->GetAttribLocation(VertexUsage::TexCoord, 0);
  210. shader->Bind();
  211. /* Per-scene matrices */
  212. ShaderUniform u_mat;
  213. u_mat = shader->GetUniformLocation("u_projection");
  214. shader->SetUniform(u_mat, GetCamera()->GetProjection());
  215. u_mat = shader->GetUniformLocation("u_view");
  216. shader->SetUniform(u_mat, GetCamera()->GetView());
  217. u_mat = shader->GetUniformLocation("u_inv_view");
  218. shader->SetUniform(u_mat, inverse(GetCamera()->GetView()));
  219. /* Per-object matrices, will be set later */
  220. u_model = shader->GetUniformLocation("u_model");
  221. u_modelview = shader->GetUniformLocation("u_modelview");
  222. u_normalmat = shader->GetUniformLocation("u_normalmat");
  223. /* Per-scene environment */
  224. array<Light *> const &lights = GetLights();
  225. array<vec4> light_data;
  226. /* FIXME: the 4th component of the position can be used for other things */
  227. /* FIXME: GetUniform("blabla") is costly */
  228. for (auto l : lights)
  229. light_data << vec4(l->GetPosition(), l->GetType()) << l->GetColor();
  230. while (light_data.Count() < LOL_MAX_LIGHT_COUNT)
  231. light_data << vec4::zero << vec4::zero;
  232. ShaderUniform u_lights = shader->GetUniformLocation("u_lights");
  233. shader->SetUniform(u_lights, light_data);
  234. }
  235. shader->SetUniform(u_model, p.m_matrix);
  236. mat4 modelview = GetCamera()->GetView() * p.m_matrix;
  237. shader->SetUniform(u_modelview, modelview);
  238. shader->SetUniform(u_normalmat, transpose(inverse(mat3(modelview))));
  239. p.m_submesh->Render();
  240. }
  241. }
  242. void Scene::RenderTiles() // XXX: rename to Blit()
  243. {
  244. RenderContext rc;
  245. /* Early test if nothing needs to be rendered */
  246. if (!data->m_tiles.Count() && !data->m_palettes.Count())
  247. return;
  248. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  249. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  250. rc.SetBlendEquation(BlendEquation::Add, BlendEquation::Max);
  251. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  252. #if defined USE_D3D9 || defined _XBOX
  253. #elif !defined HAVE_GLES_2X
  254. glEnable(GL_TEXTURE_2D);
  255. #endif
  256. if (!data->m_tile_shader)
  257. data->m_tile_shader = Shader::Create(LOLFX_RESOURCE_NAME(tile));
  258. if (!data->m_palette_shader)
  259. data->m_palette_shader = Shader::Create(LOLFX_RESOURCE_NAME(palette));
  260. for (int p = 0; p < 2; p++)
  261. {
  262. Shader *shader = (p == 0) ? data->m_tile_shader : data->m_palette_shader;
  263. array<Tile>& tiles = (p == 0) ? data->m_tiles : data->m_palettes;
  264. if (tiles.Count() == 0)
  265. continue;
  266. ShaderUniform uni_mat, uni_tex, uni_pal, uni_texsize;
  267. ShaderAttrib attr_pos, attr_tex;
  268. attr_pos = shader->GetAttribLocation(VertexUsage::Position, 0);
  269. attr_tex = shader->GetAttribLocation(VertexUsage::TexCoord, 0);
  270. shader->Bind();
  271. uni_mat = shader->GetUniformLocation("u_projection");
  272. shader->SetUniform(uni_mat, GetCamera(data->m_tile_cam)->GetProjection());
  273. uni_mat = shader->GetUniformLocation("u_view");
  274. shader->SetUniform(uni_mat, GetCamera(data->m_tile_cam)->GetView());
  275. uni_mat = shader->GetUniformLocation("u_model");
  276. shader->SetUniform(uni_mat, mat4(1.f));
  277. uni_tex = shader->GetUniformLocation("u_texture");
  278. uni_pal = data->m_palette_shader->GetUniformLocation("u_palette");
  279. uni_texsize = shader->GetUniformLocation("u_texsize");
  280. for (int buf = 0, i = 0, n; i < tiles.Count(); i = n, buf += 2)
  281. {
  282. /* Count how many quads will be needed */
  283. for (n = i + 1; n < tiles.Count(); n++)
  284. if (tiles[i].tileset != tiles[n].tileset)
  285. break;
  286. /* Create a vertex array object */
  287. VertexBuffer *vb1 = new VertexBuffer(6 * (n - i) * sizeof(vec3));
  288. vec3 *vertex = (vec3 *)vb1->Lock(0, 0);
  289. VertexBuffer *vb2 = new VertexBuffer(6 * (n - i) * sizeof(vec2));
  290. vec2 *texture = (vec2 *)vb2->Lock(0, 0);
  291. data->m_tile_bufs.Push(vb1);
  292. data->m_tile_bufs.Push(vb2);
  293. for (int j = i; j < n; j++)
  294. {
  295. tiles[i].tileset->BlitTile(tiles[j].id,
  296. tiles[j].pos, tiles[j].o,
  297. tiles[j].scale, tiles[j].angle,
  298. vertex + 6 * (j - i), texture + 6 * (j - i));
  299. }
  300. vb1->Unlock();
  301. vb2->Unlock();
  302. /* Bind texture */
  303. if (tiles[i].tileset->GetPalette())
  304. {
  305. if (tiles[i].tileset->GetTexture())
  306. shader->SetUniform(uni_tex, tiles[i].tileset->GetTexture()->GetTextureUniform(), 0);
  307. if (tiles[i].tileset->GetPalette()->GetTexture())
  308. shader->SetUniform(uni_pal, tiles[i].tileset->GetPalette()->GetTexture()->GetTextureUniform(), 1);
  309. }
  310. else
  311. {
  312. shader->SetUniform(uni_tex, 0);
  313. if (tiles[i].tileset->GetTexture())
  314. shader->SetUniform(uni_tex, tiles[i].tileset->GetTexture()->GetTextureUniform(), 0);
  315. tiles[i].tileset->Bind();
  316. }
  317. shader->SetUniform(uni_texsize,
  318. (vec2)tiles[i].tileset->GetTextureSize());
  319. /* Bind vertex and texture coordinate buffers */
  320. data->m_tile_vdecl->Bind();
  321. data->m_tile_vdecl->SetStream(vb1, attr_pos);
  322. data->m_tile_vdecl->SetStream(vb2, attr_tex);
  323. /* Draw arrays */
  324. data->m_tile_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6);
  325. data->m_tile_vdecl->Unbind();
  326. tiles[i].tileset->Unbind();
  327. }
  328. tiles.Empty();
  329. shader->Unbind();
  330. }
  331. #if defined USE_D3D9 || defined _XBOX
  332. /* TODO */
  333. #elif !defined HAVE_GLES_2X
  334. glDisable(GL_TEXTURE_2D);
  335. #endif
  336. }
  337. void Scene::RenderLines(float seconds) // XXX: rename to Blit()
  338. {
  339. RenderContext rc;
  340. if (!data->m_lines.Count())
  341. return;
  342. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  343. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  344. rc.SetBlendEquation(BlendEquation::Add, BlendEquation::Max);
  345. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  346. int linecount = data->m_lines.Count();
  347. if (!data->m_line_shader)
  348. data->m_line_shader = Shader::Create(LOLFX_RESOURCE_NAME(line));
  349. array<vec4, vec4, vec4, vec4> buff;
  350. buff.Resize(linecount);
  351. int real_linecount = 0;
  352. mat4 const inv_view_proj = inverse(g_scene->GetCamera()->GetProjection() * g_scene->GetCamera()->GetView());
  353. for (int i = 0; i < linecount; i++)
  354. {
  355. if (data->m_lines[i].m5 & data->m_debug_mask)
  356. {
  357. buff[real_linecount].m1 = vec4(data->m_lines[i].m1, (float)data->m_lines[i].m6);
  358. buff[real_linecount].m2 = data->m_lines[i].m3;
  359. buff[real_linecount].m3 = vec4(data->m_lines[i].m2, (float)data->m_lines[i].m7);
  360. buff[real_linecount].m4 = data->m_lines[i].m3;
  361. real_linecount++;
  362. }
  363. data->m_lines[i].m4 -= seconds;
  364. if (data->m_lines[i].m4 < 0.f)
  365. {
  366. data->m_lines.RemoveSwap(i--);
  367. linecount--;
  368. }
  369. }
  370. VertexBuffer *vb = new VertexBuffer(buff.Bytes());
  371. float *vertex = (float *)vb->Lock(0, 0);
  372. memcpy(vertex, buff.Data(), buff.Bytes());
  373. vb->Unlock();
  374. data->m_line_shader->Bind();
  375. ShaderUniform uni_mat, uni_tex;
  376. ShaderAttrib attr_pos, attr_col;
  377. attr_pos = data->m_line_shader->GetAttribLocation(VertexUsage::Position, 0);
  378. attr_col = data->m_line_shader->GetAttribLocation(VertexUsage::Color, 0);
  379. data->m_line_shader->Bind();
  380. uni_mat = data->m_line_shader->GetUniformLocation("u_projection");
  381. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  382. uni_mat = data->m_line_shader->GetUniformLocation("u_view");
  383. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetView());
  384. data->m_line_vdecl->Bind();
  385. data->m_line_vdecl->SetStream(vb, attr_pos, attr_col);
  386. data->m_line_vdecl->DrawElements(MeshPrimitive::Lines, 0, 2 * real_linecount);
  387. data->m_line_vdecl->Unbind();
  388. data->m_line_shader->Unbind();
  389. //data->m_lines.Empty();
  390. delete vb;
  391. }
  392. } /* namespace lol */