OpenGL.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. /**
  2. * Copyright (c) 2006-2015 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. #include <limits>
  29. // C
  30. #include <cstring>
  31. // For SDL_GL_GetProcAddress.
  32. #include <SDL_video.h>
  33. #ifdef LOVE_IOS
  34. #include <SDL_syswm.h>
  35. #endif
  36. namespace love
  37. {
  38. namespace graphics
  39. {
  40. namespace opengl
  41. {
  42. OpenGL::OpenGL()
  43. : stats()
  44. , contextInitialized(false)
  45. , maxAnisotropy(1.0f)
  46. , maxTextureSize(0)
  47. , maxRenderTargets(1)
  48. , maxRenderbufferSamples(0)
  49. , maxTextureUnits(1)
  50. , vendor(VENDOR_UNKNOWN)
  51. , state()
  52. {
  53. matrices.transform.reserve(10);
  54. matrices.projection.reserve(2);
  55. }
  56. bool OpenGL::initContext()
  57. {
  58. if (contextInitialized)
  59. return true;
  60. if (!gladLoadGLLoader(SDL_GL_GetProcAddress))
  61. return false;
  62. initOpenGLFunctions();
  63. initVendor();
  64. initMatrices();
  65. contextInitialized = true;
  66. return true;
  67. }
  68. void OpenGL::setupContext()
  69. {
  70. if (!contextInitialized)
  71. return;
  72. initMaxValues();
  73. GLfloat glcolor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  74. glVertexAttrib4fv(ATTRIB_COLOR, glcolor);
  75. glVertexAttrib4fv(ATTRIB_CONSTANTCOLOR, glcolor);
  76. GLint maxvertexattribs = 1;
  77. glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxvertexattribs);
  78. state.enabledAttribArrays = 1u << uint32(maxvertexattribs - 1);
  79. useVertexAttribArrays(0);
  80. // Get the current viewport.
  81. glGetIntegerv(GL_VIEWPORT, (GLint *) &state.viewport.x);
  82. // And the current scissor - but we need to compensate for GL scissors
  83. // starting at the bottom left instead of top left.
  84. glGetIntegerv(GL_SCISSOR_BOX, (GLint *) &state.scissor.x);
  85. state.scissor.y = state.viewport.h - (state.scissor.y + state.scissor.h);
  86. if (GLAD_VERSION_1_0)
  87. glGetFloatv(GL_POINT_SIZE, &state.pointSize);
  88. else
  89. state.pointSize = 1.0f;
  90. if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
  91. || GLAD_EXT_sRGB_write_control)
  92. {
  93. state.framebufferSRGBEnabled = (glIsEnabled(GL_FRAMEBUFFER_SRGB) == GL_TRUE);
  94. }
  95. else
  96. state.framebufferSRGBEnabled = false;
  97. // Initialize multiple texture unit support for shaders.
  98. state.boundTextures.clear();
  99. state.boundTextures.resize(maxTextureUnits, 0);
  100. GLenum curgltextureunit;
  101. glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &curgltextureunit);
  102. state.curTextureUnit = (int) curgltextureunit - GL_TEXTURE0;
  103. // Retrieve currently bound textures for each texture unit.
  104. for (int i = 0; i < (int) state.boundTextures.size(); i++)
  105. {
  106. glActiveTexture(GL_TEXTURE0 + i);
  107. glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &state.boundTextures[i]);
  108. }
  109. glActiveTexture(curgltextureunit);
  110. createDefaultTexture();
  111. // Invalidate the cached matrices by setting some elements to NaN.
  112. float nan = std::numeric_limits<float>::quiet_NaN();
  113. state.lastProjectionMatrix.setTranslation(nan, nan);
  114. state.lastTransformMatrix.setTranslation(nan, nan);
  115. if (GLAD_VERSION_1_0)
  116. glMatrixMode(GL_MODELVIEW);
  117. contextInitialized = true;
  118. }
  119. void OpenGL::deInitContext()
  120. {
  121. if (!contextInitialized)
  122. return;
  123. glDeleteTextures(1, &state.defaultTexture);
  124. state.defaultTexture = 0;
  125. contextInitialized = false;
  126. }
  127. void OpenGL::initVendor()
  128. {
  129. const char *vstr = (const char *) glGetString(GL_VENDOR);
  130. if (!vstr)
  131. {
  132. vendor = VENDOR_UNKNOWN;
  133. return;
  134. }
  135. // http://feedback.wildfiregames.com/report/opengl/feature/GL_VENDOR
  136. // http://stackoverflow.com/questions/2093594/opengl-extensions-available-on-different-android-devices
  137. if (strstr(vstr, "ATI Technologies"))
  138. vendor = VENDOR_AMD;
  139. else if (strstr(vstr, "NVIDIA"))
  140. vendor = VENDOR_NVIDIA;
  141. else if (strstr(vstr, "Intel"))
  142. vendor = VENDOR_INTEL;
  143. else if (strstr(vstr, "Mesa"))
  144. vendor = VENDOR_MESA_SOFT;
  145. else if (strstr(vstr, "Apple Computer") || strstr(vstr, "Apple Inc."))
  146. vendor = VENDOR_APPLE;
  147. else if (strstr(vstr, "Microsoft"))
  148. vendor = VENDOR_MICROSOFT;
  149. else if (strstr(vstr, "Imagination"))
  150. vendor = VENDOR_IMGTEC;
  151. else if (strstr(vstr, "ARM"))
  152. vendor = VENDOR_ARM;
  153. else if (strstr(vstr, "Qualcomm"))
  154. vendor = VENDOR_QUALCOMM;
  155. else if (strstr(vstr, "Broadcom"))
  156. vendor = VENDOR_BROADCOM;
  157. else if (strstr(vstr, "Vivante"))
  158. vendor = VENDOR_VIVANTE;
  159. else
  160. vendor = VENDOR_UNKNOWN;
  161. }
  162. void OpenGL::initOpenGLFunctions()
  163. {
  164. // Alias extension-suffixed framebuffer functions to core versions since
  165. // there are so many different-named extensions that do the same things...
  166. if (!(GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
  167. {
  168. if (GLAD_VERSION_1_0 && GLAD_EXT_framebuffer_object)
  169. {
  170. fp_glBindRenderbuffer = fp_glBindRenderbufferEXT;
  171. fp_glDeleteRenderbuffers = fp_glDeleteRenderbuffersEXT;
  172. fp_glGenRenderbuffers = fp_glGenRenderbuffersEXT;
  173. fp_glRenderbufferStorage = fp_glRenderbufferStorageEXT;
  174. fp_glGetRenderbufferParameteriv = fp_glGetRenderbufferParameterivEXT;
  175. fp_glBindFramebuffer = fp_glBindFramebufferEXT;
  176. fp_glDeleteFramebuffers = fp_glDeleteFramebuffersEXT;
  177. fp_glGenFramebuffers = fp_glGenFramebuffersEXT;
  178. fp_glCheckFramebufferStatus = fp_glCheckFramebufferStatusEXT;
  179. fp_glFramebufferTexture2D = fp_glFramebufferTexture2DEXT;
  180. fp_glFramebufferRenderbuffer = fp_glFramebufferRenderbufferEXT;
  181. fp_glGetFramebufferAttachmentParameteriv = fp_glGetFramebufferAttachmentParameterivEXT;
  182. fp_glGenerateMipmap = fp_glGenerateMipmapEXT;
  183. }
  184. if (GLAD_EXT_framebuffer_blit)
  185. fp_glBlitFramebuffer = fp_glBlitFramebufferEXT;
  186. else if (GLAD_ANGLE_framebuffer_blit)
  187. fp_glBlitFramebuffer = fp_glBlitFramebufferANGLE;
  188. else if (GLAD_NV_framebuffer_blit)
  189. fp_glBlitFramebuffer = fp_glBlitFramebufferNV;
  190. if (GLAD_EXT_framebuffer_multisample)
  191. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleEXT;
  192. else if (GLAD_APPLE_framebuffer_multisample)
  193. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleAPPLE;
  194. else if (GLAD_ANGLE_framebuffer_multisample)
  195. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleANGLE;
  196. else if (GLAD_NV_framebuffer_multisample)
  197. fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleNV;
  198. }
  199. }
  200. void OpenGL::initMaxValues()
  201. {
  202. // We'll need this value to clamp anisotropy.
  203. if (GLAD_EXT_texture_filter_anisotropic)
  204. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
  205. else
  206. maxAnisotropy = 1.0f;
  207. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
  208. int maxattachments = 1;
  209. int maxdrawbuffers = 1;
  210. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_0)
  211. {
  212. glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments);
  213. glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers);
  214. }
  215. maxRenderTargets = std::min(maxattachments, maxdrawbuffers);
  216. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object
  217. || GLAD_EXT_framebuffer_multisample || GLAD_APPLE_framebuffer_multisample
  218. || GLAD_ANGLE_framebuffer_multisample)
  219. {
  220. glGetIntegerv(GL_MAX_SAMPLES, &maxRenderbufferSamples);
  221. }
  222. else
  223. maxRenderbufferSamples = 0;
  224. glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
  225. }
  226. void OpenGL::initMatrices()
  227. {
  228. matrices.transform.clear();
  229. matrices.projection.clear();
  230. matrices.transform.push_back(Matrix());
  231. matrices.projection.push_back(Matrix());
  232. }
  233. void OpenGL::createDefaultTexture()
  234. {
  235. // Set the 'default' texture (id 0) as a repeating white pixel. Otherwise,
  236. // texture2D calls inside a shader would return black when drawing graphics
  237. // primitives, which would create the need to use different "passthrough"
  238. // shaders for untextured primitives vs images.
  239. GLuint curtexture = state.boundTextures[state.curTextureUnit];
  240. glGenTextures(1, &state.defaultTexture);
  241. bindTexture(state.defaultTexture);
  242. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  243. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  244. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  245. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  246. GLubyte pix[] = {255, 255, 255, 255};
  247. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix);
  248. bindTexture(curtexture);
  249. }
  250. void OpenGL::pushTransform()
  251. {
  252. matrices.transform.push_back(matrices.transform.back());
  253. }
  254. void OpenGL::popTransform()
  255. {
  256. matrices.transform.pop_back();
  257. }
  258. Matrix &OpenGL::getTransform()
  259. {
  260. return matrices.transform.back();
  261. }
  262. void OpenGL::prepareDraw()
  263. {
  264. TempDebugGroup debuggroup("Prepare OpenGL draw");
  265. Shader *shader = Shader::current;
  266. if (shader != nullptr)
  267. {
  268. // Make sure the active shader has the correct values for its love-
  269. // provided uniforms.
  270. shader->checkSetScreenParams();
  271. }
  272. const Matrix &curproj = matrices.projection.back();
  273. const Matrix &curxform = matrices.transform.back();
  274. if (GLAD_ES_VERSION_2_0 && shader)
  275. {
  276. // Send built-in uniforms to the current shader.
  277. shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_MATRIX, 4, curxform.getElements(), 1);
  278. shader->sendBuiltinMatrix(Shader::BUILTIN_PROJECTION_MATRIX, 4, curproj.getElements(), 1);
  279. Matrix tp_matrix(curproj * curxform);
  280. shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX, 4, tp_matrix.getElements(), 1);
  281. shader->checkSetPointSize(state.pointSize);
  282. }
  283. else if (GLAD_VERSION_1_0)
  284. {
  285. const Matrix &lastproj = state.lastProjectionMatrix;
  286. const Matrix &lastxform = state.lastTransformMatrix;
  287. // We only need to re-upload the projection matrix if it's changed.
  288. if (memcmp(curproj.getElements(), lastproj.getElements(), sizeof(float) * 16) != 0)
  289. {
  290. glMatrixMode(GL_PROJECTION);
  291. glLoadMatrixf(curproj.getElements());
  292. glMatrixMode(GL_MODELVIEW);
  293. state.lastProjectionMatrix = matrices.projection.back();
  294. }
  295. // Same with the transform matrix.
  296. if (memcmp(curxform.getElements(), lastxform.getElements(), sizeof(float) * 16) != 0)
  297. {
  298. glLoadMatrixf(curxform.getElements());
  299. state.lastTransformMatrix = matrices.transform.back();
  300. }
  301. }
  302. }
  303. void OpenGL::drawArrays(GLenum mode, GLint first, GLsizei count)
  304. {
  305. glDrawArrays(mode, first, count);
  306. ++stats.drawCalls;
  307. }
  308. void OpenGL::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
  309. {
  310. glDrawElements(mode, count, type, indices);
  311. ++stats.drawCalls;
  312. }
  313. void OpenGL::useVertexAttribArrays(uint32 arraybits)
  314. {
  315. uint32 diff = arraybits ^ state.enabledAttribArrays;
  316. if (diff == 0)
  317. return;
  318. // Max 32 attributes. As of when this was written, no GL driver exposes more
  319. // than 32. Lets hope that doesn't change...
  320. for (uint32 i = 0; i < 32; i++)
  321. {
  322. uint32 bit = 1 << i;
  323. if (diff & bit)
  324. {
  325. if (arraybits & bit)
  326. glEnableVertexAttribArray(i);
  327. else
  328. glDisableVertexAttribArray(i);
  329. }
  330. }
  331. state.enabledAttribArrays = arraybits;
  332. // glDisableVertexAttribArray will make the constant value for a vertex
  333. // attribute undefined. We rely on the per-vertex color attribte being white
  334. // when no per-vertex color is used, so we set it here.
  335. // FIXME: Is there a better place to do this?
  336. if ((diff & ATTRIBFLAG_COLOR) && !(arraybits & ATTRIBFLAG_COLOR))
  337. glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
  338. }
  339. void OpenGL::setViewport(const OpenGL::Viewport &v)
  340. {
  341. glViewport(v.x, v.y, v.w, v.h);
  342. state.viewport = v;
  343. // glScissor starts from the lower left, so we compensate when setting the
  344. // scissor. When the viewport is changed, we need to manually update the
  345. // scissor again.
  346. setScissor(state.scissor);
  347. }
  348. OpenGL::Viewport OpenGL::getViewport() const
  349. {
  350. return state.viewport;
  351. }
  352. void OpenGL::setScissor(const OpenGL::Viewport &v)
  353. {
  354. if (Canvas::current)
  355. glScissor(v.x, v.y, v.w, v.h);
  356. else
  357. {
  358. // With no Canvas active, we need to compensate for glScissor starting
  359. // from the lower left of the viewport instead of the top left.
  360. glScissor(v.x, state.viewport.h - (v.y + v.h), v.w, v.h);
  361. }
  362. state.scissor = v;
  363. }
  364. OpenGL::Viewport OpenGL::getScissor() const
  365. {
  366. return state.scissor;
  367. }
  368. void OpenGL::setPointSize(float size)
  369. {
  370. if (GLAD_VERSION_1_0)
  371. glPointSize(size);
  372. state.pointSize = size;
  373. }
  374. float OpenGL::getPointSize() const
  375. {
  376. return state.pointSize;
  377. }
  378. void OpenGL::setFramebufferSRGB(bool enable)
  379. {
  380. if (enable)
  381. glEnable(GL_FRAMEBUFFER_SRGB);
  382. else
  383. glDisable(GL_FRAMEBUFFER_SRGB);
  384. state.framebufferSRGBEnabled = enable;
  385. }
  386. bool OpenGL::hasFramebufferSRGB() const
  387. {
  388. return state.framebufferSRGBEnabled;
  389. }
  390. void OpenGL::bindFramebuffer(GLenum target, GLuint framebuffer)
  391. {
  392. glBindFramebuffer(target, framebuffer);
  393. if (target == GL_FRAMEBUFFER)
  394. ++stats.framebufferBinds;
  395. }
  396. GLuint OpenGL::getDefaultFBO() const
  397. {
  398. #ifdef LOVE_IOS
  399. // Hack: iOS uses a custom FBO.
  400. SDL_SysWMinfo info = {};
  401. SDL_VERSION(&info.version);
  402. SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
  403. return info.info.uikit.framebuffer;
  404. #else
  405. return 0;
  406. #endif
  407. }
  408. GLuint OpenGL::getDefaultTexture() const
  409. {
  410. return state.defaultTexture;
  411. }
  412. void OpenGL::setTextureUnit(int textureunit)
  413. {
  414. if (textureunit < 0 || (size_t) textureunit >= state.boundTextures.size())
  415. throw love::Exception("Invalid texture unit index (%d).", textureunit);
  416. if (textureunit != state.curTextureUnit)
  417. glActiveTexture(GL_TEXTURE0 + textureunit);
  418. state.curTextureUnit = textureunit;
  419. }
  420. void OpenGL::bindTexture(GLuint texture)
  421. {
  422. if (texture != state.boundTextures[state.curTextureUnit])
  423. {
  424. state.boundTextures[state.curTextureUnit] = texture;
  425. glBindTexture(GL_TEXTURE_2D, texture);
  426. }
  427. }
  428. void OpenGL::bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev)
  429. {
  430. if (textureunit < 0 || (size_t) textureunit >= state.boundTextures.size())
  431. throw love::Exception("Invalid texture unit index.");
  432. if (texture != state.boundTextures[textureunit])
  433. {
  434. int oldtextureunit = state.curTextureUnit;
  435. setTextureUnit(textureunit);
  436. state.boundTextures[textureunit] = texture;
  437. glBindTexture(GL_TEXTURE_2D, texture);
  438. if (restoreprev)
  439. setTextureUnit(oldtextureunit);
  440. }
  441. }
  442. void OpenGL::deleteTexture(GLuint texture)
  443. {
  444. // glDeleteTextures binds texture 0 to all texture units the deleted texture
  445. // was bound to before deletion.
  446. for (GLuint &texid : state.boundTextures)
  447. {
  448. if (texid == texture)
  449. texid = 0;
  450. }
  451. glDeleteTextures(1, &texture);
  452. }
  453. void OpenGL::setTextureFilter(graphics::Texture::Filter &f)
  454. {
  455. GLint gmin, gmag;
  456. if (f.mipmap == Texture::FILTER_NONE)
  457. {
  458. if (f.min == Texture::FILTER_NEAREST)
  459. gmin = GL_NEAREST;
  460. else // f.min == Texture::FILTER_LINEAR
  461. gmin = GL_LINEAR;
  462. }
  463. else
  464. {
  465. if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_NEAREST)
  466. gmin = GL_NEAREST_MIPMAP_NEAREST;
  467. else if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_LINEAR)
  468. gmin = GL_NEAREST_MIPMAP_LINEAR;
  469. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_NEAREST)
  470. gmin = GL_LINEAR_MIPMAP_NEAREST;
  471. else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_LINEAR)
  472. gmin = GL_LINEAR_MIPMAP_LINEAR;
  473. else
  474. gmin = GL_LINEAR;
  475. }
  476. switch (f.mag)
  477. {
  478. case Texture::FILTER_NEAREST:
  479. gmag = GL_NEAREST;
  480. break;
  481. case Texture::FILTER_LINEAR:
  482. default:
  483. gmag = GL_LINEAR;
  484. break;
  485. }
  486. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
  487. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
  488. if (GLAD_EXT_texture_filter_anisotropic)
  489. {
  490. f.anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy);
  491. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, f.anisotropy);
  492. }
  493. else
  494. f.anisotropy = 1.0f;
  495. }
  496. void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w)
  497. {
  498. auto glWrapMode = [](Texture::WrapMode wmode) -> GLint
  499. {
  500. switch (wmode)
  501. {
  502. case Texture::WRAP_CLAMP:
  503. default:
  504. return GL_CLAMP_TO_EDGE;
  505. case Texture::WRAP_REPEAT:
  506. return GL_REPEAT;
  507. case Texture::WRAP_MIRRORED_REPEAT:
  508. return GL_MIRRORED_REPEAT;
  509. }
  510. };
  511. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapMode(w.s));
  512. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapMode(w.t));
  513. }
  514. int OpenGL::getMaxTextureSize() const
  515. {
  516. return maxTextureSize;
  517. }
  518. int OpenGL::getMaxRenderTargets() const
  519. {
  520. return maxRenderTargets;
  521. }
  522. int OpenGL::getMaxRenderbufferSamples() const
  523. {
  524. return maxRenderbufferSamples;
  525. }
  526. int OpenGL::getMaxTextureUnits() const
  527. {
  528. return maxTextureUnits;
  529. }
  530. void OpenGL::updateTextureMemorySize(size_t oldsize, size_t newsize)
  531. {
  532. int64 memsize = (int64) stats.textureMemory + ((int64 )newsize - (int64) oldsize);
  533. stats.textureMemory = (size_t) std::max(memsize, (int64) 0);
  534. }
  535. OpenGL::Vendor OpenGL::getVendor() const
  536. {
  537. return vendor;
  538. }
  539. const char *OpenGL::debugSeverityString(GLenum severity)
  540. {
  541. switch (severity)
  542. {
  543. case GL_DEBUG_SEVERITY_HIGH:
  544. return "high";
  545. case GL_DEBUG_SEVERITY_MEDIUM:
  546. return "medium";
  547. case GL_DEBUG_SEVERITY_LOW:
  548. return "low";
  549. default:
  550. return "unknown";
  551. }
  552. }
  553. const char *OpenGL::debugSourceString(GLenum source)
  554. {
  555. switch (source)
  556. {
  557. case GL_DEBUG_SOURCE_API:
  558. return "API";
  559. case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
  560. return "window";
  561. case GL_DEBUG_SOURCE_SHADER_COMPILER:
  562. return "shader";
  563. case GL_DEBUG_SOURCE_THIRD_PARTY:
  564. return "external";
  565. case GL_DEBUG_SOURCE_APPLICATION:
  566. return "LOVE";
  567. case GL_DEBUG_SOURCE_OTHER:
  568. return "other";
  569. default:
  570. return "unknown";
  571. }
  572. }
  573. const char *OpenGL::debugTypeString(GLenum type)
  574. {
  575. switch (type)
  576. {
  577. case GL_DEBUG_TYPE_ERROR:
  578. return "error";
  579. case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
  580. return "deprecated behavior";
  581. case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
  582. return "undefined behavior";
  583. case GL_DEBUG_TYPE_PERFORMANCE:
  584. return "performance";
  585. case GL_DEBUG_TYPE_PORTABILITY:
  586. return "portability";
  587. case GL_DEBUG_TYPE_OTHER:
  588. return "other";
  589. default:
  590. return "unknown";
  591. }
  592. }
  593. // OpenGL class instance singleton.
  594. OpenGL gl;
  595. } // opengl
  596. } // graphics
  597. } // love