851 строка
25 KiB

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