Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

894 řádky
27 KiB

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