Image.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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. #include "Image.h"
  21. #include "common/int.h"
  22. // STD
  23. #include <cstring> // For memcpy
  24. #include <algorithm> // for min/max
  25. namespace love
  26. {
  27. namespace graphics
  28. {
  29. namespace opengl
  30. {
  31. int Image::imageCount = 0;
  32. float Image::maxMipmapSharpness = 0.0f;
  33. Texture::FilterMode Image::defaultMipmapFilter = Texture::FILTER_NEAREST;
  34. float Image::defaultMipmapSharpness = 0.0f;
  35. Image::Image(love::image::ImageData *data, const Flags &flags)
  36. : data(data)
  37. , cdata(nullptr)
  38. , texture(0)
  39. , mipmapSharpness(defaultMipmapSharpness)
  40. , compressed(false)
  41. , flags(flags)
  42. , usingDefaultTexture(false)
  43. , textureMemorySize(0)
  44. {
  45. width = data->getWidth();
  46. height = data->getHeight();
  47. preload();
  48. ++imageCount;
  49. }
  50. Image::Image(love::image::CompressedData *cdata, const Flags &flags)
  51. : data(nullptr)
  52. , cdata(cdata)
  53. , texture(0)
  54. , mipmapSharpness(defaultMipmapSharpness)
  55. , compressed(true)
  56. , flags(flags)
  57. , usingDefaultTexture(false)
  58. , textureMemorySize(0)
  59. {
  60. this->flags.sRGB = (flags.sRGB || cdata->isSRGB());
  61. width = cdata->getWidth(0);
  62. height = cdata->getHeight(0);
  63. if (flags.mipmaps)
  64. {
  65. // The mipmap texture data comes from the CompressedData in this case,
  66. // so we should make sure it has all necessary mipmap levels.
  67. if (cdata->getMipmapCount() < (int) log2(std::max(width, height)) + 1)
  68. throw love::Exception("Image cannot have mipmaps: compressed image data does not have all required mipmap levels.");
  69. }
  70. preload();
  71. ++imageCount;
  72. }
  73. Image::~Image()
  74. {
  75. unload();
  76. --imageCount;
  77. }
  78. love::image::ImageData *Image::getImageData() const
  79. {
  80. return data.get();
  81. }
  82. love::image::CompressedData *Image::getCompressedData() const
  83. {
  84. return cdata.get();
  85. }
  86. void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  87. {
  88. Matrix t;
  89. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  90. drawv(t, vertices);
  91. }
  92. void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  93. {
  94. Matrix t;
  95. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  96. drawv(t, quad->getVertices());
  97. }
  98. void Image::predraw()
  99. {
  100. bind();
  101. }
  102. void Image::postdraw()
  103. {
  104. }
  105. GLuint Image::getGLTexture() const
  106. {
  107. return texture;
  108. }
  109. void Image::setFilter(const Texture::Filter &f)
  110. {
  111. if (!validateFilter(f, flags.mipmaps))
  112. {
  113. if (f.mipmap != FILTER_NONE && !flags.mipmaps)
  114. throw love::Exception("Non-mipmapped image cannot have mipmap filtering.");
  115. else
  116. throw love::Exception("Invalid texture filter.");
  117. }
  118. filter = f;
  119. // We don't want filtering or (attempted) mipmaps on the default texture.
  120. if (usingDefaultTexture)
  121. {
  122. filter.mipmap = FILTER_NONE;
  123. filter.min = filter.mag = FILTER_NEAREST;
  124. }
  125. bind();
  126. gl.setTextureFilter(filter);
  127. }
  128. bool Image::setWrap(const Texture::Wrap &w)
  129. {
  130. bool success = true;
  131. wrap = w;
  132. if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
  133. {
  134. if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP)
  135. success = false;
  136. // If we only have limited NPOT support then the wrap mode must be CLAMP.
  137. wrap.s = wrap.t = WRAP_CLAMP;
  138. }
  139. bind();
  140. gl.setTextureWrap(w);
  141. return success;
  142. }
  143. void Image::setMipmapSharpness(float sharpness)
  144. {
  145. // OpenGL ES doesn't support LOD bias via glTexParameter.
  146. if (!GLAD_VERSION_1_4)
  147. return;
  148. // LOD bias has the range (-maxbias, maxbias)
  149. mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f);
  150. bind();
  151. // negative bias is sharper
  152. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness);
  153. }
  154. float Image::getMipmapSharpness() const
  155. {
  156. return mipmapSharpness;
  157. }
  158. void Image::bind() const
  159. {
  160. if (texture != 0)
  161. gl.bindTexture(texture);
  162. }
  163. void Image::preload()
  164. {
  165. // For colors.
  166. memset(vertices, 255, sizeof(Vertex)*4);
  167. vertices[0].x = 0;
  168. vertices[0].y = 0;
  169. vertices[1].x = 0;
  170. vertices[1].y = (float) height;
  171. vertices[2].x = (float) width;
  172. vertices[2].y = (float) height;
  173. vertices[3].x = (float) width;
  174. vertices[3].y = 0;
  175. vertices[0].s = 0;
  176. vertices[0].t = 0;
  177. vertices[1].s = 0;
  178. vertices[1].t = 1;
  179. vertices[2].s = 1;
  180. vertices[2].t = 1;
  181. vertices[3].s = 1;
  182. vertices[3].t = 0;
  183. if (flags.mipmaps)
  184. filter.mipmap = defaultMipmapFilter;
  185. }
  186. bool Image::load()
  187. {
  188. return loadVolatile();
  189. }
  190. void Image::unload()
  191. {
  192. return unloadVolatile();
  193. }
  194. void Image::generateMipmaps()
  195. {
  196. // The GL_GENERATE_MIPMAP texparameter is set in loadVolatile if we don't
  197. // have support for glGenerateMipmap.
  198. if (flags.mipmaps && !isCompressed() &&
  199. (GLAD_ES_VERSION_2_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
  200. {
  201. // Driver bug: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
  202. #if defined(LOVE_WINDOWS) || defined(LOVE_LINUX)
  203. if (gl.getVendor() == OpenGL::VENDOR_ATI_AMD)
  204. glEnable(GL_TEXTURE_2D);
  205. #endif
  206. glGenerateMipmap(GL_TEXTURE_2D);
  207. }
  208. }
  209. void Image::loadTextureFromCompressedData()
  210. {
  211. GLenum iformat = getCompressedFormat(cdata->getFormat());
  212. int count = flags.mipmaps ? cdata->getMipmapCount() : 1;
  213. // We have to inform OpenGL if the image doesn't have all mipmap levels.
  214. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0)
  215. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1);
  216. for (int i = 0; i < count; i++)
  217. {
  218. glCompressedTexImage2D(GL_TEXTURE_2D, i, iformat,
  219. cdata->getWidth(i), cdata->getHeight(i), 0,
  220. (GLsizei) cdata->getSize(i), cdata->getData(i));
  221. }
  222. }
  223. void Image::loadTextureFromImageData()
  224. {
  225. GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
  226. GLenum format = GL_RGBA;
  227. // in GLES2, the internalformat and format params of TexImage have to match.
  228. if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
  229. {
  230. format = flags.sRGB ? GL_SRGB_ALPHA : GL_RGBA;
  231. iformat = format;
  232. }
  233. {
  234. love::thread::Lock lock(data->getMutex());
  235. glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, format,
  236. GL_UNSIGNED_BYTE, data->getData());
  237. }
  238. generateMipmaps();
  239. }
  240. bool Image::loadVolatile()
  241. {
  242. if (isCompressed() && !hasCompressedTextureSupport(cdata->getFormat(), flags.sRGB))
  243. {
  244. const char *str;
  245. if (image::CompressedData::getConstant(cdata->getFormat(), str))
  246. {
  247. throw love::Exception("Cannot create image: "
  248. "%s%s compressed images are not supported on this system.", flags.sRGB ? "sRGB " : "", str);
  249. }
  250. else
  251. throw love::Exception("cannot create image: format is not supported on this system.");
  252. }
  253. else if (!isCompressed())
  254. {
  255. if (flags.sRGB && !hasSRGBSupport())
  256. throw love::Exception("sRGB images are not supported on this system.");
  257. // GL_EXT_sRGB doesn't support glGenerateMipmap for sRGB textures.
  258. if (flags.sRGB && (GLAD_ES_VERSION_2_0 && GLAD_EXT_sRGB && !GLAD_ES_VERSION_3_0))
  259. {
  260. flags.mipmaps = false;
  261. filter.mipmap = FILTER_NONE;
  262. }
  263. }
  264. // NPOT textures don't support mipmapping without full NPOT support.
  265. if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
  266. {
  267. flags.mipmaps = false;
  268. filter.mipmap = FILTER_NONE;
  269. }
  270. if (maxMipmapSharpness == 0.0f && GLAD_VERSION_1_4)
  271. glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
  272. glGenTextures(1, &texture);
  273. gl.bindTexture(texture);
  274. setFilter(filter);
  275. setWrap(wrap);
  276. setMipmapSharpness(mipmapSharpness);
  277. // Use a default texture if the size is too big for the system.
  278. if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize())
  279. {
  280. loadDefaultTexture();
  281. return true;
  282. }
  283. if (!flags.mipmaps && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0))
  284. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  285. if (flags.mipmaps && !isCompressed() &&
  286. !(GLAD_ES_VERSION_2_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
  287. {
  288. // Auto-generate mipmaps every time the texture is modified, if
  289. // glGenerateMipmap isn't supported.
  290. glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
  291. }
  292. while (glGetError() != GL_NO_ERROR); // Clear errors.
  293. try
  294. {
  295. if (isCompressed())
  296. loadTextureFromCompressedData();
  297. else
  298. loadTextureFromImageData();
  299. GLenum glerr = glGetError();
  300. if (glerr != GL_NO_ERROR)
  301. throw love::Exception("Cannot create image (error code 0x%x)", glerr);
  302. }
  303. catch (love::Exception &)
  304. {
  305. gl.deleteTexture(texture);
  306. texture = 0;
  307. throw;
  308. }
  309. size_t prevmemsize = textureMemorySize;
  310. if (isCompressed())
  311. {
  312. textureMemorySize = 0;
  313. for (int i = 0; i < (flags.mipmaps ? cdata->getMipmapCount() : 1); i++)
  314. textureMemorySize += cdata->getSize(i);
  315. }
  316. else
  317. {
  318. textureMemorySize = width * height * 4;
  319. if (flags.mipmaps)
  320. textureMemorySize *= 1.333;
  321. }
  322. gl.updateTextureMemorySize(prevmemsize, textureMemorySize);
  323. usingDefaultTexture = false;
  324. return true;
  325. }
  326. void Image::unloadVolatile()
  327. {
  328. // Delete the hardware texture.
  329. if (texture != 0)
  330. {
  331. gl.deleteTexture(texture);
  332. texture = 0;
  333. gl.updateTextureMemorySize(textureMemorySize, 0);
  334. textureMemorySize = 0;
  335. }
  336. }
  337. bool Image::refresh(int xoffset, int yoffset, int w, int h)
  338. {
  339. // No effect if the texture hasn't been created yet.
  340. if (texture == 0 || usingDefaultTexture)
  341. return false;
  342. if (xoffset < 0 || yoffset < 0 || w <= 0 || h <= 0 ||
  343. (xoffset + w) > width || (yoffset + h) > height)
  344. {
  345. throw love::Exception("Invalid rectangle dimensions.");
  346. }
  347. bind();
  348. if (isCompressed())
  349. loadTextureFromCompressedData();
  350. else
  351. {
  352. const image::pixel *pdata = (const image::pixel *) data->getData();
  353. pdata += yoffset * data->getWidth() + xoffset;
  354. {
  355. thread::Lock lock(data->getMutex());
  356. glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h, GL_RGBA,
  357. GL_UNSIGNED_BYTE, pdata);
  358. }
  359. generateMipmaps();
  360. }
  361. return true;
  362. }
  363. const Image::Flags &Image::getFlags() const
  364. {
  365. return flags;
  366. }
  367. void Image::loadDefaultTexture()
  368. {
  369. usingDefaultTexture = true;
  370. bind();
  371. setFilter(filter);
  372. // A nice friendly checkerboard to signify invalid textures...
  373. GLubyte px[] = {0xFF,0xFF,0xFF,0xFF, 0xC0,0xC0,0xC0,0xFF,
  374. 0xC0,0xC0,0xC0,0xFF, 0xFF,0xFF,0xFF,0xFF};
  375. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, px);
  376. }
  377. void Image::drawv(const Matrix &t, const Vertex *v)
  378. {
  379. OpenGL::TempTransform transform(gl);
  380. transform.get() *= t;
  381. predraw();
  382. glEnableVertexAttribArray(ATTRIB_POS);
  383. glEnableVertexAttribArray(ATTRIB_TEXCOORD);
  384. glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].x);
  385. glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].s);
  386. gl.prepareDraw();
  387. gl.drawArrays(GL_TRIANGLE_FAN, 0, 4);
  388. glDisableVertexAttribArray(ATTRIB_TEXCOORD);
  389. glDisableVertexAttribArray(ATTRIB_POS);
  390. postdraw();
  391. }
  392. void Image::setDefaultMipmapSharpness(float sharpness)
  393. {
  394. defaultMipmapSharpness = sharpness;
  395. }
  396. float Image::getDefaultMipmapSharpness()
  397. {
  398. return defaultMipmapSharpness;
  399. }
  400. void Image::setDefaultMipmapFilter(Texture::FilterMode f)
  401. {
  402. defaultMipmapFilter = f;
  403. }
  404. Texture::FilterMode Image::getDefaultMipmapFilter()
  405. {
  406. return defaultMipmapFilter;
  407. }
  408. bool Image::isCompressed() const
  409. {
  410. return compressed;
  411. }
  412. GLenum Image::getCompressedFormat(image::CompressedData::Format cformat) const
  413. {
  414. switch (cformat)
  415. {
  416. case image::CompressedData::FORMAT_DXT1:
  417. if (flags.sRGB)
  418. return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
  419. else
  420. return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  421. case image::CompressedData::FORMAT_DXT3:
  422. if (flags.sRGB)
  423. return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
  424. else
  425. return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
  426. case image::CompressedData::FORMAT_DXT5:
  427. if (flags.sRGB)
  428. return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
  429. else
  430. return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  431. case image::CompressedData::FORMAT_BC4:
  432. return GL_COMPRESSED_RED_RGTC1;
  433. case image::CompressedData::FORMAT_BC4s:
  434. return GL_COMPRESSED_SIGNED_RED_RGTC1;
  435. case image::CompressedData::FORMAT_BC5:
  436. return GL_COMPRESSED_RG_RGTC2;
  437. case image::CompressedData::FORMAT_BC5s:
  438. return GL_COMPRESSED_SIGNED_RG_RGTC2;
  439. case image::CompressedData::FORMAT_BC6H:
  440. return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
  441. case image::CompressedData::FORMAT_BC6Hs:
  442. return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
  443. case image::CompressedData::FORMAT_BC7:
  444. if (flags.sRGB)
  445. return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
  446. else
  447. return GL_COMPRESSED_RGBA_BPTC_UNORM;
  448. case image::CompressedData::FORMAT_ETC1:
  449. // The ETC2 format can load ETC1 textures.
  450. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility)
  451. return GL_COMPRESSED_RGB8_ETC2;
  452. else
  453. return GL_ETC1_RGB8_OES;
  454. case image::CompressedData::FORMAT_ETC2_RGB:
  455. if (flags.sRGB)
  456. return GL_COMPRESSED_SRGB8_ETC2;
  457. else
  458. return GL_COMPRESSED_RGB8_ETC2;
  459. case image::CompressedData::FORMAT_ETC2_RGBA:
  460. if (flags.sRGB)
  461. return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
  462. else
  463. return GL_COMPRESSED_RGBA8_ETC2_EAC;
  464. case image::CompressedData::FORMAT_ETC2_RGBA1:
  465. if (flags.sRGB)
  466. return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
  467. else
  468. return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
  469. case image::CompressedData::FORMAT_EAC_R:
  470. return GL_COMPRESSED_R11_EAC;
  471. case image::CompressedData::FORMAT_EAC_Rs:
  472. return GL_COMPRESSED_SIGNED_R11_EAC;
  473. case image::CompressedData::FORMAT_EAC_RG:
  474. return GL_COMPRESSED_RG11_EAC;
  475. case image::CompressedData::FORMAT_EAC_RGs:
  476. return GL_COMPRESSED_SIGNED_RG11_EAC;
  477. case image::CompressedData::FORMAT_PVR1_RGB2:
  478. if (flags.sRGB)
  479. return GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT;
  480. else
  481. return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
  482. case image::CompressedData::FORMAT_PVR1_RGB4:
  483. if (flags.sRGB)
  484. return GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT;
  485. else
  486. return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
  487. case image::CompressedData::FORMAT_PVR1_RGBA2:
  488. if (flags.sRGB)
  489. return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT;
  490. else
  491. return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
  492. case image::CompressedData::FORMAT_PVR1_RGBA4:
  493. if (flags.sRGB)
  494. return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT;
  495. else
  496. return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
  497. default:
  498. if (flags.sRGB)
  499. return GL_SRGB8_ALPHA8;
  500. else
  501. return GL_RGBA8;
  502. }
  503. }
  504. bool Image::hasAnisotropicFilteringSupport()
  505. {
  506. return GLAD_EXT_texture_filter_anisotropic;
  507. }
  508. bool Image::hasCompressedTextureSupport(image::CompressedData::Format format, bool sRGB)
  509. {
  510. switch (format)
  511. {
  512. case image::CompressedData::FORMAT_DXT1:
  513. return GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1;
  514. case image::CompressedData::FORMAT_DXT3:
  515. return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3;
  516. case image::CompressedData::FORMAT_DXT5:
  517. return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5;
  518. case image::CompressedData::FORMAT_BC4:
  519. case image::CompressedData::FORMAT_BC4s:
  520. case image::CompressedData::FORMAT_BC5:
  521. case image::CompressedData::FORMAT_BC5s:
  522. return (GLAD_VERSION_3_0 || GLAD_ARB_texture_compression_rgtc || GLAD_EXT_texture_compression_rgtc);
  523. case image::CompressedData::FORMAT_BC6H:
  524. case image::CompressedData::FORMAT_BC6Hs:
  525. case image::CompressedData::FORMAT_BC7:
  526. return GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc;
  527. case image::CompressedData::FORMAT_ETC1:
  528. // ETC2 support guarantees ETC1 support as well.
  529. return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture;
  530. case image::CompressedData::FORMAT_ETC2_RGB:
  531. case image::CompressedData::FORMAT_ETC2_RGBA:
  532. case image::CompressedData::FORMAT_ETC2_RGBA1:
  533. case image::CompressedData::FORMAT_EAC_R:
  534. case image::CompressedData::FORMAT_EAC_Rs:
  535. case image::CompressedData::FORMAT_EAC_RG:
  536. case image::CompressedData::FORMAT_EAC_RGs:
  537. return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility;
  538. case image::CompressedData::FORMAT_PVR1_RGB2:
  539. case image::CompressedData::FORMAT_PVR1_RGB4:
  540. case image::CompressedData::FORMAT_PVR1_RGBA2:
  541. case image::CompressedData::FORMAT_PVR1_RGBA4:
  542. if (sRGB)
  543. return GLAD_EXT_pvrtc_sRGB;
  544. else
  545. return GLAD_IMG_texture_compression_pvrtc;
  546. default:
  547. return false;
  548. }
  549. }
  550. bool Image::hasSRGBSupport()
  551. {
  552. return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
  553. }
  554. bool Image::getConstant(const char *in, FlagType &out)
  555. {
  556. return flagNames.find(in, out);
  557. }
  558. bool Image::getConstant(FlagType in, const char *&out)
  559. {
  560. return flagNames.find(in, out);
  561. }
  562. StringMap<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM>::Entry Image::flagNameEntries[] =
  563. {
  564. {"mipmaps", Image::FLAG_TYPE_MIPMAPS},
  565. {"srgb", Image::FLAG_TYPE_SRGB},
  566. };
  567. StringMap<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM> Image::flagNames(Image::flagNameEntries, sizeof(Image::flagNameEntries));
  568. } // opengl
  569. } // graphics
  570. } // love