Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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