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.
 
 
 

764 lines
21 KiB

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