Canvas.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. const Graphics::Capabilities &caps = gfx->getCapabilities();
  62. if (!gfx->isCanvasFormatSupported(format, readable))
  63. {
  64. const char *fstr = "rgba8";
  65. const char *readablestr = "";
  66. if (readable != !isPixelFormatDepthStencil(format))
  67. readablestr = readable ? " readable" : " non-readable";
  68. love::getConstant(format, fstr);
  69. throw love::Exception("The %s%s canvas format is not supported by your graphics drivers.", fstr, readablestr);
  70. }
  71. if (getRequestedMSAA() > 1 && texType != TEXTURE_2D)
  72. throw love::Exception("MSAA is only supported for 2D texture types.");
  73. if (!readable && texType != TEXTURE_2D)
  74. throw love::Exception("Non-readable pixel formats are only supported for 2D texture types.");
  75. if (!caps.textureTypes[texType])
  76. {
  77. const char *textypestr = "unknown";
  78. Texture::getConstant(texType, textypestr);
  79. throw love::Exception("%s textures are not supported on this system!", textypestr);
  80. }
  81. validateDimensions(true);
  82. canvasCount++;
  83. }
  84. Canvas::~Canvas()
  85. {
  86. canvasCount--;
  87. }
  88. Canvas::MipmapMode Canvas::getMipmapMode() const
  89. {
  90. return settings.mipmaps;
  91. }
  92. int Canvas::getRequestedMSAA() const
  93. {
  94. return settings.msaa;
  95. }
  96. love::image::ImageData *Canvas::newImageData(love::image::Image *module, int slice, int mipmap, const Rect &r)
  97. {
  98. if (!isReadable())
  99. throw love::Exception("Canvas:newImageData cannot be called on non-readable Canvases.");
  100. if (isPixelFormatDepthStencil(getPixelFormat()))
  101. throw love::Exception("Canvas:newImageData cannot be called on Canvases with depth/stencil pixel formats.");
  102. 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))
  103. throw love::Exception("Invalid rectangle dimensions.");
  104. if (slice < 0 || (texType == TEXTURE_VOLUME && slice >= getDepth(mipmap))
  105. || (texType == TEXTURE_2D_ARRAY && slice >= layers)
  106. || (texType == TEXTURE_CUBE && slice >= 6))
  107. {
  108. throw love::Exception("Invalid slice index.");
  109. }
  110. Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
  111. if (gfx != nullptr && gfx->isCanvasActive(this))
  112. throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active.");
  113. PixelFormat dataformat;
  114. switch (getPixelFormat())
  115. {
  116. case PIXELFORMAT_RGB10A2: // FIXME: Conversions aren't supported in GLES
  117. dataformat = PIXELFORMAT_RGBA16;
  118. break;
  119. case PIXELFORMAT_R16F:
  120. case PIXELFORMAT_RG16F:
  121. case PIXELFORMAT_RGBA16F:
  122. case PIXELFORMAT_RG11B10F: // FIXME: Conversions aren't supported in GLES
  123. dataformat = PIXELFORMAT_RGBA16F;
  124. break;
  125. case PIXELFORMAT_R32F:
  126. case PIXELFORMAT_RG32F:
  127. case PIXELFORMAT_RGBA32F:
  128. dataformat = PIXELFORMAT_RGBA32F;
  129. break;
  130. default:
  131. dataformat = PIXELFORMAT_RGBA8;
  132. break;
  133. }
  134. return module->newImageData(r.w, r.h, dataformat);
  135. }
  136. void Canvas::draw(Graphics *gfx, Quad *q, const Matrix4 &t)
  137. {
  138. if (gfx->isCanvasActive(this))
  139. throw love::Exception("Cannot render a Canvas to itself!");
  140. Texture::draw(gfx, q, t);
  141. }
  142. void Canvas::drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m)
  143. {
  144. if (gfx->isCanvasActive(this, layer))
  145. throw love::Exception("Cannot render a Canvas to itself!");
  146. Texture::drawLayer(gfx, layer, quad, m);
  147. }
  148. bool Canvas::getConstant(const char *in, MipmapMode &out)
  149. {
  150. return mipmapModes.find(in, out);
  151. }
  152. bool Canvas::getConstant(MipmapMode in, const char *&out)
  153. {
  154. return mipmapModes.find(in, out);
  155. }
  156. StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM>::Entry Canvas::mipmapEntries[] =
  157. {
  158. { "none", MIPMAPS_NONE },
  159. { "manual", MIPMAPS_MANUAL },
  160. { "auto", MIPMAPS_AUTO },
  161. };
  162. StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM> Canvas::mipmapModes(Canvas::mipmapEntries, sizeof(Canvas::mipmapEntries));
  163. } // graphics
  164. } // love