Canvas.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /**
  2. * Copyright (c) 2006-2017 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 "Canvas.h"
  21. #include "Graphics.h"
  22. namespace love
  23. {
  24. namespace graphics
  25. {
  26. love::Type Canvas::type("Canvas", &Texture::type);
  27. int Canvas::canvasCount = 0;
  28. Canvas::Canvas(const Settings &settings)
  29. : Texture(settings.type)
  30. {
  31. this->settings = settings;
  32. width = settings.width;
  33. height = settings.height;
  34. pixelWidth = (int) ((width * settings.pixeldensity) + 0.5);
  35. pixelHeight = (int) ((height * settings.pixeldensity) + 0.5);
  36. format = settings.format;
  37. if (texType == TEXTURE_VOLUME)
  38. depth = settings.layers;
  39. else if (texType == TEXTURE_2D_ARRAY)
  40. layers = settings.layers;
  41. else
  42. layers = 1;
  43. if (width <= 0 || height <= 0 || layers <= 0)
  44. throw love::Exception("Canvas dimensions must be greater than 0.");
  45. if (texType != TEXTURE_2D && settings.msaa > 1)
  46. throw love::Exception("MSAA is only supported for Canvases with the 2D texture type.");
  47. if (settings.readable.hasValue)
  48. readable = settings.readable.value;
  49. else
  50. readable = !isPixelFormatDepthStencil(format);
  51. if (readable && isPixelFormatDepthStencil(format) && settings.msaa > 1)
  52. throw love::Exception("Readable depth/stencil Canvases with MSAA are not currently supported.");
  53. if ((!readable || settings.msaa > 1) && settings.mipmaps != MIPMAPS_NONE)
  54. throw love::Exception("Non-readable and MSAA textures cannot have mipmaps.");
  55. if (settings.mipmaps != MIPMAPS_NONE)
  56. {
  57. mipmapCount = getMipmapCount(pixelWidth, pixelHeight);
  58. filter.mipmap = defaultMipmapFilter;
  59. }
  60. auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
  61. if (!gfx->isCanvasFormatSupported(format, readable))
  62. {
  63. const char *fstr = "rgba8";
  64. const char *readablestr = "";
  65. if (readable != !isPixelFormatDepthStencil(format))
  66. readablestr = readable ? " readable" : " non-readable";
  67. love::getConstant(format, fstr);
  68. throw love::Exception("The %s%s canvas format is not supported by your graphics drivers.", fstr, readablestr);
  69. }
  70. if (getRequestedMSAA() > 1 && texType != TEXTURE_2D)
  71. throw love::Exception("MSAA is only supported for 2D texture types.");
  72. if (!readable && texType != TEXTURE_2D)
  73. throw love::Exception("Non-readable pixel formats are only supported for 2D texture types.");
  74. if (!gfx->isTextureTypeSupported(texType))
  75. {
  76. const char *textypestr = "unknown";
  77. Texture::getConstant(texType, textypestr);
  78. throw love::Exception("%s textures are not supported on this system!", textypestr);
  79. }
  80. int maxsize = 0;
  81. switch (texType)
  82. {
  83. case TEXTURE_2D:
  84. maxsize = gfx->getSystemLimit(Graphics::LIMIT_TEXTURE_SIZE);
  85. if (pixelWidth > maxsize)
  86. throw TextureTooLargeException("width", pixelWidth);
  87. else if (pixelHeight > maxsize)
  88. throw TextureTooLargeException("height", pixelHeight);
  89. break;
  90. case TEXTURE_VOLUME:
  91. maxsize = gfx->getSystemLimit(Graphics::LIMIT_VOLUME_TEXTURE_SIZE);
  92. if (pixelWidth > maxsize)
  93. throw TextureTooLargeException("width", pixelWidth);
  94. else if (pixelHeight > maxsize)
  95. throw TextureTooLargeException("height", pixelHeight);
  96. else if (depth > maxsize)
  97. throw TextureTooLargeException("depth", depth);
  98. break;
  99. case TEXTURE_2D_ARRAY:
  100. maxsize = gfx->getSystemLimit(Graphics::LIMIT_TEXTURE_SIZE);
  101. if (pixelWidth > maxsize)
  102. throw TextureTooLargeException("width", pixelWidth);
  103. else if (pixelHeight > maxsize)
  104. throw TextureTooLargeException("height", pixelHeight);
  105. else if (layers > gfx->getSystemLimit(Graphics::LIMIT_TEXTURE_LAYERS))
  106. throw TextureTooLargeException("array layer count", layers);
  107. break;
  108. case TEXTURE_CUBE:
  109. if (pixelWidth != pixelHeight)
  110. throw love::Exception("Cubemap textures must have equal width and height.");
  111. else if (pixelWidth > gfx->getSystemLimit(Graphics::LIMIT_CUBE_TEXTURE_SIZE))
  112. throw TextureTooLargeException("width", pixelWidth);
  113. break;
  114. default:
  115. break;
  116. }
  117. canvasCount++;
  118. }
  119. Canvas::~Canvas()
  120. {
  121. canvasCount--;
  122. }
  123. Canvas::MipmapMode Canvas::getMipmapMode() const
  124. {
  125. return settings.mipmaps;
  126. }
  127. int Canvas::getRequestedMSAA() const
  128. {
  129. return settings.msaa;
  130. }
  131. love::image::ImageData *Canvas::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r)
  132. {
  133. if (!isReadable())
  134. throw love::Exception("Canvas:newImageData cannot be called on non-readable Canvases.");
  135. if (isPixelFormatDepthStencil(getPixelFormat()))
  136. throw love::Exception("Canvas:newImageData cannot be called on Canvases with depth/stencil pixel formats.");
  137. if (r.x < 0 || r.y < 0 || r.w <= 0 || r.h <= 0 || (r.x + r.w) > getPixelWidth(mipmap) || (r.y + r.h) > getPixelHeight(mipmap))
  138. throw love::Exception("Invalid rectangle dimensions.");
  139. if (slice < 0 || (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap))
  140. || (texType == TEXTURE_2D_ARRAY && slice >= layers)
  141. || (texType == TEXTURE_CUBE && slice >= 6))
  142. {
  143. throw love::Exception("Invalid slice index.");
  144. }
  145. Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
  146. if (gfx != nullptr && gfx->isCanvasActive(this))
  147. throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active.");
  148. PixelFormat dataformat;
  149. switch (getPixelFormat())
  150. {
  151. case PIXELFORMAT_RGB10A2: // FIXME: Conversions aren't supported in GLES
  152. dataformat = PIXELFORMAT_RGBA16;
  153. break;
  154. case PIXELFORMAT_R16F:
  155. case PIXELFORMAT_RG16F:
  156. case PIXELFORMAT_RGBA16F:
  157. case PIXELFORMAT_RG11B10F: // FIXME: Conversions aren't supported in GLES
  158. dataformat = PIXELFORMAT_RGBA16F;
  159. break;
  160. case PIXELFORMAT_R32F:
  161. case PIXELFORMAT_RG32F:
  162. case PIXELFORMAT_RGBA32F:
  163. dataformat = PIXELFORMAT_RGBA32F;
  164. break;
  165. default:
  166. dataformat = PIXELFORMAT_RGBA8;
  167. break;
  168. }
  169. return module->newImageData(r.w, r.h, dataformat);
  170. }
  171. void Canvas::draw(Graphics *gfx, Quad *q, const Matrix4 &t)
  172. {
  173. if (gfx->isCanvasActive(this))
  174. throw love::Exception("Cannot render a Canvas to itself!");
  175. Texture::draw(gfx, q, t);
  176. }
  177. void Canvas::drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m)
  178. {
  179. if (gfx->isCanvasActive(this, layer))
  180. throw love::Exception("Cannot render a Canvas to itself!");
  181. Texture::drawLayer(gfx, layer, quad, m);
  182. }
  183. bool Canvas::getConstant(const char *in, MipmapMode &out)
  184. {
  185. return mipmapModes.find(in, out);
  186. }
  187. bool Canvas::getConstant(MipmapMode in, const char *&out)
  188. {
  189. return mipmapModes.find(in, out);
  190. }
  191. StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM>::Entry Canvas::mipmapEntries[] =
  192. {
  193. { "none", MIPMAPS_NONE },
  194. { "manual", MIPMAPS_MANUAL },
  195. { "auto", MIPMAPS_AUTO },
  196. };
  197. StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM> Canvas::mipmapModes(Canvas::mipmapEntries, sizeof(Canvas::mipmapEntries));
  198. } // graphics
  199. } // love