OpenGL.cpp 19 KB

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