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.
 
 
 

898 lines
27 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2016 Sam Hocevar <sam@hocevar.net>
  5. // © 2014—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  6. //
  7. // Lol Engine is free software. It comes without any warranty, to
  8. // the extent permitted by applicable law. You can redistribute it
  9. // and/or modify it under the terms of the Do What the Fuck You Want
  10. // to Public License, Version 2, as published by the WTFPL Task Force.
  11. // See http://www.wtfpl.net/ for more details.
  12. //
  13. #include <lol/engine-internal.h>
  14. #include <cstdlib>
  15. #if defined(_WIN32)
  16. # define WIN32_LEAN_AND_MEAN 1
  17. # include <windows.h>
  18. # undef WIN32_LEAN_AND_MEAN
  19. #endif
  20. #include "lolgl.h"
  21. LOLFX_RESOURCE_DECLARE(gpu_tile);
  22. LOLFX_RESOURCE_DECLARE(gpu_palette);
  23. LOLFX_RESOURCE_DECLARE(gpu_line);
  24. LOLFX_RESOURCE_DECLARE(gpu_blit);
  25. LOLFX_RESOURCE_DECLARE(gpu_postprocess);
  26. namespace lol
  27. {
  28. /*
  29. * The global g_scenes object, initialised by Video::Init
  30. */
  31. array<Scene*> Scene::g_scenes;
  32. /*
  33. * A quick and dirty Tile structure for 2D blits
  34. */
  35. struct Tile
  36. {
  37. mat4 m_model;
  38. TileSet *m_tileset;
  39. int m_id;
  40. };
  41. //-----------------------------------------------------------------------------
  42. static array<SceneDisplay*> m_scene_displays;
  43. static inline void gpu_marker(char const *message)
  44. {
  45. #if LOL_USE_GLEW
  46. if (GLEW_GREMEDY_string_marker)
  47. glStringMarkerGREMEDY(0, message);
  48. #else
  49. UNUSED(message);
  50. #endif
  51. }
  52. /*
  53. * Public SceneDisplay class
  54. */
  55. void SceneDisplay::Add(SceneDisplay* display)
  56. {
  57. m_scene_displays << display;
  58. }
  59. int SceneDisplay::GetCount()
  60. {
  61. return m_scene_displays.count();
  62. }
  63. SceneDisplay* SceneDisplay::GetDisplay(int index)
  64. {
  65. ASSERT(0 <= index && index < m_scene_displays.count(),
  66. "invalid display index %d", index);
  67. return m_scene_displays[index];
  68. }
  69. void SceneDisplay::DestroyAll()
  70. {
  71. for (SceneDisplay* display : m_scene_displays)
  72. delete display;
  73. m_scene_displays.empty();
  74. }
  75. /* ------------------------------------------------ */
  76. void SceneDisplay::Enable()
  77. {
  78. // TODO: PROFILER STUFF
  79. }
  80. void SceneDisplay::Disable()
  81. {
  82. // TODO: PROFILER STUFF
  83. }
  84. /*
  85. * Primitive implementation class
  86. */
  87. void PrimitiveSource::Render(Scene& scene) { UNUSED(scene); }
  88. void PrimitiveRenderer::Render(Scene& scene, PrimitiveSource* primitive)
  89. {
  90. UNUSED(scene);
  91. UNUSED(primitive);
  92. }
  93. /*
  94. * Scene implementation class
  95. */
  96. class SceneData
  97. {
  98. friend class Scene;
  99. private:
  100. SceneData()
  101. {
  102. /* TODO: FIX THAT */
  103. ASSERT(!(m_used_id & ((uint64_t)1 << 63)), "Too many scenes !!!!");
  104. m_mask_id = m_used_id;
  105. m_used_id = m_used_id << 1;
  106. }
  107. /* Mask ID */
  108. /* TODO: Do a mask class that handles more than 64 slots */
  109. static uint64_t m_used_id;
  110. uint64_t m_mask_id = 0;
  111. /* Scene display: if none has been set to the scene,
  112. * the default one created by the app will be used */
  113. SceneDisplay* m_display = nullptr;
  114. /** Render buffers: where to render to. */
  115. Framebuffer *m_renderbuffer[4];
  116. struct postprocess
  117. {
  118. Shader *m_shader[2];
  119. VertexBuffer *m_vbo = nullptr;
  120. VertexDeclaration *m_vdecl = nullptr;
  121. ShaderUniform m_buffer_uni[2][3];
  122. ShaderAttrib m_coord[2];
  123. }
  124. m_pp;
  125. /* Sources are shared by all scenes.
  126. * Renderers are scene-dependent. They get the primitive in the identical
  127. * slot to render with the given scene.
  128. * Primitives and renderers will be kept until:
  129. * - Updated by entity
  130. * - Marked Fire&Forget
  131. * - Scene is destroyed */
  132. map<uintptr_t, array<PrimitiveRenderer*>> m_prim_renderers;
  133. static map<uintptr_t, array<PrimitiveSource*>> m_prim_sources;
  134. static mutex m_prim_mutex;
  135. Camera *m_default_cam;
  136. array<Camera *> m_camera_stack;
  137. /* Old line API <P0, P1, COLOR, TIME, MASK> */
  138. struct line_api
  139. {
  140. //float m_duration, m_segment_size;
  141. //vec4 m_color;
  142. array<vec3, vec3, vec4, float, int, bool, bool> m_lines;
  143. int /*m_mask,*/ m_debug_mask;
  144. Shader *m_shader;
  145. VertexDeclaration *m_vdecl;
  146. }
  147. m_line_api;
  148. /* The old tiles API */
  149. struct tile_api
  150. {
  151. int m_cam;
  152. array<Tile> m_tiles;
  153. array<Tile> m_palettes;
  154. array<Light *> m_lights;
  155. Shader *m_shader;
  156. Shader *m_palette_shader;
  157. VertexDeclaration *m_vdecl;
  158. array<VertexBuffer *> m_bufs;
  159. }
  160. m_tile_api;
  161. };
  162. uint64_t SceneData::m_used_id = 1;
  163. map<uintptr_t, array<PrimitiveSource*>> SceneData::m_prim_sources;
  164. mutex SceneData::m_prim_mutex;
  165. /*
  166. * Public Scene class
  167. */
  168. Scene::Scene(ivec2 size)
  169. : data(new SceneData())
  170. {
  171. data->m_renderbuffer[0] = new Framebuffer(size);
  172. data->m_renderbuffer[1] = new Framebuffer(size);
  173. data->m_renderbuffer[2] = new Framebuffer(size);
  174. data->m_renderbuffer[3] = new Framebuffer(size);
  175. data->m_pp.m_shader[0] = Shader::Create(LOLFX_RESOURCE_NAME(gpu_blit));
  176. data->m_pp.m_shader[1] = Shader::Create(LOLFX_RESOURCE_NAME(gpu_postprocess));
  177. data->m_pp.m_coord[0] = data->m_pp.m_shader[0]->GetAttribLocation(VertexUsage::Position, 0);
  178. data->m_pp.m_coord[1] = data->m_pp.m_shader[1]->GetAttribLocation(VertexUsage::Position, 0);
  179. data->m_pp.m_vdecl = new VertexDeclaration(VertexStream<vec2>(VertexUsage::Position));
  180. data->m_pp.m_buffer_uni[0][0] = data->m_pp.m_shader[0]->GetUniformLocation("u_buffer");
  181. data->m_pp.m_buffer_uni[1][0] = data->m_pp.m_shader[1]->GetUniformLocation("u_buffer");
  182. data->m_pp.m_buffer_uni[1][1] = data->m_pp.m_shader[1]->GetUniformLocation("u_prev_buffer");
  183. data->m_pp.m_buffer_uni[1][2] = data->m_pp.m_shader[1]->GetUniformLocation("u_prev_final");
  184. array<vec2> quad { vec2( 1.0, 1.0), vec2(-1.0, -1.0), vec2( 1.0, -1.0),
  185. vec2(-1.0, -1.0), vec2( 1.0, 1.0), vec2(-1.0, 1.0), };
  186. data->m_pp.m_vbo = new VertexBuffer(quad.bytes());
  187. void *vertices = data->m_pp.m_vbo->Lock(0, 0);
  188. memcpy(vertices, quad.data(), quad.bytes());
  189. data->m_pp.m_vbo->Unlock();
  190. /* Create a default orthographic camera, in case the user doesn’t. */
  191. data->m_default_cam = new Camera();
  192. mat4 proj = mat4::ortho(0.f, (float)size.x, 0.f, (float)size.y, -1000.f, 1000.f);
  193. data->m_default_cam->SetProjection(proj);
  194. PushCamera(data->m_default_cam);
  195. data->m_tile_api.m_cam = -1;
  196. data->m_tile_api.m_shader = 0;
  197. data->m_tile_api.m_palette_shader = 0;
  198. data->m_tile_api.m_vdecl = new VertexDeclaration(VertexStream<vec3>(VertexUsage::Position),
  199. VertexStream<vec2>(VertexUsage::TexCoord));
  200. data->m_line_api.m_shader = 0;
  201. data->m_line_api.m_vdecl = new VertexDeclaration(VertexStream<vec4,vec4>(VertexUsage::Position, VertexUsage::Color));
  202. data->m_line_api.m_debug_mask = 1;
  203. }
  204. //-----------------------------------------------------------------------------
  205. Scene::~Scene()
  206. {
  207. PopCamera(data->m_default_cam);
  208. /* FIXME: this must be done while the GL context is still active.
  209. * Change the code architecture to make sure of that. */
  210. /* FIXME: also, make sure we do not add code to Reset() that will
  211. * reallocate stuff */
  212. Reset();
  213. delete data->m_line_api.m_vdecl;
  214. delete data->m_tile_api.m_vdecl;
  215. delete data;
  216. }
  217. //-----------------------------------------------------------------------------
  218. void Scene::AddNew(ivec2 size)
  219. {
  220. Scene::g_scenes << new Scene(size);
  221. }
  222. void Scene::DestroyScene(Scene* scene)
  223. {
  224. Scene::g_scenes.remove_item(scene);
  225. delete scene;
  226. }
  227. void Scene::DestroyAll()
  228. {
  229. while (Scene::g_scenes.count())
  230. delete Scene::g_scenes.pop();
  231. }
  232. int Scene::GetCount()
  233. {
  234. return g_scenes.count();
  235. }
  236. //-----------------------------------------------------------------------------
  237. bool Scene::IsReady(int index)
  238. {
  239. return 0 <= index && index < g_scenes.count() && !!g_scenes[index];
  240. }
  241. //-----------------------------------------------------------------------------
  242. Scene& Scene::GetScene(int index)
  243. {
  244. ASSERT(0 <= index && index < g_scenes.count() && !!g_scenes[index],
  245. "Trying to get a non-existent scene %d", index);
  246. return *g_scenes[index];
  247. }
  248. //-----------------------------------------------------------------------------
  249. void Scene::Link(Entity* entity)
  250. {
  251. entity->m_scene_mask |= data->m_mask_id;
  252. }
  253. //-----------------------------------------------------------------------------
  254. bool Scene::IsRelevant(Entity* entity)
  255. {
  256. return !!(entity->m_scene_mask & data->m_mask_id);
  257. }
  258. //-----------------------------------------------------------------------------
  259. Camera* Scene::GetCamera(int cam_idx)
  260. {
  261. ASSERT(!!data, "Trying to access a non-ready scene");
  262. return (0 <= cam_idx && cam_idx < data->m_camera_stack.count()) ?
  263. data->m_camera_stack[cam_idx] :
  264. data->m_camera_stack.last();
  265. }
  266. //-----------------------------------------------------------------------------
  267. int Scene::PushCamera(Camera *cam)
  268. {
  269. ASSERT(!!data, "Trying to access a non-ready scene");
  270. Ticker::Ref(cam);
  271. data->m_camera_stack.push(cam);
  272. return (int)data->m_camera_stack.count() - 1;
  273. }
  274. //-----------------------------------------------------------------------------
  275. void Scene::PopCamera(Camera *cam)
  276. {
  277. ASSERT(!!data, "Trying to access a non-ready scene");
  278. /* Parse from the end because that’s probably where we’ll find
  279. * our camera first. */
  280. for (int i = data->m_camera_stack.count(); i--;)
  281. {
  282. if (data->m_camera_stack[i] == cam)
  283. {
  284. Ticker::Unref(cam);
  285. data->m_camera_stack.remove(i);
  286. return;
  287. }
  288. }
  289. ASSERT(false, "trying to pop a nonexistent camera from the scene");
  290. }
  291. //-----------------------------------------------------------------------------
  292. void Scene::SetTileCam(int cam_idx)
  293. {
  294. ASSERT(!!data, "Trying to access a non-ready scene");
  295. data->m_tile_api.m_cam = cam_idx;
  296. }
  297. //-----------------------------------------------------------------------------
  298. void Scene::Reset()
  299. {
  300. ASSERT(!!data, "Trying to access a non-ready scene");
  301. /* New scenegraph: Release fire&forget primitives */
  302. array<uintptr_t> keys = data->m_prim_renderers.keys();
  303. for (uintptr_t key : keys)
  304. {
  305. for (int idx = 0; idx < data->m_prim_renderers[key].count(); ++idx)
  306. if (data->m_prim_renderers[key][idx]->m_fire_and_forget)
  307. ReleasePrimitiveRenderer(idx--, key);
  308. }
  309. for (int i = 0; i < data->m_tile_api.m_bufs.count(); i++)
  310. delete data->m_tile_api.m_bufs[i];
  311. data->m_tile_api.m_bufs.empty();
  312. data->m_tile_api.m_lights.empty();
  313. }
  314. //---- Primitive source stuff -------------------------------------------------
  315. int Scene::HasPrimitiveSource(uintptr_t key)
  316. {
  317. int count;
  318. SceneData::m_prim_mutex.lock();
  319. {
  320. count = SceneData::m_prim_sources[key].count();
  321. }
  322. SceneData::m_prim_mutex.unlock();
  323. return count;
  324. }
  325. int Scene::AddPrimitiveSource(uintptr_t key, PrimitiveSource* source)
  326. {
  327. int count;
  328. SceneData::m_prim_mutex.lock();
  329. {
  330. count = SceneData::m_prim_sources[key].count();
  331. SceneData::m_prim_sources[key].push(source);
  332. }
  333. SceneData::m_prim_mutex.unlock();
  334. return count;
  335. }
  336. void Scene::SetPrimitiveSource(int index, uintptr_t key, PrimitiveSource* source)
  337. {
  338. ASSERT(source);
  339. ASSERT(index >= 0);
  340. PrimitiveSource* old = nullptr;
  341. SceneData::m_prim_mutex.lock();
  342. {
  343. if (index < SceneData::m_prim_sources[key].count())
  344. old = SceneData::m_prim_sources[key][index];
  345. else
  346. SceneData::m_prim_sources[key].resize(index + 1);
  347. SceneData::m_prim_sources[key][index] = source;
  348. }
  349. SceneData::m_prim_mutex.unlock();
  350. // Delete old AFTER having released the lock
  351. delete old;
  352. }
  353. void Scene::ReleasePrimitiveSource(int index, uintptr_t key)
  354. {
  355. PrimitiveSource* old = nullptr;
  356. SceneData::m_prim_mutex.lock();
  357. {
  358. ASSERT(0 <= index && index < SceneData::m_prim_sources[key].count());
  359. old = SceneData::m_prim_sources[key][index];
  360. SceneData::m_prim_sources[key].remove(index);
  361. }
  362. SceneData::m_prim_mutex.unlock();
  363. // Delete old AFTER having released the lock
  364. delete old;
  365. }
  366. void Scene::ReleaseAllPrimitiveSources(uintptr_t key)
  367. {
  368. array<PrimitiveSource*> oldies;
  369. SceneData::m_prim_mutex.lock();
  370. {
  371. oldies.reserve(SceneData::m_prim_sources[key].count());
  372. for (PrimitiveSource* source : SceneData::m_prim_sources[key])
  373. oldies << source;
  374. SceneData::m_prim_sources[key].empty();
  375. }
  376. SceneData::m_prim_mutex.unlock();
  377. // Delete oldies AFTER having released the lock
  378. for (PrimitiveSource* old : oldies)
  379. delete old;
  380. }
  381. //---- Primitive renderer stuff -----------------------------------------------
  382. int Scene::HasPrimitiveRenderer(uintptr_t key)
  383. {
  384. return data->m_prim_renderers[key].count();
  385. }
  386. void Scene::AddPrimitiveRenderer(uintptr_t key, PrimitiveRenderer* renderer)
  387. {
  388. renderer->m_fire_and_forget = true;
  389. data->m_prim_renderers[key].push(renderer);
  390. }
  391. void Scene::SetPrimitiveRenderer(int index, uintptr_t key, PrimitiveRenderer* renderer)
  392. {
  393. ASSERT(renderer);
  394. ASSERT(index >= 0);
  395. if (index < data->m_prim_renderers[key].count())
  396. {
  397. ASSERT(data->m_prim_renderers[key][index]);
  398. delete data->m_prim_renderers[key][index];
  399. }
  400. else
  401. data->m_prim_renderers[key].resize(index + 1);
  402. data->m_prim_renderers[key][index] = renderer;
  403. }
  404. void Scene::ReleasePrimitiveRenderer(int index, uintptr_t key)
  405. {
  406. ASSERT(0 <= index && index < data->m_prim_renderers[key].count());
  407. delete data->m_prim_renderers[key][index];
  408. data->m_prim_renderers[key].remove(index);
  409. }
  410. void Scene::ReleaseAllPrimitiveRenderers(uintptr_t key)
  411. {
  412. for (PrimitiveRenderer*& renderer : data->m_prim_renderers[key])
  413. {
  414. delete renderer;
  415. renderer = nullptr;
  416. }
  417. }
  418. //-----------------------------------------------------------------------------
  419. void Scene::AddTile(TileSet *tileset, int id, vec3 pos, vec2 scale, float radians)
  420. {
  421. ASSERT(id < tileset->GetTileCount());
  422. ivec2 size = tileset->GetTileSize(id);
  423. mat4 model = mat4::translate(pos)
  424. * mat4::scale(scale.x, scale.y, 1.f)
  425. * mat4::translate(size.x * 0.5f, size.y * 0.5f, 0.f)
  426. * mat4::rotate(scale.x * scale.y < 0 ? radians : -radians,
  427. vec3::axis_z);
  428. AddTile(tileset, id, model);
  429. }
  430. void Scene::AddTile(TileSet *tileset, int id, mat4 model)
  431. {
  432. ASSERT(id < tileset->GetTileCount());
  433. Tile t;
  434. t.m_model = model;
  435. t.m_tileset = tileset;
  436. t.m_id = id;
  437. if (tileset->GetPalette())
  438. data->m_tile_api.m_palettes.push(t);
  439. else
  440. data->m_tile_api.m_tiles.push(t);
  441. }
  442. //-----------------------------------------------------------------------------
  443. void Scene::AddLine(vec3 a, vec3 b, vec4 color)
  444. {
  445. ASSERT(!!data, "Trying to access a non-ready scene");
  446. data->m_line_api.m_lines.push(a, b, color, -1.f, 0xFFFFFFFF, false, false);
  447. }
  448. //-----------------------------------------------------------------------------
  449. void Scene::AddLine(vec3 a, vec3 b, vec4 color, float duration, int mask)
  450. {
  451. ASSERT(!!data, "Trying to access a non-ready scene");
  452. data->m_line_api.m_lines.push(a, b, color, duration, mask, false, false);
  453. }
  454. //-----------------------------------------------------------------------------
  455. void Scene::AddLight(Light *l)
  456. {
  457. ASSERT(!!data, "Trying to access a non-ready scene");
  458. data->m_tile_api.m_lights.push(l);
  459. }
  460. //-----------------------------------------------------------------------------
  461. array<Light *> const &Scene::GetLights()
  462. {
  463. ASSERT(!!data, "Trying to access a non-ready scene");
  464. return data->m_tile_api.m_lights;
  465. }
  466. //-----------------------------------------------------------------------------
  467. void Scene::SetDisplay(SceneDisplay* display)
  468. {
  469. data->m_display = display;
  470. }
  471. //-----------------------------------------------------------------------------
  472. void Scene::EnableDisplay()
  473. {
  474. // If no display has been set, use the default one
  475. if (!data->m_display)
  476. SetDisplay(SceneDisplay::GetDisplay());
  477. data->m_display->Enable();
  478. }
  479. void Scene::DisableDisplay()
  480. {
  481. ASSERT(data->m_display);
  482. data->m_display->Disable();
  483. }
  484. static bool do_pp = true;
  485. void Scene::pre_render(float)
  486. {
  487. gpu_marker("Pre Render");
  488. /* First render into the offline buffer */
  489. if (do_pp)
  490. {
  491. data->m_renderbuffer[0]->Bind();
  492. }
  493. {
  494. RenderContext rc;
  495. if (do_pp)
  496. {
  497. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  498. rc.SetClearDepth(1.f);
  499. }
  500. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  501. }
  502. }
  503. /* Render everything that the scene contains */
  504. void Scene::render(float seconds)
  505. {
  506. gpu_marker("Render");
  507. // FIXME: get rid of the delta time argument
  508. render_primitives();
  509. render_tiles();
  510. render_lines(seconds);
  511. }
  512. void Scene::post_render(float)
  513. {
  514. gpu_marker("Post Render");
  515. if (do_pp)
  516. {
  517. data->m_renderbuffer[0]->Unbind();
  518. gpu_marker("PostProcess");
  519. data->m_renderbuffer[3]->Bind();
  520. RenderContext rc;
  521. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  522. rc.SetClearDepth(1.f);
  523. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  524. /* Execute post process */
  525. data->m_pp.m_shader[1]->Bind();
  526. data->m_pp.m_shader[1]->SetUniform(data->m_pp.m_buffer_uni[1][0], data->m_renderbuffer[0]->GetTextureUniform(), 0);
  527. data->m_pp.m_shader[1]->SetUniform(data->m_pp.m_buffer_uni[1][1], data->m_renderbuffer[1]->GetTextureUniform(), 1);
  528. data->m_pp.m_shader[1]->SetUniform(data->m_pp.m_buffer_uni[1][2], data->m_renderbuffer[2]->GetTextureUniform(), 2);
  529. data->m_pp.m_vdecl->SetStream(data->m_pp.m_vbo, data->m_pp.m_coord[1]);
  530. data->m_pp.m_vdecl->Bind();
  531. data->m_pp.m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  532. data->m_pp.m_vdecl->Unbind();
  533. data->m_pp.m_shader[1]->Unbind();
  534. data->m_renderbuffer[3]->Unbind();
  535. }
  536. if (do_pp)
  537. {
  538. gpu_marker("Blit frame");
  539. data->m_pp.m_shader[0]->Bind();
  540. RenderContext rc;
  541. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  542. rc.SetClearDepth(1.f);
  543. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  544. /* Blit final image to screen */
  545. data->m_pp.m_shader[0]->SetUniform(data->m_pp.m_buffer_uni[0][0], data->m_renderbuffer[3]->GetTextureUniform(), 3);
  546. data->m_pp.m_vdecl->SetStream(data->m_pp.m_vbo, data->m_pp.m_coord[0]);
  547. data->m_pp.m_vdecl->Bind();
  548. data->m_pp.m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  549. data->m_pp.m_vdecl->Unbind();
  550. data->m_pp.m_shader[0]->Unbind();
  551. }
  552. if (do_pp)
  553. {
  554. /* Swap back buffers */
  555. std::swap(data->m_renderbuffer[0], data->m_renderbuffer[1]);
  556. std::swap(data->m_renderbuffer[2], data->m_renderbuffer[3]);
  557. }
  558. gpu_marker("End Render");
  559. }
  560. //-----------------------------------------------------------------------------
  561. void Scene::render_primitives()
  562. {
  563. ASSERT(!!data, "Trying to access a non-ready scene");
  564. /* FIXME: Temp fix for mesh having no render context*/
  565. RenderContext rc;
  566. rc.SetCullMode(CullMode::Clockwise);
  567. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  568. /* new scenegraph */
  569. array<uintptr_t> keys = data->m_prim_renderers.keys();
  570. for (uintptr_t key : keys)
  571. {
  572. for (int idx = 0; idx < data->m_prim_renderers[key].count(); ++idx)
  573. {
  574. /* TODO: Not sure if thread compliant */
  575. data->m_prim_renderers[key][idx]->Render(*this, idx < SceneData::m_prim_sources[key].count() ? SceneData::m_prim_sources[key][idx] : nullptr);
  576. }
  577. }
  578. }
  579. //-----------------------------------------------------------------------------
  580. void Scene::render_tiles() // XXX: rename to Blit()
  581. {
  582. ASSERT(!!data, "Trying to access a non-ready scene");
  583. RenderContext rc;
  584. /* Early test if nothing needs to be rendered */
  585. if (!data->m_tile_api.m_tiles.count() && !data->m_tile_api.m_palettes.count())
  586. return;
  587. /* FIXME: we disable culling for now because we don’t have a reliable
  588. * way to know which side is facing the camera. */
  589. rc.SetCullMode(CullMode::Disabled);
  590. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  591. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  592. rc.SetBlendEquation(BlendEquation::Add, BlendEquation::Max);
  593. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  594. #if (defined LOL_USE_GLEW || defined HAVE_GL_2X) && !defined HAVE_GLES_2X
  595. glEnable(GL_TEXTURE_2D);
  596. #endif
  597. if (!data->m_tile_api.m_shader)
  598. data->m_tile_api.m_shader = Shader::Create(LOLFX_RESOURCE_NAME(gpu_tile));
  599. if (!data->m_tile_api.m_palette_shader && data->m_tile_api.m_palettes.count())
  600. data->m_tile_api.m_palette_shader = Shader::Create(LOLFX_RESOURCE_NAME(gpu_palette));
  601. for (int p = 0; p < 2; p++)
  602. {
  603. Shader *shader = (p == 0) ? data->m_tile_api.m_shader : data->m_tile_api.m_palette_shader;
  604. array<Tile>& tiles = (p == 0) ? data->m_tile_api.m_tiles : data->m_tile_api.m_palettes;
  605. if (tiles.count() == 0)
  606. continue;
  607. ShaderUniform uni_mat, uni_tex, uni_pal, uni_texsize;
  608. ShaderAttrib attr_pos, attr_tex;
  609. attr_pos = shader->GetAttribLocation(VertexUsage::Position, 0);
  610. attr_tex = shader->GetAttribLocation(VertexUsage::TexCoord, 0);
  611. shader->Bind();
  612. uni_mat = shader->GetUniformLocation("u_projection");
  613. shader->SetUniform(uni_mat, GetCamera(data->m_tile_api.m_cam)->GetProjection());
  614. uni_mat = shader->GetUniformLocation("u_view");
  615. shader->SetUniform(uni_mat, GetCamera(data->m_tile_api.m_cam)->GetView());
  616. uni_mat = shader->GetUniformLocation("u_model");
  617. shader->SetUniform(uni_mat, mat4(1.f));
  618. uni_tex = shader->GetUniformLocation("u_texture");
  619. uni_pal = data->m_tile_api.m_palette_shader ? data->m_tile_api.m_palette_shader->GetUniformLocation("u_palette") : ShaderUniform();
  620. uni_texsize = shader->GetUniformLocation("u_texsize");
  621. for (int buf = 0, i = 0, n; i < tiles.count(); i = n, buf += 2)
  622. {
  623. /* Count how many quads will be needed */
  624. for (n = i + 1; n < tiles.count(); n++)
  625. if (tiles[i].m_tileset != tiles[n].m_tileset)
  626. break;
  627. /* Create a vertex array object */
  628. VertexBuffer *vb1 = new VertexBuffer(6 * (n - i) * sizeof(vec3));
  629. vec3 *vertex = (vec3 *)vb1->Lock(0, 0);
  630. VertexBuffer *vb2 = new VertexBuffer(6 * (n - i) * sizeof(vec2));
  631. vec2 *texture = (vec2 *)vb2->Lock(0, 0);
  632. data->m_tile_api.m_bufs.push(vb1);
  633. data->m_tile_api.m_bufs.push(vb2);
  634. for (int j = i; j < n; j++)
  635. {
  636. tiles[i].m_tileset->BlitTile(tiles[j].m_id, tiles[j].m_model,
  637. vertex + 6 * (j - i), texture + 6 * (j - i));
  638. }
  639. vb1->Unlock();
  640. vb2->Unlock();
  641. /* Bind texture */
  642. if (tiles[i].m_tileset->GetPalette())
  643. {
  644. if (tiles[i].m_tileset->GetTexture())
  645. shader->SetUniform(uni_tex, tiles[i].m_tileset->GetTexture()->GetTextureUniform(), 0);
  646. if (tiles[i].m_tileset->GetPalette()->GetTexture())
  647. shader->SetUniform(uni_pal, tiles[i].m_tileset->GetPalette()->GetTexture()->GetTextureUniform(), 1);
  648. }
  649. else
  650. {
  651. shader->SetUniform(uni_tex, 0);
  652. if (tiles[i].m_tileset->GetTexture())
  653. shader->SetUniform(uni_tex, tiles[i].m_tileset->GetTexture()->GetTextureUniform(), 0);
  654. tiles[i].m_tileset->Bind();
  655. }
  656. shader->SetUniform(uni_texsize,
  657. (vec2)tiles[i].m_tileset->GetTextureSize());
  658. /* Bind vertex and texture coordinate buffers */
  659. data->m_tile_api.m_vdecl->Bind();
  660. data->m_tile_api.m_vdecl->SetStream(vb1, attr_pos);
  661. data->m_tile_api.m_vdecl->SetStream(vb2, attr_tex);
  662. /* Draw arrays */
  663. data->m_tile_api.m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6);
  664. data->m_tile_api.m_vdecl->Unbind();
  665. tiles[i].m_tileset->Unbind();
  666. }
  667. tiles.empty();
  668. shader->Unbind();
  669. if (!data->m_tile_api.m_palette_shader)
  670. break;
  671. }
  672. #if (defined LOL_USE_GLEW || defined HAVE_GL_2X) && !defined HAVE_GLES_2X
  673. glDisable(GL_TEXTURE_2D);
  674. #endif
  675. }
  676. //-----------------------------------------------------------------------------
  677. // FIXME: get rid of the delta time argument
  678. // XXX: rename to Blit()
  679. void Scene::render_lines(float seconds)
  680. {
  681. ASSERT(!!data, "Trying to access a non-ready scene");
  682. RenderContext rc;
  683. if (!data->m_line_api.m_lines.count())
  684. return;
  685. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  686. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  687. rc.SetBlendEquation(BlendEquation::Add, BlendEquation::Max);
  688. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  689. int linecount = (int)data->m_line_api.m_lines.count();
  690. if (!data->m_line_api.m_shader)
  691. data->m_line_api.m_shader = Shader::Create(LOLFX_RESOURCE_NAME(gpu_line));
  692. array<vec4, vec4, vec4, vec4> buff;
  693. buff.resize(linecount);
  694. int real_linecount = 0;
  695. mat4 const inv_view_proj = inverse(GetCamera()->GetProjection() * GetCamera()->GetView());
  696. for (int i = 0; i < linecount; i++)
  697. {
  698. if (data->m_line_api.m_lines[i].m5 & data->m_line_api.m_debug_mask)
  699. {
  700. buff[real_linecount].m1 = vec4(data->m_line_api.m_lines[i].m1, (float)data->m_line_api.m_lines[i].m6);
  701. buff[real_linecount].m2 = data->m_line_api.m_lines[i].m3;
  702. buff[real_linecount].m3 = vec4(data->m_line_api.m_lines[i].m2, (float)data->m_line_api.m_lines[i].m7);
  703. buff[real_linecount].m4 = data->m_line_api.m_lines[i].m3;
  704. real_linecount++;
  705. }
  706. data->m_line_api.m_lines[i].m4 -= seconds;
  707. if (data->m_line_api.m_lines[i].m4 < 0.f)
  708. {
  709. data->m_line_api.m_lines.remove_swap(i--);
  710. linecount--;
  711. }
  712. }
  713. VertexBuffer *vb = new VertexBuffer(buff.bytes());
  714. float *vertex = (float *)vb->Lock(0, 0);
  715. memcpy(vertex, buff.data(), buff.bytes());
  716. vb->Unlock();
  717. data->m_line_api.m_shader->Bind();
  718. ShaderUniform uni_mat, uni_tex;
  719. ShaderAttrib attr_pos, attr_col;
  720. attr_pos = data->m_line_api.m_shader->GetAttribLocation(VertexUsage::Position, 0);
  721. attr_col = data->m_line_api.m_shader->GetAttribLocation(VertexUsage::Color, 0);
  722. data->m_line_api.m_shader->Bind();
  723. uni_mat = data->m_line_api.m_shader->GetUniformLocation("u_projection");
  724. data->m_line_api.m_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  725. uni_mat = data->m_line_api.m_shader->GetUniformLocation("u_view");
  726. data->m_line_api.m_shader->SetUniform(uni_mat, GetCamera()->GetView());
  727. data->m_line_api.m_vdecl->Bind();
  728. data->m_line_api.m_vdecl->SetStream(vb, attr_pos, attr_col);
  729. data->m_line_api.m_vdecl->DrawElements(MeshPrimitive::Lines, 0, 2 * real_linecount);
  730. data->m_line_api.m_vdecl->Unbind();
  731. data->m_line_api.m_shader->Unbind();
  732. //data->m_line_api.m_lines.empty();
  733. delete vb;
  734. }
  735. } /* namespace lol */