OpenGL.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /**
  2. * Copyright (c) 2006-2013 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. #include "OpenGL.h"
  21. // LOVE
  22. #include "common/config.h"
  23. #include "common/Exception.h"
  24. #include "Shader.h"
  25. // STL
  26. #include <algorithm>
  27. namespace love
  28. {
  29. namespace graphics
  30. {
  31. namespace opengl
  32. {
  33. OpenGL::OpenGL()
  34. : contextInitialized(false)
  35. , maxAnisotropy(1.0f)
  36. , state()
  37. {
  38. }
  39. void OpenGL::initContext()
  40. {
  41. if (contextInitialized)
  42. return;
  43. initOpenGLFunctions();
  44. // Store the current color so we don't have to get it through GL later.
  45. GLfloat glcolor[4];
  46. glGetFloatv(GL_CURRENT_COLOR, glcolor);
  47. state.color.r = glcolor[0];
  48. state.color.g = glcolor[1];
  49. state.color.b = glcolor[2];
  50. state.color.a = glcolor[3];
  51. // Initialize multiple texture unit support for shaders, if available.
  52. state.textureUnits.clear();
  53. if (Shader::isSupported())
  54. {
  55. GLint maxtextureunits;
  56. glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureunits);
  57. state.textureUnits.resize(maxtextureunits, 0);
  58. GLenum curgltextureunit;
  59. glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &curgltextureunit);
  60. state.curTextureUnit = curgltextureunit - GL_TEXTURE0;
  61. // Retrieve currently bound textures for each texture unit.
  62. for (size_t i = 0; i < state.textureUnits.size(); i++)
  63. {
  64. glActiveTexture(GL_TEXTURE0 + i);
  65. glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &state.textureUnits[i]);
  66. }
  67. glActiveTexture(curgltextureunit);
  68. }
  69. else
  70. {
  71. // Multitexturing not supported, so we only have 1 texture unit.
  72. state.textureUnits.resize(1, 0);
  73. state.curTextureUnit = 0;
  74. glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &state.textureUnits[0]);
  75. }
  76. // We'll need this value to clamp anisotropy.
  77. if (GLEE_EXT_texture_filter_anisotropic)
  78. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
  79. else
  80. maxAnisotropy = 1.0f;
  81. createDefaultTexture();
  82. contextInitialized = true;
  83. }
  84. void OpenGL::deInitContext()
  85. {
  86. if (!contextInitialized)
  87. return;
  88. contextInitialized = false;
  89. }
  90. void OpenGL::initOpenGLFunctions()
  91. {
  92. // The functionality of the core and ARB VBOs are identical, so we can
  93. // assign the pointers of the core functions to the names of the ARB
  94. // functions, if the latter isn't supported but the former is.
  95. if (GLEE_VERSION_1_5 && !GLEE_ARB_vertex_buffer_object)
  96. {
  97. glBindBufferARB = (GLEEPFNGLBINDBUFFERARBPROC) glBindBuffer;
  98. glBufferDataARB = (GLEEPFNGLBUFFERDATAARBPROC) glBufferData;
  99. glBufferSubDataARB = (GLEEPFNGLBUFFERSUBDATAARBPROC) glBufferSubData;
  100. glDeleteBuffersARB = (GLEEPFNGLDELETEBUFFERSARBPROC) glDeleteBuffers;
  101. glGenBuffersARB = (GLEEPFNGLGENBUFFERSARBPROC) glGenBuffers;
  102. glGetBufferParameterivARB = (GLEEPFNGLGETBUFFERPARAMETERIVARBPROC) glGetBufferParameteriv;
  103. glGetBufferPointervARB = (GLEEPFNGLGETBUFFERPOINTERVARBPROC) glGetBufferPointerv;
  104. glGetBufferSubDataARB = (GLEEPFNGLGETBUFFERSUBDATAARBPROC) glGetBufferSubData;
  105. glIsBufferARB = (GLEEPFNGLISBUFFERARBPROC) glIsBuffer;
  106. glMapBufferARB = (GLEEPFNGLMAPBUFFERARBPROC) glMapBuffer;
  107. glUnmapBufferARB = (GLEEPFNGLUNMAPBUFFERARBPROC) glUnmapBuffer;
  108. }
  109. // Same deal for compressed textures.
  110. if (GLEE_VERSION_1_3 && !GLEE_ARB_texture_compression)
  111. {
  112. glCompressedTexImage2DARB = (GLEEPFNGLCOMPRESSEDTEXIMAGE2DARBPROC) glCompressedTexImage2D;
  113. glCompressedTexSubImage2DARB = (GLEEPFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) glCompressedTexSubImage2D;
  114. glGetCompressedTexImageARB = (GLEEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC) glGetCompressedTexImage;
  115. }
  116. }
  117. void OpenGL::createDefaultTexture()
  118. {
  119. // Set the 'default' texture (id 0) as a repeating white pixel. Otherwise,
  120. // texture2D calls inside a shader would return black when drawing graphics
  121. // primitives, which would create the need to use different "passthrough"
  122. // shaders for untextured primitives vs images.
  123. GLuint curtexture = state.textureUnits[state.curTextureUnit];
  124. bindTexture(0);
  125. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  126. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  127. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  128. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  129. GLubyte pix = 255;
  130. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE8, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pix);
  131. bindTexture(curtexture);
  132. }
  133. void OpenGL::setColor(const Color &c)
  134. {
  135. glColor4ubv(&c.r);
  136. state.color = c;
  137. }
  138. Color OpenGL::getColor()
  139. {
  140. return state.color;
  141. }
  142. void OpenGL::setActiveTextureUnit(int textureunit)
  143. {
  144. if (textureunit < 0 || (size_t) textureunit >= state.textureUnits.size())
  145. throw love::Exception("Invalid texture unit index (%d).", textureunit);
  146. if (textureunit != state.curTextureUnit)
  147. {
  148. if (state.textureUnits.size() > 1)
  149. glActiveTexture(GL_TEXTURE0 + textureunit);
  150. else
  151. throw love::Exception("Multitexturing not supported.");
  152. }
  153. state.curTextureUnit = textureunit;
  154. }
  155. void OpenGL::bindTexture(GLuint texture)
  156. {
  157. if (texture != state.textureUnits[state.curTextureUnit])
  158. {
  159. state.textureUnits[state.curTextureUnit] = texture;
  160. glBindTexture(GL_TEXTURE_2D, texture);
  161. }
  162. }
  163. void OpenGL::bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev)
  164. {
  165. if (textureunit < 0 || (size_t) textureunit >= state.textureUnits.size())
  166. throw love::Exception("Invalid texture unit index.");
  167. if (texture != state.textureUnits[textureunit])
  168. {
  169. int oldtextureunit = state.curTextureUnit;
  170. setActiveTextureUnit(textureunit);
  171. state.textureUnits[textureunit] = texture;
  172. glBindTexture(GL_TEXTURE_2D, texture);
  173. if (restoreprev)
  174. setActiveTextureUnit(oldtextureunit);
  175. }
  176. }
  177. void OpenGL::deleteTexture(GLuint texture)
  178. {
  179. // glDeleteTextures binds texture 0 to all texture units the deleted texture
  180. // was bound to before deletion.
  181. std::vector<GLuint>::iterator it;
  182. for (it = state.textureUnits.begin(); it != state.textureUnits.end(); ++it)
  183. {
  184. if (*it == texture)
  185. *it = 0;
  186. }
  187. glDeleteTextures(1, &texture);
  188. }
  189. float OpenGL::setTextureFilter(const graphics::Image::Filter &f)
  190. {
  191. GLint gmin, gmag;
  192. if (f.mipmap == Image::FILTER_NONE)
  193. {
  194. if (f.min == Image::FILTER_NEAREST)
  195. gmin = GL_NEAREST;
  196. else // f.min == Image::FILTER_LINEAR
  197. gmin = GL_LINEAR;
  198. }
  199. else
  200. {
  201. if (f.min == Image::FILTER_NEAREST && f.mipmap == Image::FILTER_NEAREST)
  202. gmin = GL_NEAREST_MIPMAP_NEAREST;
  203. else if (f.min == Image::FILTER_NEAREST && f.mipmap == Image::FILTER_LINEAR)
  204. gmin = GL_NEAREST_MIPMAP_LINEAR;
  205. else if (f.min == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_NEAREST)
  206. gmin = GL_LINEAR_MIPMAP_NEAREST;
  207. else if (f.min == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_LINEAR)
  208. gmin = GL_LINEAR_MIPMAP_LINEAR;
  209. else
  210. gmin = GL_LINEAR;
  211. }
  212. switch (f.mag)
  213. {
  214. case Image::FILTER_NEAREST:
  215. gmag = GL_NEAREST;
  216. break;
  217. case Image::FILTER_LINEAR:
  218. default:
  219. gmag = GL_LINEAR;
  220. break;
  221. }
  222. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
  223. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
  224. float anisotropy = 1.0f;
  225. if (GLEE_EXT_texture_filter_anisotropic)
  226. {
  227. anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy);
  228. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
  229. }
  230. return anisotropy;
  231. }
  232. graphics::Image::Filter OpenGL::getTextureFilter()
  233. {
  234. GLint gmin, gmag;
  235. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin);
  236. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag);
  237. Image::Filter f;
  238. switch (gmin)
  239. {
  240. case GL_NEAREST:
  241. f.min = Image::FILTER_NEAREST;
  242. f.mipmap = Image::FILTER_NONE;
  243. break;
  244. case GL_NEAREST_MIPMAP_NEAREST:
  245. f.min = f.mipmap = Image::FILTER_NEAREST;
  246. break;
  247. case GL_NEAREST_MIPMAP_LINEAR:
  248. f.min = Image::FILTER_NEAREST;
  249. f.mipmap = Image::FILTER_LINEAR;
  250. break;
  251. case GL_LINEAR_MIPMAP_NEAREST:
  252. f.min = Image::FILTER_LINEAR;
  253. f.mipmap = Image::FILTER_NEAREST;
  254. break;
  255. case GL_LINEAR_MIPMAP_LINEAR:
  256. f.min = f.mipmap = Image::FILTER_LINEAR;
  257. break;
  258. case GL_LINEAR:
  259. default:
  260. f.min = Image::FILTER_LINEAR;
  261. f.mipmap = Image::FILTER_NONE;
  262. break;
  263. }
  264. switch (gmag)
  265. {
  266. case GL_NEAREST:
  267. f.mag = Image::FILTER_NEAREST;
  268. break;
  269. case GL_LINEAR:
  270. default:
  271. f.mag = Image::FILTER_LINEAR;
  272. break;
  273. }
  274. if (GLEE_EXT_texture_filter_anisotropic)
  275. glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &f.anisotropy);
  276. return f;
  277. }
  278. void OpenGL::setTextureWrap(const graphics::Image::Wrap &w)
  279. {
  280. GLint gs, gt;
  281. switch (w.s)
  282. {
  283. case Image::WRAP_CLAMP:
  284. gs = GL_CLAMP_TO_EDGE;
  285. break;
  286. case Image::WRAP_REPEAT:
  287. default:
  288. gs = GL_REPEAT;
  289. break;
  290. }
  291. switch (w.t)
  292. {
  293. case Image::WRAP_CLAMP:
  294. gt = GL_CLAMP_TO_EDGE;
  295. break;
  296. case Image::WRAP_REPEAT:
  297. default:
  298. gt = GL_REPEAT;
  299. break;
  300. }
  301. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs);
  302. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt);
  303. }
  304. graphics::Image::Wrap OpenGL::getTextureWrap()
  305. {
  306. GLint gs, gt;
  307. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs);
  308. glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &gt);
  309. Image::Wrap w;
  310. switch (gs)
  311. {
  312. case GL_CLAMP_TO_EDGE:
  313. w.s = Image::WRAP_CLAMP;
  314. break;
  315. case GL_REPEAT:
  316. default:
  317. w.s = Image::WRAP_REPEAT;
  318. break;
  319. }
  320. switch (gt)
  321. {
  322. case GL_CLAMP_TO_EDGE:
  323. w.t = Image::WRAP_CLAMP;
  324. break;
  325. case GL_REPEAT:
  326. default:
  327. w.t = Image::WRAP_REPEAT;
  328. break;
  329. }
  330. return w;
  331. }
  332. // OpenGL class instance singleton.
  333. OpenGL gl;
  334. } // opengl
  335. } // graphics
  336. } // love