OpenGL.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /**
  2. * Copyright (c) 2006-2014 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "common/config.h"
  22. #include "OpenGL.h"
  23. #include "Shader.h"
  24. #include "Canvas.h"
  25. #include "common/Exception.h"
  26. // C++
  27. #include <algorithm>
  28. // C
  29. #include <cstring>
  30. namespace love
  31. {
  32. namespace graphics
  33. {
  34. namespace opengl
  35. {
  36. OpenGL::OpenGL()
  37. : contextInitialized(false)
  38. , maxAnisotropy(1.0f)
  39. , maxTextureSize(0)
  40. , maxRenderTargets(0)
  41. , vendor(VENDOR_UNKNOWN)
  42. , state()
  43. {
  44. }
  45. void OpenGL::initContext()
  46. {
  47. if (contextInitialized)
  48. return;
  49. initOpenGLFunctions();
  50. initVendor();
  51. // Store the current color so we don't have to get it through GL later.
  52. GLfloat glcolor[4];
  53. glGetFloatv(GL_CURRENT_COLOR, glcolor);
  54. state.color.r = glcolor[0] * 255;
  55. state.color.g = glcolor[1] * 255;
  56. state.color.b = glcolor[2] * 255;
  57. state.color.a = glcolor[3] * 255;
  58. // Same with the current clear color.
  59. glGetFloatv(GL_COLOR_CLEAR_VALUE, glcolor);
  60. state.clearColor.r = glcolor[0] * 255;
  61. state.clearColor.g = glcolor[1] * 255;
  62. state.clearColor.b = glcolor[2] * 255;
  63. state.clearColor.a = glcolor[3] * 255;
  64. // Get the current viewport.
  65. glGetIntegerv(GL_VIEWPORT, (GLint *) &state.viewport.x);
  66. // And the current scissor - but we need to compensate for GL scissors
  67. // starting at the bottom left instead of top left.
  68. glGetIntegerv(GL_SCISSOR_BOX, (GLint *) &state.scissor.x);
  69. state.scissor.y = state.viewport.h - (state.scissor.y + state.scissor.h);
  70. // Initialize multiple texture unit support for shaders, if available.
  71. state.textureUnits.clear();
  72. if (Shader::isSupported())
  73. {
  74. GLint maxtextureunits;
  75. glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureunits);
  76. state.textureUnits.resize(maxtextureunits, 0);
  77. GLenum curgltextureunit;
  78. glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &curgltextureunit);
  79. state.curTextureUnit = (int) curgltextureunit - GL_TEXTURE0;
  80. // Retrieve currently bound textures for each texture unit.
  81. for (size_t i = 0; i < state.textureUnits.size(); i++)
  82. {
  83. glActiveTexture(GL_TEXTURE0 + i);
  84. glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &state.textureUnits[i]);
  85. }
  86. glActiveTexture(curgltextureunit);
  87. }
  88. else
  89. {
  90. // Multitexturing not supported, so we only have 1 texture unit.
  91. state.textureUnits.resize(1, 0);
  92. state.curTextureUnit = 0;
  93. glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &state.textureUnits[0]);
  94. }
  95. initMaxValues();
  96. createDefaultTexture();
  97. state.lastPseudoInstanceID = -1;
  98. contextInitialized = true;
  99. }
  100. void OpenGL::deInitContext()
  101. {
  102. if (!contextInitialized)
  103. return;
  104. contextInitialized = false;
  105. }
  106. void OpenGL::initVendor()
  107. {
  108. const char *vstr = (const char *) glGetString(GL_VENDOR);
  109. if (!vstr)
  110. {
  111. vendor = VENDOR_UNKNOWN;
  112. return;
  113. }
  114. // http://feedback.wildfiregames.com/report/opengl/feature/GL_VENDOR
  115. if (strstr(vstr, "ATI Technologies"))
  116. vendor = VENDOR_ATI_AMD;
  117. else if (strstr(vstr, "NVIDIA"))
  118. vendor = VENDOR_NVIDIA;
  119. else if (strstr(vstr, "Intel"))
  120. vendor = VENDOR_INTEL;
  121. else if (strstr(vstr, "Mesa"))
  122. vendor = VENDOR_MESA_SOFT;
  123. else if (strstr(vstr, "Apple Computer"))
  124. vendor = VENDOR_APPLE;
  125. else if (strstr(vstr, "Microsoft"))
  126. vendor = VENDOR_MICROSOFT;
  127. else
  128. vendor = VENDOR_UNKNOWN;
  129. }
  130. void OpenGL::initOpenGLFunctions()
  131. {
  132. // The functionality of the core and ARB VBOs are identical, so we can
  133. // assign the pointers of the core functions to the names of the ARB
  134. // functions, if the latter isn't supported but the former is.
  135. if (GLEE_VERSION_1_5 && !GLEE_ARB_vertex_buffer_object)
  136. {
  137. glBindBufferARB = (GLEEPFNGLBINDBUFFERARBPROC) glBindBuffer;
  138. glBufferDataARB = (GLEEPFNGLBUFFERDATAARBPROC) glBufferData;
  139. glBufferSubDataARB = (GLEEPFNGLBUFFERSUBDATAARBPROC) glBufferSubData;
  140. glDeleteBuffersARB = (GLEEPFNGLDELETEBUFFERSARBPROC) glDeleteBuffers;
  141. glGenBuffersARB = (GLEEPFNGLGENBUFFERSARBPROC) glGenBuffers;
  142. glGetBufferParameterivARB = (GLEEPFNGLGETBUFFERPARAMETERIVARBPROC) glGetBufferParameteriv;
  143. glGetBufferPointervARB = (GLEEPFNGLGETBUFFERPOINTERVARBPROC) glGetBufferPointerv;
  144. glGetBufferSubDataARB = (GLEEPFNGLGETBUFFERSUBDATAARBPROC) glGetBufferSubData;
  145. glIsBufferARB = (GLEEPFNGLISBUFFERARBPROC) glIsBuffer;
  146. glMapBufferARB = (GLEEPFNGLMAPBUFFERARBPROC) glMapBuffer;
  147. glUnmapBufferARB = (GLEEPFNGLUNMAPBUFFERARBPROC) glUnmapBuffer;
  148. }
  149. // Same deal for compressed textures.
  150. if (GLEE_VERSION_1_3 && !GLEE_ARB_texture_compression)
  151. {
  152. glCompressedTexImage2DARB = (GLEEPFNGLCOMPRESSEDTEXIMAGE2DARBPROC) glCompressedTexImage2D;
  153. glCompressedTexSubImage2DARB = (GLEEPFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) glCompressedTexSubImage2D;
  154. glGetCompressedTexImageARB = (GLEEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC) glGetCompressedTexImage;
  155. }
  156. }
  157. void OpenGL::initMaxValues()
  158. {
  159. // We'll need this value to clamp anisotropy.
  160. if (GLEE_EXT_texture_filter_anisotropic)
  161. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
  162. else
  163. maxAnisotropy = 1.0f;
  164. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
  165. if (Canvas::isSupported() && (GLEE_VERSION_2_0 || GLEE_ARB_draw_buffers))
  166. {
  167. int maxattachments = 0;
  168. glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments);
  169. int maxdrawbuffers = 0;
  170. glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers);
  171. maxRenderTargets = std::min(maxattachments, maxdrawbuffers);
  172. }
  173. else
  174. maxRenderTargets = 0;
  175. }
  176. void OpenGL::createDefaultTexture()
  177. {
  178. // Set the 'default' texture (id 0) as a repeating white pixel. Otherwise,
  179. // texture2D calls inside a shader would return black when drawing graphics
  180. // primitives, which would create the need to use different "passthrough"
  181. // shaders for untextured primitives vs images.
  182. GLuint curtexture = state.textureUnits[state.curTextureUnit];
  183. bindTexture(0);
  184. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  185. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  186. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  187. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  188. GLubyte pix = 255;
  189. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE8, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pix);
  190. bindTexture(curtexture);
  191. }
  192. void OpenGL::prepareDraw()
  193. {
  194. Shader *shader = Shader::current;
  195. if (shader != nullptr)
  196. {
  197. // Make sure the active shader has the correct values for its
  198. // love-provided uniforms.
  199. shader->checkSetScreenParams();
  200. // Make sure the Instance ID variable is up-to-date when
  201. // pseudo-instancing is used.
  202. if (state.lastPseudoInstanceID != 0 && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID))
  203. {
  204. glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, 0.0f);
  205. state.lastPseudoInstanceID = 0;
  206. }
  207. // We need to make sure antialiased Canvases are properly resolved
  208. // before sampling from their textures in a shader.
  209. // This is kind of a big hack. :(
  210. const std::map<std::string, Object *> &r = shader->getBoundRetainables();
  211. for (auto it = r.begin(); it != r.end(); ++it)
  212. {
  213. // Even bigger hack! D:
  214. Canvas *canvas = dynamic_cast<Canvas *>(it->second);
  215. if (canvas != nullptr)
  216. canvas->resolveMSAA();
  217. }
  218. }
  219. }
  220. void OpenGL::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
  221. {
  222. Shader *shader = Shader::current;
  223. if (GLEE_ARB_draw_instanced)
  224. glDrawArraysInstancedARB(mode, first, count, primcount);
  225. else
  226. {
  227. bool shaderHasID = shader && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID);
  228. // Pseudo-instancing fallback.
  229. for (int i = 0; i < primcount; i++)
  230. {
  231. if (shaderHasID)
  232. glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, (GLfloat) i);
  233. glDrawArrays(mode, first, count);
  234. }
  235. if (shaderHasID)
  236. state.lastPseudoInstanceID = primcount - 1;
  237. }
  238. }
  239. void OpenGL::drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount)
  240. {
  241. Shader *shader = Shader::current;
  242. if (GLEE_ARB_draw_instanced)
  243. glDrawElementsInstancedARB(mode, count, type, indices, primcount);
  244. else
  245. {
  246. bool shaderHasID = shader && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID);
  247. // Pseudo-instancing fallback.
  248. for (int i = 0; i < primcount; i++)
  249. {
  250. if (shaderHasID)
  251. glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, (GLfloat) i);
  252. glDrawElements(mode, count, type, indices);
  253. }
  254. if (shaderHasID)
  255. state.lastPseudoInstanceID = primcount - 1;
  256. }
  257. }
  258. void OpenGL::setColor(const Color &c)
  259. {
  260. glColor4ubv(&c.r);
  261. state.color = c;
  262. }
  263. Color OpenGL::getColor() const
  264. {
  265. return state.color;
  266. }
  267. void OpenGL::setClearColor(const Color &c)
  268. {
  269. glClearColor(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f);
  270. state.clearColor = c;
  271. }
  272. Color OpenGL::getClearColor() const
  273. {
  274. return state.clearColor;
  275. }
  276. void OpenGL::setViewport(const OpenGL::Viewport &v)
  277. {
  278. glViewport(v.x, v.y, v.w, v.h);
  279. state.viewport = v;
  280. // glScissor starts from the lower left, so we compensate when setting the
  281. // scissor. When the viewport is changed, we need to manually update the
  282. // scissor again.
  283. setScissor(state.scissor);
  284. }
  285. OpenGL::Viewport OpenGL::getViewport() const
  286. {
  287. return state.viewport;
  288. }
  289. void OpenGL::setScissor(const OpenGL::Viewport &v)
  290. {
  291. if (Canvas::current)
  292. glScissor(v.x, v.y, v.w, v.h);
  293. else
  294. {
  295. // With no Canvas active, we need to compensate for glScissor starting
  296. // from the lower left of the viewport instead of the top left.
  297. glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h);
  298. }
  299. state.scissor = v;
  300. }
  301. OpenGL::Viewport OpenGL::getScissor() const
  302. {
  303. return state.scissor;
  304. }
  305. void OpenGL::setTextureUnit(int textureunit)
  306. {
  307. if (textureunit < 0 || (size_t) textureunit >= state.textureUnits.size())
  308. throw love::Exception("Invalid texture unit index (%d).", textureunit);
  309. if (textureunit != state.curTextureUnit)
  310. {
  311. if (state.textureUnits.size() > 1)
  312. glActiveTexture(GL_TEXTURE0 + textureunit);
  313. else
  314. throw love::Exception("Multitexturing is not supported.");
  315. }
  316. state.curTextureUnit = textureunit;
  317. }
  318. void OpenGL::bindTexture(GLuint texture)
  319. {
  320. if (texture != state.textureUnits[state.curTextureUnit])
  321. {
  322. state.textureUnits[state.curTextureUnit] = texture;
  323. glBindTexture(GL_TEXTURE_2D, texture);
  324. }
  325. }
  326. void OpenGL::bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev)
  327. {
  328. if (textureunit < 0 || (size_t) textureunit >= state.textureUnits.size())
  329. throw love::Exception("Invalid texture unit index.");
  330. if (texture != state.textureUnits[textureunit])
  331. {
  332. int oldtextureunit = state.curTextureUnit;
  333. setTextureUnit(textureunit);
  334. state.textureUnits[textureunit] = texture;
  335. glBindTexture(GL_TEXTURE_2D, texture);
  336. if (restoreprev)
  337. setTextureUnit(oldtextureunit);
  338. }
  339. }
  340. void OpenGL::deleteTexture(GLuint texture)
  341. {
  342. // glDeleteTextures binds texture 0 to all texture units the deleted texture
  343. // was bound to before deletion.
  344. std::vector<GLuint>::iterator it;
  345. for (it = state.textureUnits.begin(); it != state.textureUnits.end(); ++it)
  346. {
  347. if (*it == texture)
  348. *it = 0;
  349. }
  350. glDeleteTextures(1, &texture);
  351. }
  352. float OpenGL::setTextureFilter(graphics::Texture::Filter &f)
  353. {
  354. GLint gmin, gmag;
  355. if (f.mipmap == Texture::FILTER_NONE)
  356. {
  357. if (f.min == Texture::FILTER_NEAREST)
  358. gmin = GL_NEAREST;
  359. else // f.min == Texture::FILTER_LINEAR
  360. gmin = GL_LINEAR;
  361. }
  362. else
  363. {
  364. if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_NEAREST)
  365. gmin = GL_NEAREST_MIPMAP_NEAREST;
  366. else if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_LINEAR)
  367. gmin = GL_NEAREST_MIPMAP_LINEAR;
  368. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_NEAREST)
  369. gmin = GL_LINEAR_MIPMAP_NEAREST;
  370. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_LINEAR)
  371. gmin = GL_LINEAR_MIPMAP_LINEAR;
  372. else
  373. gmin = GL_LINEAR;
  374. }
  375. switch (f.mag)
  376. {
  377. case Texture::FILTER_NEAREST:
  378. gmag = GL_NEAREST;
  379. break;
  380. case Texture::FILTER_LINEAR:
  381. default:
  382. gmag = GL_LINEAR;
  383. break;
  384. }
  385. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
  386. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
  387. if (GLEE_EXT_texture_filter_anisotropic)
  388. {
  389. f.anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy);
  390. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, f.anisotropy);
  391. }
  392. return f.anisotropy;
  393. }
  394. graphics::Texture::Filter OpenGL::getTextureFilter()
  395. {
  396. GLint gmin, gmag;
  397. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin);
  398. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag);
  399. Texture::Filter f;
  400. switch (gmin)
  401. {
  402. case GL_NEAREST:
  403. f.min = Texture::FILTER_NEAREST;
  404. f.mipmap = Texture::FILTER_NONE;
  405. break;
  406. case GL_NEAREST_MIPMAP_NEAREST:
  407. f.min = f.mipmap = Texture::FILTER_NEAREST;
  408. break;
  409. case GL_NEAREST_MIPMAP_LINEAR:
  410. f.min = Texture::FILTER_NEAREST;
  411. f.mipmap = Texture::FILTER_LINEAR;
  412. break;
  413. case GL_LINEAR_MIPMAP_NEAREST:
  414. f.min = Texture::FILTER_LINEAR;
  415. f.mipmap = Texture::FILTER_NEAREST;
  416. break;
  417. case GL_LINEAR_MIPMAP_LINEAR:
  418. f.min = f.mipmap = Texture::FILTER_LINEAR;
  419. break;
  420. case GL_LINEAR:
  421. default:
  422. f.min = Texture::FILTER_LINEAR;
  423. f.mipmap = Texture::FILTER_NONE;
  424. break;
  425. }
  426. switch (gmag)
  427. {
  428. case GL_NEAREST:
  429. f.mag = Texture::FILTER_NEAREST;
  430. break;
  431. case GL_LINEAR:
  432. default:
  433. f.mag = Texture::FILTER_LINEAR;
  434. break;
  435. }
  436. if (GLEE_EXT_texture_filter_anisotropic)
  437. glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &f.anisotropy);
  438. return f;
  439. }
  440. void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w)
  441. {
  442. GLint gs, gt;
  443. switch (w.s)
  444. {
  445. case Texture::WRAP_CLAMP:
  446. gs = GL_CLAMP_TO_EDGE;
  447. break;
  448. case Texture::WRAP_REPEAT:
  449. default:
  450. gs = GL_REPEAT;
  451. break;
  452. }
  453. switch (w.t)
  454. {
  455. case Texture::WRAP_CLAMP:
  456. gt = GL_CLAMP_TO_EDGE;
  457. break;
  458. case Texture::WRAP_REPEAT:
  459. default:
  460. gt = GL_REPEAT;
  461. break;
  462. }
  463. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs);
  464. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt);
  465. }
  466. graphics::Texture::Wrap OpenGL::getTextureWrap()
  467. {
  468. GLint gs, gt;
  469. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs);
  470. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &gt);
  471. Texture::Wrap w;
  472. switch (gs)
  473. {
  474. case GL_CLAMP_TO_EDGE:
  475. w.s = Texture::WRAP_CLAMP;
  476. break;
  477. case GL_REPEAT:
  478. default:
  479. w.s = Texture::WRAP_REPEAT;
  480. break;
  481. }
  482. switch (gt)
  483. {
  484. case GL_CLAMP_TO_EDGE:
  485. w.t = Texture::WRAP_CLAMP;
  486. break;
  487. case GL_REPEAT:
  488. default:
  489. w.t = Texture::WRAP_REPEAT;
  490. break;
  491. }
  492. return w;
  493. }
  494. int OpenGL::getMaxTextureSize() const
  495. {
  496. return maxTextureSize;
  497. }
  498. int OpenGL::getMaxRenderTargets() const
  499. {
  500. return maxRenderTargets;
  501. }
  502. OpenGL::Vendor OpenGL::getVendor() const
  503. {
  504. return vendor;
  505. }
  506. const char *OpenGL::debugSeverityString(GLenum severity)
  507. {
  508. switch (severity)
  509. {
  510. case GL_DEBUG_SEVERITY_HIGH:
  511. return "high";
  512. case GL_DEBUG_SEVERITY_MEDIUM:
  513. return "medium";
  514. case GL_DEBUG_SEVERITY_LOW:
  515. return "low";
  516. default:
  517. break;
  518. }
  519. return "unknown";
  520. }
  521. const char *OpenGL::debugSourceString(GLenum source)
  522. {
  523. switch (source)
  524. {
  525. case GL_DEBUG_SOURCE_API:
  526. return "API";
  527. case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
  528. return "window";
  529. case GL_DEBUG_SOURCE_SHADER_COMPILER:
  530. return "shader";
  531. case GL_DEBUG_SOURCE_THIRD_PARTY:
  532. return "external";
  533. case GL_DEBUG_SOURCE_APPLICATION:
  534. return "LOVE";
  535. case GL_DEBUG_SOURCE_OTHER:
  536. return "other";
  537. default:
  538. break;
  539. }
  540. return "unknown";
  541. }
  542. const char *OpenGL::debugTypeString(GLenum type)
  543. {
  544. switch (type)
  545. {
  546. case GL_DEBUG_TYPE_ERROR:
  547. return "error";
  548. case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
  549. return "deprecated behavior";
  550. case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
  551. return "undefined behavior";
  552. case GL_DEBUG_TYPE_PERFORMANCE:
  553. return "performance";
  554. case GL_DEBUG_TYPE_PORTABILITY:
  555. return "portability";
  556. case GL_DEBUG_TYPE_OTHER:
  557. return "other";
  558. default:
  559. break;
  560. }
  561. return "unknown";
  562. }
  563. // OpenGL class instance singleton.
  564. OpenGL gl;
  565. } // opengl
  566. } // graphics
  567. } // love