您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

332 行
8.8 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 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 defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstdlib>
  14. #ifdef WIN32
  15. # define WIN32_LEAN_AND_MEAN
  16. # include <windows.h>
  17. #endif
  18. #include "core.h"
  19. #include "lolgl.h"
  20. LOLFX_RESOURCE_DECLARE(tile);
  21. LOLFX_RESOURCE_DECLARE(line);
  22. namespace lol
  23. {
  24. /*
  25. * The global g_scene object, initialised by Video::Init
  26. */
  27. Scene *g_scene = nullptr;
  28. /*
  29. * A quick and dirty Tile structure for 2D blits
  30. */
  31. struct Tile
  32. {
  33. TileSet *tileset;
  34. uint32_t prio;
  35. vec3 pos;
  36. vec2 scale;
  37. int id, o;
  38. };
  39. /*
  40. * Scene implementation class
  41. */
  42. class SceneData
  43. {
  44. friend class Scene;
  45. private:
  46. Array<vec3, vec3, vec4> m_lines;
  47. Shader *m_line_shader;
  48. VertexDeclaration *m_line_vdecl;
  49. Array<Tile> m_tiles;
  50. Array<Light *> m_lights;
  51. Shader *m_tile_shader;
  52. VertexDeclaration *m_tile_vdecl;
  53. Array<VertexBuffer *> m_tile_bufs;
  54. Camera *m_default_cam;
  55. Array<Camera *> m_camera_stack;
  56. };
  57. /*
  58. * Public Scene class
  59. */
  60. Scene::Scene(ivec2 size)
  61. : data(new SceneData())
  62. {
  63. /* Create a default orthographic camera, in case the user doesn’t. */
  64. data->m_default_cam = new Camera();
  65. mat4 proj = mat4::ortho(0, size.x, 0, size.y, -1000.f, 1000.f);
  66. data->m_default_cam->SetProjection(proj);
  67. PushCamera(data->m_default_cam);
  68. data->m_tile_shader = 0;
  69. data->m_tile_vdecl = new VertexDeclaration(VertexStream<vec3>(VertexUsage::Position),
  70. VertexStream<vec2>(VertexUsage::TexCoord));
  71. data->m_line_shader = 0;
  72. data->m_line_vdecl = new VertexDeclaration(VertexStream<vec3,vec4>(VertexUsage::Position, VertexUsage::Color));
  73. }
  74. Scene::~Scene()
  75. {
  76. PopCamera(data->m_default_cam);
  77. /* FIXME: this must be done while the GL context is still active.
  78. * Change the code architecture to make sure of that. */
  79. /* FIXME: also, make sure we do not add code to Reset() that will
  80. * reallocate stuff */
  81. Reset();
  82. delete data->m_line_vdecl;
  83. delete data->m_tile_vdecl;
  84. delete data;
  85. }
  86. void Scene::PushCamera(Camera *cam)
  87. {
  88. Ticker::Ref(cam);
  89. data->m_camera_stack.Push(cam);
  90. }
  91. void Scene::PopCamera(Camera *cam)
  92. {
  93. /* Parse from the end because that’s probably where we’ll find
  94. * our camera first. */
  95. for (int i = data->m_camera_stack.Count(); i--; )
  96. {
  97. if (data->m_camera_stack[i] == cam)
  98. {
  99. Ticker::Unref(cam);
  100. data->m_camera_stack.Remove(i);
  101. return;
  102. }
  103. }
  104. ASSERT(false, "trying to pop a nonexistent camera from the scene");
  105. }
  106. Camera *Scene::GetCamera()
  107. {
  108. return data->m_camera_stack.Last();
  109. }
  110. void Scene::Reset()
  111. {
  112. for (int i = 0; i < data->m_tile_bufs.Count(); i++)
  113. delete data->m_tile_bufs[i];
  114. data->m_tile_bufs.Empty();
  115. data->m_lights.Empty();
  116. }
  117. void Scene::AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale)
  118. {
  119. ASSERT(id < tileset->GetTileCount());
  120. Tile t;
  121. /* FIXME: this sorting only works for a 45-degree camera */
  122. t.prio = -pos.y - 2 * 32 * pos.z + (o ? 0 : 32);
  123. t.tileset = tileset;
  124. t.id = id;
  125. t.pos = pos;
  126. t.o = o;
  127. t.scale = scale;
  128. data->m_tiles.Push(t);
  129. }
  130. void Scene::AddLine(vec3 a, vec3 b, vec4 color)
  131. {
  132. data->m_lines.Push(a, b, color);
  133. }
  134. void Scene::AddLight(Light *l)
  135. {
  136. data->m_lights.Push(l);
  137. }
  138. Array<Light *> const &Scene::GetLights() const
  139. {
  140. return data->m_lights;
  141. }
  142. void Scene::RenderPrimitives()
  143. {
  144. /* TODO: this should be the main entry for rendering of all
  145. * primitives found in the scene graph. When we have one. */
  146. }
  147. void Scene::RenderTiles() // XXX: rename to Blit()
  148. {
  149. RenderContext rc;
  150. /* Early test if nothing needs to be rendered */
  151. if (!data->m_tiles.Count())
  152. return;
  153. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  154. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  155. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  156. #if defined USE_D3D9 || defined _XBOX
  157. #elif !defined HAVE_GLES_2X
  158. glEnable(GL_TEXTURE_2D);
  159. #endif
  160. if (!data->m_tile_shader)
  161. data->m_tile_shader = Shader::Create(LOLFX_RESOURCE_NAME(tile));
  162. ShaderUniform uni_mat, uni_tex, uni_texsize;
  163. ShaderAttrib attr_pos, attr_tex;
  164. attr_pos = data->m_tile_shader->GetAttribLocation(VertexUsage::Position, 0);
  165. attr_tex = data->m_tile_shader->GetAttribLocation(VertexUsage::TexCoord, 0);
  166. data->m_tile_shader->Bind();
  167. uni_mat = data->m_tile_shader->GetUniformLocation("proj_matrix");
  168. data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  169. uni_mat = data->m_tile_shader->GetUniformLocation("view_matrix");
  170. data->m_tile_shader->SetUniform(uni_mat, GetCamera()->GetView());
  171. uni_mat = data->m_tile_shader->GetUniformLocation("model_matrix");
  172. data->m_tile_shader->SetUniform(uni_mat, mat4(1.f));
  173. uni_tex = data->m_tile_shader->GetUniformLocation("in_Texture");
  174. data->m_tile_shader->SetUniform(uni_tex, 0);
  175. uni_texsize = data->m_tile_shader->GetUniformLocation("in_TexSize");
  176. for (int buf = 0, i = 0, n; i < data->m_tiles.Count(); i = n, buf += 2)
  177. {
  178. /* Count how many quads will be needed */
  179. for (n = i + 1; n < data->m_tiles.Count(); n++)
  180. if (data->m_tiles[i].tileset != data->m_tiles[n].tileset)
  181. break;
  182. /* Create a vertex array object */
  183. VertexBuffer *vb1 = new VertexBuffer(6 * 3 * (n - i) * sizeof(float));
  184. float *vertex = (float *)vb1->Lock(0, 0);
  185. VertexBuffer *vb2 = new VertexBuffer(6 * 2 * (n - i) * sizeof(float));
  186. float *texture = (float *)vb2->Lock(0, 0);
  187. data->m_tile_bufs.Push(vb1);
  188. data->m_tile_bufs.Push(vb2);
  189. for (int j = i; j < n; j++)
  190. {
  191. data->m_tiles[i].tileset->BlitTile(data->m_tiles[j].id,
  192. data->m_tiles[j].pos, data->m_tiles[j].o,
  193. data->m_tiles[j].scale,
  194. vertex + 18 * (j - i), texture + 12 * (j - i));
  195. }
  196. vb1->Unlock();
  197. vb2->Unlock();
  198. /* Bind texture */
  199. data->m_tiles[i].tileset->Bind();
  200. data->m_tile_shader->SetUniform(uni_texsize,
  201. (vec2)data->m_tiles[i].tileset->GetTextureSize());
  202. /* Bind vertex and texture coordinate buffers */
  203. data->m_tile_vdecl->Bind();
  204. data->m_tile_vdecl->SetStream(vb1, attr_pos);
  205. data->m_tile_vdecl->SetStream(vb2, attr_tex);
  206. /* Draw arrays */
  207. data->m_tile_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6);
  208. data->m_tile_vdecl->Unbind();
  209. data->m_tiles[i].tileset->Unbind();
  210. }
  211. data->m_tiles.Empty();
  212. data->m_tile_shader->Unbind();
  213. #if defined USE_D3D9 || defined _XBOX
  214. /* TODO */
  215. #elif !defined HAVE_GLES_2X
  216. glDisable(GL_TEXTURE_2D);
  217. #endif
  218. }
  219. void Scene::RenderLines() // XXX: rename to Blit()
  220. {
  221. RenderContext rc;
  222. if (!data->m_lines.Count())
  223. return;
  224. rc.SetDepthFunc(DepthFunc::LessOrEqual);
  225. rc.SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::OneMinusSrcAlpha);
  226. rc.SetAlphaFunc(AlphaFunc::GreaterOrEqual, 0.01f);
  227. int linecount = data->m_lines.Count();
  228. if (!data->m_line_shader)
  229. data->m_line_shader = Shader::Create(LOLFX_RESOURCE_NAME(line));
  230. VertexBuffer *vb = new VertexBuffer((sizeof(vec3) + sizeof(vec4)) * 2 * linecount);
  231. float *vertex = (float *)vb->Lock(0, 0);
  232. for (int i = 0; i < linecount; i++)
  233. {
  234. memcpy(vertex, &data->m_lines[i].m1, sizeof(vec3));
  235. vertex += 3;
  236. memcpy(vertex, &data->m_lines[i].m3, sizeof(vec4));
  237. vertex += 4;
  238. memcpy(vertex, &data->m_lines[i].m2, sizeof(vec3));
  239. vertex += 3;
  240. memcpy(vertex, &data->m_lines[i].m3, sizeof(vec4));
  241. vertex += 4;
  242. }
  243. vb->Unlock();
  244. data->m_line_shader->Bind();
  245. ShaderUniform uni_mat, uni_tex;
  246. ShaderAttrib attr_pos, attr_col;
  247. attr_pos = data->m_line_shader->GetAttribLocation(VertexUsage::Position, 0);
  248. attr_col = data->m_line_shader->GetAttribLocation(VertexUsage::Color, 0);
  249. data->m_line_shader->Bind();
  250. uni_mat = data->m_line_shader->GetUniformLocation("proj_matrix");
  251. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetProjection());
  252. uni_mat = data->m_line_shader->GetUniformLocation("view_matrix");
  253. data->m_line_shader->SetUniform(uni_mat, GetCamera()->GetView());
  254. data->m_line_vdecl->Bind();
  255. data->m_line_vdecl->SetStream(vb, attr_pos, attr_col);
  256. data->m_line_vdecl->DrawElements(MeshPrimitive::Lines, 0, 2 * linecount);
  257. data->m_line_vdecl->Unbind();
  258. data->m_line_shader->Unbind();
  259. data->m_lines.Empty();
  260. delete vb;
  261. }
  262. } /* namespace lol */