2
0

Image.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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 "Image.h"
  21. // STD
  22. #include <cstring> // For memcpy
  23. #include <algorithm> // for min/max
  24. #include <iostream>
  25. namespace love
  26. {
  27. namespace graphics
  28. {
  29. namespace opengl
  30. {
  31. float Image::maxMipmapSharpness = 0.0f;
  32. float Image::maxMipmapAnisotropy = 0.0f;
  33. Image::FilterMode Image::defaultMipmapFilter = Image::FILTER_NONE;
  34. float Image::defaultMipmapSharpness = 0.0f;
  35. float Image::defaultMipmapAnisotropy = 0.0f;
  36. Image::Image(love::image::ImageData *data)
  37. : width((float)(data->getWidth()))
  38. , height((float)(data->getHeight()))
  39. , texture(0)
  40. , mipmapSharpness(defaultMipmapSharpness)
  41. , mipmapAnisotropy(defaultMipmapAnisotropy)
  42. , mipmapsCreated(false)
  43. {
  44. data->retain();
  45. this->data = data;
  46. memset(vertices, 255, sizeof(vertex)*4);
  47. vertices[0].x = 0;
  48. vertices[0].y = 0;
  49. vertices[1].x = 0;
  50. vertices[1].y = height;
  51. vertices[2].x = width;
  52. vertices[2].y = height;
  53. vertices[3].x = width;
  54. vertices[3].y = 0;
  55. vertices[0].s = 0;
  56. vertices[0].t = 0;
  57. vertices[1].s = 0;
  58. vertices[1].t = 1;
  59. vertices[2].s = 1;
  60. vertices[2].t = 1;
  61. vertices[3].s = 1;
  62. vertices[3].t = 0;
  63. filter = getDefaultFilter();
  64. filter.mipmap = defaultMipmapFilter;
  65. }
  66. Image::~Image()
  67. {
  68. if (data != 0)
  69. data->release();
  70. unload();
  71. }
  72. float Image::getWidth() const
  73. {
  74. return width;
  75. }
  76. float Image::getHeight() const
  77. {
  78. return height;
  79. }
  80. const vertex *Image::getVertices() const
  81. {
  82. return vertices;
  83. }
  84. love::image::ImageData *Image::getData() const
  85. {
  86. return data;
  87. }
  88. void Image::getRectangleVertices(int x, int y, int w, int h, vertex *vertices) const
  89. {
  90. // Check upper.
  91. x = (x+w > (int)width) ? (int)width-w : x;
  92. y = (y+h > (int)height) ? (int)height-h : y;
  93. // Check lower.
  94. x = (x < 0) ? 0 : x;
  95. y = (y < 0) ? 0 : y;
  96. vertices[0].x = 0;
  97. vertices[0].y = 0;
  98. vertices[1].x = 0;
  99. vertices[1].y = (float)h;
  100. vertices[2].x = (float)w;
  101. vertices[2].y = (float)h;
  102. vertices[3].x = (float)w;
  103. vertices[3].y = 0;
  104. float tx = (float)x/width;
  105. float ty = (float)y/height;
  106. float tw = (float)w/width;
  107. float th = (float)h/height;
  108. vertices[0].s = tx;
  109. vertices[0].t = ty;
  110. vertices[1].s = tx;
  111. vertices[1].t = ty+th;
  112. vertices[2].s = tx+tw;
  113. vertices[2].t = ty+th;
  114. vertices[3].s = tx+tw;
  115. vertices[3].t = ty;
  116. }
  117. void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
  118. {
  119. static Matrix t;
  120. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  121. drawv(t, vertices);
  122. }
  123. void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
  124. {
  125. static Matrix t;
  126. const vertex *v = quad->getVertices();
  127. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  128. drawv(t, v);
  129. }
  130. void Image::checkMipmapsCreated()
  131. {
  132. if (mipmapsCreated || (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR))
  133. return;
  134. if (!hasMipmapSupport())
  135. throw love::Exception("Mipmap filtering is not supported on this system.");
  136. // Some old drivers claim support for NPOT textures, but fail when creating mipmaps.
  137. // we can't detect which systems will do this, so we fail gracefully for all NPOT images.
  138. int w = int(width), h = int(height);
  139. if (w != next_p2(w) || h != next_p2(h))
  140. throw love::Exception("Cannot create mipmaps: image does not have power of two dimensions.");
  141. bind();
  142. if (hasNpot() && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object))
  143. {
  144. // AMD/ATI drivers have several bugs when generating mipmaps,
  145. // re-uploading the entire base image seems to be required.
  146. glTexImage2D(GL_TEXTURE_2D,
  147. 0,
  148. GL_RGBA8,
  149. (GLsizei)width,
  150. (GLsizei)height,
  151. 0,
  152. GL_RGBA,
  153. GL_UNSIGNED_BYTE,
  154. data->getData());
  155. // More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
  156. glEnable(GL_TEXTURE_2D);
  157. glGenerateMipmap(GL_TEXTURE_2D);
  158. }
  159. else
  160. {
  161. glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
  162. glTexSubImage2D(GL_TEXTURE_2D,
  163. 0,
  164. 0,
  165. 0,
  166. (GLsizei)width,
  167. (GLsizei)height,
  168. GL_RGBA,
  169. GL_UNSIGNED_BYTE,
  170. data->getData());
  171. }
  172. mipmapsCreated = true;
  173. }
  174. void Image::setFilter(const Image::Filter &f)
  175. {
  176. filter = f;
  177. bind();
  178. setTextureFilter(f);
  179. checkMipmapsCreated();
  180. }
  181. const Image::Filter &Image::getFilter() const
  182. {
  183. return filter;
  184. }
  185. void Image::setWrap(const Image::Wrap &w)
  186. {
  187. wrap = w;
  188. bind();
  189. setTextureWrap(w);
  190. }
  191. const Image::Wrap &Image::getWrap() const
  192. {
  193. return wrap;
  194. }
  195. void Image::setMipmapSharpness(float sharpness, float anisotropy)
  196. {
  197. if (hasMipmapSharpnessSupport())
  198. {
  199. // LOD bias has the range (-maxbias, maxbias)
  200. mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f);
  201. bind();
  202. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper
  203. }
  204. else
  205. mipmapSharpness = 0.0f;
  206. if (hasMipmapAnisotropySupport())
  207. {
  208. mipmapAnisotropy = std::min(std::max(anisotropy, 0.0f), maxMipmapAnisotropy);
  209. bind();
  210. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, mipmapAnisotropy);
  211. }
  212. else
  213. mipmapAnisotropy = 0.0f;
  214. }
  215. void Image::getMipmapSharpness(float *sharpness, float *anisotropy) const
  216. {
  217. *sharpness = mipmapSharpness;
  218. *anisotropy = mipmapAnisotropy;
  219. }
  220. void Image::bind() const
  221. {
  222. if (texture == 0)
  223. return;
  224. bindTexture(texture);
  225. }
  226. bool Image::load()
  227. {
  228. return loadVolatile();
  229. }
  230. void Image::unload()
  231. {
  232. return unloadVolatile();
  233. }
  234. bool Image::loadVolatile()
  235. {
  236. if (hasMipmapSharpnessSupport() && maxMipmapSharpness == 0.0f)
  237. glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
  238. if (hasMipmapAnisotropySupport() && maxMipmapAnisotropy == 0.0f)
  239. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxMipmapAnisotropy);
  240. if (hasNpot())
  241. return loadVolatileNPOT();
  242. else
  243. return loadVolatilePOT();
  244. }
  245. bool Image::loadVolatilePOT()
  246. {
  247. glGenTextures(1,(GLuint *)&texture);
  248. bindTexture(texture);
  249. setTextureFilter(filter);
  250. setTextureWrap(wrap);
  251. float p2width = next_p2(width);
  252. float p2height = next_p2(height);
  253. float s = width/p2width;
  254. float t = height/p2height;
  255. vertices[1].t = t;
  256. vertices[2].t = t;
  257. vertices[2].s = s;
  258. vertices[3].s = s;
  259. while (glGetError() != GL_NO_ERROR); // clear errors
  260. glTexImage2D(GL_TEXTURE_2D,
  261. 0,
  262. GL_RGBA8,
  263. (GLsizei)p2width,
  264. (GLsizei)p2height,
  265. 0,
  266. GL_RGBA,
  267. GL_UNSIGNED_BYTE,
  268. 0);
  269. glTexSubImage2D(GL_TEXTURE_2D,
  270. 0,
  271. 0,
  272. 0,
  273. (GLsizei)width,
  274. (GLsizei)height,
  275. GL_RGBA,
  276. GL_UNSIGNED_BYTE,
  277. data->getData());
  278. if (glGetError() != GL_NO_ERROR)
  279. throw love::Exception("Cannot create image: size may be too large for this system.");
  280. mipmapsCreated = false;
  281. checkMipmapsCreated();
  282. setMipmapSharpness(mipmapSharpness, mipmapAnisotropy);
  283. return true;
  284. }
  285. bool Image::loadVolatileNPOT()
  286. {
  287. glGenTextures(1,(GLuint *)&texture);
  288. bindTexture(texture);
  289. setTextureFilter(filter);
  290. setTextureWrap(wrap);
  291. while (glGetError() != GL_NO_ERROR); // clear errors
  292. glTexImage2D(GL_TEXTURE_2D,
  293. 0,
  294. GL_RGBA8,
  295. (GLsizei)width,
  296. (GLsizei)height,
  297. 0,
  298. GL_RGBA,
  299. GL_UNSIGNED_BYTE,
  300. data->getData());
  301. if (glGetError() != GL_NO_ERROR)
  302. throw love::Exception("Cannot create image: size may be too large for this system.");
  303. mipmapsCreated = false;
  304. checkMipmapsCreated();
  305. setMipmapSharpness(mipmapSharpness, mipmapAnisotropy);
  306. return true;
  307. }
  308. void Image::unloadVolatile()
  309. {
  310. // Delete the hardware texture.
  311. if (texture != 0)
  312. {
  313. deleteTexture(texture);
  314. texture = 0;
  315. }
  316. }
  317. void Image::drawv(const Matrix &t, const vertex *v) const
  318. {
  319. bind();
  320. glPushMatrix();
  321. glMultMatrixf((const GLfloat *)t.getElements());
  322. glEnableClientState(GL_VERTEX_ARRAY);
  323. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  324. glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].x);
  325. glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].s);
  326. glDrawArrays(GL_QUADS, 0, 4);
  327. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  328. glDisableClientState(GL_VERTEX_ARRAY);
  329. glPopMatrix();
  330. }
  331. void Image::setDefaultMipmapSharpness(float sharpness, float anisotropy)
  332. {
  333. defaultMipmapSharpness = sharpness;
  334. defaultMipmapAnisotropy = anisotropy;
  335. }
  336. void Image::getDefaultMipmapSharpness(float *sharpness, float *anisotropy)
  337. {
  338. *sharpness = defaultMipmapSharpness;
  339. *anisotropy = defaultMipmapAnisotropy;
  340. }
  341. void Image::setDefaultMipmapFilter(Image::FilterMode f)
  342. {
  343. defaultMipmapFilter = f;
  344. }
  345. Image::FilterMode Image::getDefaultMipmapFilter()
  346. {
  347. return defaultMipmapFilter;
  348. }
  349. bool Image::hasNpot()
  350. {
  351. return GLEE_VERSION_2_0 || GLEE_ARB_texture_non_power_of_two;
  352. }
  353. bool Image::hasMipmapSupport()
  354. {
  355. return GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap;
  356. }
  357. bool Image::hasMipmapSharpnessSupport()
  358. {
  359. return GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias;
  360. }
  361. bool Image::hasMipmapAnisotropySupport()
  362. {
  363. return GLEE_EXT_texture_filter_anisotropic;
  364. }
  365. } // opengl
  366. } // graphics
  367. } // love