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.

scene.cpp 15 KiB

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