GLRenderer.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. /*
  2. Copyright (c) 2013 Daniele Bartolini, Michele Rossi
  3. Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
  4. Permission is hereby granted, free of charge, to any person
  5. obtaining a copy of this software and associated documentation
  6. files (the "Software"), to deal in the Software without
  7. restriction, including without limitation the rights to use,
  8. copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the
  10. Software is furnished to do so, subject to the following
  11. conditions:
  12. The above copyright notice and this permission notice shall be
  13. included in all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  16. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  19. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21. OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. #include <GL/glew.h>
  24. #include <algorithm>
  25. #include "Config.h"
  26. #include "Allocator.h"
  27. #include "Assert.h"
  28. #include "Types.h"
  29. #include "GLRenderer.h"
  30. #include "Log.h"
  31. #include "Vec2.h"
  32. #include "Vec3.h"
  33. #include "Vec4.h"
  34. #include "Mat3.h"
  35. #include "Mat4.h"
  36. #include "Device.h"
  37. #include "Hash.h"
  38. #include "StringUtils.h"
  39. namespace crown
  40. {
  41. //-----------------------------------------------------------------------------
  42. const GLenum TEXTURE_MIN_FILTER_TABLE[] =
  43. {
  44. 0, // Unused
  45. GL_NEAREST,
  46. GL_LINEAR,
  47. GL_NEAREST_MIPMAP_LINEAR,
  48. GL_LINEAR_MIPMAP_LINEAR
  49. };
  50. //-----------------------------------------------------------------------------
  51. const GLenum TEXTURE_MAG_FILTER_TABLE[] =
  52. {
  53. 0, // Unused
  54. GL_NEAREST,
  55. GL_LINEAR,
  56. GL_LINEAR,
  57. GL_LINEAR
  58. };
  59. //-----------------------------------------------------------------------------
  60. const GLenum TEXTURE_WRAP_TABLE[] =
  61. {
  62. 0, // Unused
  63. GL_CLAMP,
  64. GL_CLAMP_TO_EDGE,
  65. GL_CLAMP_TO_BORDER,
  66. GL_REPEAT
  67. };
  68. //-----------------------------------------------------------------------------
  69. GLRenderer::GLRenderer() :
  70. m_max_texture_size(0),
  71. m_max_texture_units(0),
  72. m_max_vertex_indices(0),
  73. m_max_vertex_vertices(0),
  74. m_max_anisotropy(0.0f),
  75. m_textures_id_table(m_allocator, CROWN_MAX_TEXTURES),
  76. m_active_texture_unit(0),
  77. m_vertex_buffers_id_table(m_allocator, CROWN_MAX_VERTEX_BUFFERS),
  78. m_index_buffers_id_table(m_allocator, CROWN_MAX_INDEX_BUFFERS),
  79. m_shaders_id_table(m_allocator, CROWN_MAX_SHADERS),
  80. m_gpu_programs_id_table(m_allocator, CROWN_MAX_GPU_PROGRAMS),
  81. m_uniforms_id_table(m_allocator, CROWN_MAX_UNIFORMS),
  82. m_render_targets_id_table(m_allocator, CROWN_MAX_RENDER_TARGETS)
  83. {
  84. m_min_max_point_size[0] = 0.0f;
  85. m_min_max_point_size[1] = 0.0f;
  86. m_min_max_line_width[0] = 0.0f;
  87. m_min_max_line_width[1] = 0.0f;
  88. // Initialize texture units
  89. for (uint32_t i = 0; i < CROWN_MAX_TEXTURE_UNITS; i++)
  90. {
  91. m_texture_unit[i] = 0;
  92. m_texture_unit_target[i] = GL_TEXTURE_2D;
  93. }
  94. }
  95. //-----------------------------------------------------------------------------
  96. GLRenderer::~GLRenderer()
  97. {
  98. }
  99. //-----------------------------------------------------------------------------
  100. void GLRenderer::init()
  101. {
  102. m_context.create_context();
  103. GLenum err = glewInit();
  104. CE_ASSERT(err == GLEW_OK, "Failed to initialize GLEW");
  105. GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_max_texture_size));
  106. GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &m_max_texture_units));
  107. GL_CHECK(glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &m_max_vertex_indices));
  108. GL_CHECK(glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &m_max_vertex_vertices));
  109. GL_CHECK(glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, &m_min_max_point_size[0]));
  110. GL_CHECK(glGetFloatv(GL_LINE_WIDTH_RANGE, &m_min_max_line_width[0]));
  111. Log::i("OpenGL Vendor : %s", glGetString(GL_VENDOR));
  112. Log::i("OpenGL Renderer : %s", glGetString(GL_RENDERER));
  113. Log::i("OpenGL Version : %s", glGetString(GL_VERSION));
  114. Log::i("GLSL Version : %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
  115. Log::d("Min Point Size : %f", m_min_max_point_size[0]);
  116. Log::d("Max Point Size : %f", m_min_max_point_size[1]);
  117. Log::d("Min Line Width : %f", m_min_max_line_width[0]);
  118. Log::d("Max Line Width : %f", m_min_max_line_width[1]);
  119. Log::d("Max Texture Size : %dx%d", m_max_texture_size, m_max_texture_size);
  120. Log::d("Max Texture Units : %d", m_max_texture_units);
  121. Log::d("Max Vertex Indices : %d", m_max_vertex_indices);
  122. Log::d("Max Vertex Vertices : %d", m_max_vertex_vertices);
  123. GL_CHECK(glDisable(GL_TEXTURE_2D));
  124. GL_CHECK(glDisable(GL_BLEND));
  125. GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
  126. GL_CHECK(glBlendEquation(GL_FUNC_ADD));
  127. GL_CHECK(glShadeModel(GL_SMOOTH));
  128. // Enable depth test
  129. GL_CHECK(glEnable(GL_DEPTH_TEST));
  130. GL_CHECK(glDepthFunc(GL_LEQUAL));
  131. GL_CHECK(glClearDepth(1.0));
  132. // Point sprites enabled by default
  133. GL_CHECK(glEnable(GL_POINT_SPRITE));
  134. GL_CHECK(glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE));
  135. Log::i("OpenGL Renderer initialized.");
  136. }
  137. //-----------------------------------------------------------------------------
  138. void GLRenderer::shutdown()
  139. {
  140. m_context.destroy_context();
  141. }
  142. //-----------------------------------------------------------------------------
  143. VertexBufferId GLRenderer::create_vertex_buffer(size_t count, VertexFormat format, const void* vertices)
  144. {
  145. const VertexBufferId id = m_vertex_buffers_id_table.create();
  146. VertexBuffer& buffer = m_vertex_buffers[id.index];
  147. buffer.create(count, format, vertices);
  148. return id;
  149. }
  150. //-----------------------------------------------------------------------------
  151. void GLRenderer::update_vertex_buffer(VertexBufferId id, size_t offset, size_t count, const void* vertices)
  152. {
  153. CE_ASSERT(m_vertex_buffers_id_table.has(id), "Vertex buffer does not exist");
  154. VertexBuffer& buffer = m_vertex_buffers[id.index];
  155. buffer.update(offset, count, vertices);
  156. }
  157. //-----------------------------------------------------------------------------
  158. void GLRenderer::destroy_vertex_buffer(VertexBufferId id)
  159. {
  160. CE_ASSERT(m_vertex_buffers_id_table.has(id), "Vertex buffer does not exist");
  161. VertexBuffer& buffer = m_vertex_buffers[id.index];
  162. buffer.destroy();
  163. m_vertex_buffers_id_table.destroy(id);
  164. }
  165. //-----------------------------------------------------------------------------
  166. IndexBufferId GLRenderer::create_index_buffer(size_t count, const void* indices)
  167. {
  168. const IndexBufferId id = m_index_buffers_id_table.create();
  169. IndexBuffer& buffer = m_index_buffers[id.index];
  170. buffer.create(count, indices);
  171. return id;
  172. }
  173. //-----------------------------------------------------------------------------
  174. void GLRenderer::destroy_index_buffer(IndexBufferId id)
  175. {
  176. CE_ASSERT(m_index_buffers_id_table.has(id), "Index buffer does not exist");
  177. IndexBuffer& buffer = m_index_buffers[id.index];
  178. buffer.destroy();
  179. m_index_buffers_id_table.destroy(id);
  180. }
  181. //-----------------------------------------------------------------------------
  182. TextureId GLRenderer::create_texture(uint32_t width, uint32_t height, PixelFormat format, const void* data)
  183. {
  184. const TextureId id = m_textures_id_table.create();
  185. Texture& texture = m_textures[id.index];
  186. texture.create(width, height, format, data);
  187. return id;
  188. }
  189. //-----------------------------------------------------------------------------
  190. void GLRenderer::update_texture(TextureId id, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const void* data)
  191. {
  192. CE_ASSERT(m_textures_id_table.has(id), "Texture does not exist");
  193. Texture& texture = m_textures[id.index];
  194. texture.update(x, y, width, height, data);
  195. }
  196. //-----------------------------------------------------------------------------
  197. void GLRenderer::destroy_texture(TextureId id)
  198. {
  199. CE_ASSERT(m_textures_id_table.has(id), "Texture does not exist");
  200. Texture& texture = m_textures[id.index];
  201. texture.destroy();
  202. m_textures_id_table.destroy(id);
  203. }
  204. //-----------------------------------------------------------------------------
  205. ShaderId GLRenderer::create_shader(ShaderType type, const char* text)
  206. {
  207. CE_ASSERT_NOT_NULL(text);
  208. const ShaderId& id = m_shaders_id_table.create();
  209. Shader& shader = m_shaders[id.index];
  210. shader.create(type, text);
  211. return id;
  212. }
  213. //-----------------------------------------------------------------------------
  214. void GLRenderer::destroy_shader(ShaderId id)
  215. {
  216. CE_ASSERT(m_shaders_id_table.has(id), "Shader does not exist");
  217. Shader& shader = m_shaders[id.index];
  218. shader.destroy();
  219. m_shaders_id_table.destroy(id);
  220. }
  221. //-----------------------------------------------------------------------------
  222. GPUProgramId GLRenderer::create_gpu_program(ShaderId vertex, ShaderId pixel)
  223. {
  224. CE_ASSERT(m_shaders_id_table.has(vertex), "Vertex shader does not exist");
  225. CE_ASSERT(m_shaders_id_table.has(pixel), "Pixel shader does not exist");
  226. const GPUProgramId id = m_gpu_programs_id_table.create();
  227. GPUProgram& program = m_gpu_programs[id.index];
  228. program.create(m_shaders[vertex.index], m_shaders[pixel.index]);
  229. return id;
  230. }
  231. //-----------------------------------------------------------------------------
  232. void GLRenderer::destroy_gpu_program(GPUProgramId id)
  233. {
  234. CE_ASSERT(m_gpu_programs_id_table.has(id), "GPU program does not exist");
  235. GPUProgram& program = m_gpu_programs[id.index];
  236. program.destroy();
  237. m_gpu_programs_id_table.destroy(id);
  238. }
  239. //-----------------------------------------------------------------------------
  240. UniformId GLRenderer::create_uniform(const char* name, UniformType type)
  241. {
  242. const UniformId id = m_uniforms_id_table.create();
  243. Uniform& uniform = m_uniforms[id.index];
  244. uniform.m_name = hash::murmur2_32(name, string::strlen(name), 0);
  245. uniform.m_type = type;
  246. return id;
  247. }
  248. //-----------------------------------------------------------------------------
  249. void GLRenderer::destroy_uniform(UniformId id)
  250. {
  251. CE_ASSERT(m_uniforms_id_table.has(id), "Uniform does not exist");
  252. m_uniforms_id_table.destroy(id);
  253. }
  254. //-----------------------------------------------------------------------------
  255. RenderTargetId GLRenderer::create_render_target(uint16_t width, uint16_t height, RenderTargetFormat format)
  256. {
  257. const RenderTargetId id = m_render_targets_id_table.create();
  258. RenderTarget& target = m_render_targets[id.index];
  259. target.create(width, height, format);
  260. return id;
  261. }
  262. //-----------------------------------------------------------------------------
  263. void GLRenderer::destroy_render_target(RenderTargetId id)
  264. {
  265. CE_ASSERT(m_render_targets_id_table.has(id), "Render target does not exist");
  266. RenderTarget& target = m_render_targets[id.index];
  267. target.destroy();
  268. m_render_targets_id_table.destroy(id);
  269. }
  270. // //-----------------------------------------------------------------------------
  271. // void GLRenderer::set_depth_test(bool test)
  272. // {
  273. // if (test)
  274. // {
  275. // GL_CHECK(glEnable(GL_DEPTH_TEST));
  276. // }
  277. // else
  278. // {
  279. // GL_CHECK(glDisable(GL_DEPTH_TEST));
  280. // }
  281. // }
  282. // //-----------------------------------------------------------------------------
  283. // void GLRenderer::set_depth_func(CompareFunction func)
  284. // {
  285. // GLenum gl_func = GL::compare_function(func);
  286. // GL_CHECK(glDepthFunc(gl_func));
  287. // }
  288. //-----------------------------------------------------------------------------
  289. void GLRenderer::frame()
  290. {
  291. //RenderTargetId old_rt;
  292. //old_rt.id = INVALID_ID;
  293. uint8_t layer = 0xFF;
  294. for (uint32_t s = 0; s < m_render_context.m_num_states; s++)
  295. {
  296. const uint64_t key_s = m_render_context.m_keys[s];
  297. RenderKey key;
  298. key.decode(key_s);
  299. const RenderState& cur_state = m_render_context.m_states[s];
  300. const uint64_t flags = cur_state.m_flags;
  301. //const RenderTargetId& cur_rt = m_render_context.m_targets[layer];
  302. // Check if layer changed
  303. if (key.m_layer != layer)
  304. {
  305. layer = key.m_layer;
  306. // Viewport
  307. const ViewRect& viewport = m_render_context.m_viewports[layer];
  308. GL_CHECK(glViewport(viewport.m_x, viewport.m_y, viewport.m_width, viewport.m_height));
  309. // Clear frame/depth buffer
  310. const ClearState& clear = m_render_context.m_clears[layer];
  311. if (clear.m_flags & (CLEAR_COLOR | CLEAR_DEPTH))
  312. {
  313. GLbitfield gl_clear = (clear.m_flags & CLEAR_COLOR) ? GL_COLOR_BUFFER_BIT : 0;
  314. gl_clear |= (clear.m_flags & CLEAR_DEPTH) ? GL_DEPTH_BUFFER_BIT : 0;
  315. GL_CHECK(glClearColor(clear.m_color.r, clear.m_color.g, clear.m_color.b, clear.m_color.a));
  316. GL_CHECK(glClearDepth(clear.m_depth));
  317. GL_CHECK(glClear(gl_clear));
  318. }
  319. }
  320. // Scissor
  321. const ViewRect& scissor = m_render_context.m_scissors[layer];
  322. if (scissor.area() != 0)
  323. {
  324. GL_CHECK(glEnable(GL_SCISSOR_TEST));
  325. GL_CHECK(glScissor(scissor.m_x, scissor.m_y, scissor.m_width, scissor.m_height));
  326. }
  327. else
  328. {
  329. GL_CHECK(glDisable(GL_SCISSOR_TEST));
  330. }
  331. // Depth write
  332. if (flags & (STATE_DEPTH_WRITE))
  333. {
  334. GL_CHECK(glDepthMask(flags & STATE_DEPTH_WRITE));
  335. }
  336. // Color/Alpha write
  337. if (flags & (STATE_COLOR_WRITE | STATE_ALPHA_WRITE))
  338. {
  339. GLboolean cw = !!(flags & STATE_COLOR_WRITE);
  340. GLboolean aw = !!(flags & STATE_ALPHA_WRITE);
  341. GL_CHECK(glColorMask(cw, cw, cw, aw));
  342. }
  343. // Face culling
  344. if (flags & (STATE_CULL_CW | STATE_CULL_CCW))
  345. {
  346. if (flags & STATE_CULL_CW)
  347. {
  348. GL_CHECK(glEnable(GL_CULL_FACE));
  349. GL_CHECK(glCullFace(GL_BACK));
  350. }
  351. else if (flags & STATE_CULL_CCW)
  352. {
  353. GL_CHECK(glEnable(GL_CULL_FACE));
  354. GL_CHECK(glCullFace(GL_FRONT));
  355. }
  356. }
  357. else
  358. {
  359. GL_CHECK(glDisable(GL_CULL_FACE));
  360. }
  361. // Bind GPU program
  362. if (cur_state.program.id != INVALID_ID)
  363. {
  364. const GPUProgram& gpu_program = m_gpu_programs[cur_state.program.index];
  365. GL_CHECK(glUseProgram(gpu_program.m_id));
  366. for (uint8_t uniform = 0; uniform < gpu_program.m_num_stock_uniforms; uniform++)
  367. {
  368. const GLint& uniform_location = gpu_program.m_stock_uniform_locations[uniform];
  369. const Mat4& view = m_render_context.m_view_matrices[layer];
  370. const Mat4& projection = m_render_context.m_projection_matrices[layer];
  371. switch (gpu_program.m_stock_uniforms[uniform])
  372. {
  373. case UNIFORM_VIEW:
  374. {
  375. GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, view.to_float_ptr()));
  376. break;
  377. }
  378. case UNIFORM_MODEL:
  379. {
  380. GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, cur_state.pose.to_float_ptr()));
  381. break;
  382. }
  383. case UNIFORM_MODEL_VIEW:
  384. {
  385. GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, (view *
  386. cur_state.pose).to_float_ptr()));
  387. break;
  388. }
  389. case UNIFORM_MODEL_VIEW_PROJECTION:
  390. {
  391. GL_CHECK(glUniformMatrix4fv(uniform_location, 1, GL_FALSE, (projection * view *
  392. cur_state.pose).to_float_ptr()));
  393. break;
  394. }
  395. case UNIFORM_TIME_SINCE_START:
  396. {
  397. GL_CHECK(glUniform1f(uniform_location, device()->time_since_start()));
  398. break;
  399. }
  400. default:
  401. {
  402. CE_ASSERT(false, "Oops, wrong stock uniform!");
  403. break;
  404. }
  405. }
  406. }
  407. }
  408. else
  409. {
  410. GL_CHECK(glUseProgram(0));
  411. }
  412. // Bind array buffers
  413. const VertexBufferId& vb = cur_state.vb;
  414. if (vb.id != INVALID_ID)
  415. {
  416. const VertexBuffer& vertex_buffer = m_vertex_buffers[vb.index];
  417. glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer.m_id);
  418. switch (vertex_buffer.m_format)
  419. {
  420. case VF_XY_FLOAT_32:
  421. {
  422. GL_CHECK(glEnableVertexAttribArray(ATTRIB_POSITION));
  423. GL_CHECK(glVertexAttribPointer(ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, 0));
  424. break;
  425. }
  426. case VF_XYZ_FLOAT_32:
  427. {
  428. GL_CHECK(glEnableVertexAttribArray(ATTRIB_POSITION));
  429. GL_CHECK(glVertexAttribPointer(ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0));
  430. break;
  431. }
  432. case VF_XYZ_NORMAL_FLOAT_32:
  433. {
  434. GL_CHECK(glEnableVertexAttribArray(ATTRIB_NORMAL));
  435. GL_CHECK(glVertexAttribPointer(ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, 0, 0));
  436. break;
  437. }
  438. // case VF_UV_FLOAT_32:
  439. // {
  440. // GL_CHECK(glEnableVertexAttribArray(SA_COORDS));
  441. // GL_CHECK(glVertexAttribPointer(SA_COORDS, 2, GL_FLOAT, GL_FALSE, 0, 0));
  442. // break;
  443. // }
  444. // case VF_UVT_FLOAT_32:
  445. // {
  446. // GL_CHECK(glEnableVertexAttribArray(SA_COORDS));
  447. // GL_CHECK(glVertexAttribPointer(SA_COORDS, 3, GL_FLOAT, GL_FALSE, 0, 0));
  448. // break;
  449. // }
  450. case VF_XYZ_UV_XYZ_NORMAL_FLOAT_32:
  451. {
  452. break;
  453. }
  454. default:
  455. {
  456. CE_ASSERT(false, "Oops, vertex format unknown!");
  457. break;
  458. }
  459. }
  460. }
  461. else
  462. {
  463. GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
  464. }
  465. const IndexBufferId& ib = cur_state.ib;
  466. if (ib.id != INVALID_ID)
  467. {
  468. const IndexBuffer& index_buffer = m_index_buffers[ib.index];
  469. GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer.m_id));
  470. GL_CHECK(glDrawElements(GL_TRIANGLES, index_buffer.m_index_count, GL_UNSIGNED_SHORT, 0));
  471. }
  472. else
  473. {
  474. GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
  475. }
  476. }
  477. GL_CHECK(glFinish());
  478. m_render_context.clear();
  479. m_context.swap_buffers();
  480. }
  481. //-----------------------------------------------------------------------------
  482. void GLRenderer::draw_lines(const float* vertices, const float* colors, uint32_t count)
  483. {
  484. GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
  485. GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
  486. GL_CHECK(glEnableClientState(GL_VERTEX_ARRAY));
  487. GL_CHECK(glEnableClientState(GL_COLOR_ARRAY));
  488. GL_CHECK(glVertexPointer(3, GL_FLOAT, 0, vertices));
  489. GL_CHECK(glColorPointer(4, GL_FLOAT, 0, colors));
  490. GL_CHECK(glDrawArrays(GL_LINES, 0, count));
  491. GL_CHECK(glDisableClientState(GL_COLOR_ARRAY));
  492. GL_CHECK(glDisableClientState(GL_VERTEX_ARRAY));
  493. }
  494. //-----------------------------------------------------------------------------
  495. Renderer* Renderer::create(Allocator& a)
  496. {
  497. return CE_NEW(a, GLRenderer);
  498. }
  499. //-----------------------------------------------------------------------------
  500. void Renderer::destroy(Allocator& a, Renderer* renderer)
  501. {
  502. CE_DELETE(a, renderer);
  503. }
  504. } // namespace crown