mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
Added antialiasing (MSAA) support to Canvases via a new optional parameter. Added Canvas:getFSAA.
This commit is contained in:
@@ -55,7 +55,7 @@ public:
|
||||
* @param kx Shear along the x-axis.
|
||||
* @param ky Shear along the y-axis.
|
||||
**/
|
||||
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0;
|
||||
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) = 0;
|
||||
};
|
||||
|
||||
} // graphics
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
* @param kx Shear along the x-axis.
|
||||
* @param ky Shear along the y-axis.
|
||||
**/
|
||||
virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0;
|
||||
virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) = 0;
|
||||
|
||||
virtual int getWidth() const;
|
||||
virtual int getHeight() const;
|
||||
|
||||
@@ -63,12 +63,26 @@ struct FramebufferStrategy
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Create a MSAA renderbuffer and attach it to the active FBO.
|
||||
/**
|
||||
* @param[in] width Width of the MSAA buffer
|
||||
* @param[in] height Height of the MSAA buffer
|
||||
* @param[inout] samples Number of samples to use
|
||||
* @param[in] internalformat The internal format to use for the buffer
|
||||
* @param[out] buffer Name for the MSAA buffer
|
||||
* @return Whether the MSAA buffer was successfully created and attached
|
||||
**/
|
||||
virtual bool createMSAABuffer(int, int, int &, GLenum, GLuint &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// remove objects
|
||||
/**
|
||||
* @param[in] framebuffer Framebuffer name
|
||||
* @param[in] depth_stencil Name for packed depth and stencil buffer
|
||||
*/
|
||||
virtual void deleteFBO(GLuint, GLuint) {}
|
||||
virtual void deleteFBO(GLuint, GLuint, GLuint) {}
|
||||
virtual void bindFBO(GLuint) {}
|
||||
|
||||
/// attach additional canvases to the active framebuffer for rendering
|
||||
@@ -93,8 +107,11 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, texture, 0);
|
||||
if (texture != 0)
|
||||
{
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, texture, 0);
|
||||
}
|
||||
|
||||
// check status
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
@@ -118,13 +135,44 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
// check status
|
||||
return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &stencil);
|
||||
stencil = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil)
|
||||
virtual bool createMSAABuffer(int width, int height, int &samples, GLenum internalformat, GLuint &buffer)
|
||||
{
|
||||
glGenRenderbuffers(1, &buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, buffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat,
|
||||
width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, buffer);
|
||||
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &buffer);
|
||||
buffer = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint msaa_buffer)
|
||||
{
|
||||
if (depth_stencil != 0)
|
||||
glDeleteRenderbuffers(1, &depth_stencil);
|
||||
if (msaa_buffer != 0)
|
||||
glDeleteRenderbuffers(1, &msaa_buffer);
|
||||
if (framebuffer != 0)
|
||||
glDeleteFramebuffers(1, &framebuffer);
|
||||
}
|
||||
@@ -192,7 +240,7 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
|
||||
virtual bool createStencil(int width, int height, GLuint &stencil)
|
||||
{
|
||||
// create combined depth/stencil buffer
|
||||
glDeleteRenderbuffers(1, &stencil);
|
||||
glDeleteRenderbuffersEXT(1, &stencil);
|
||||
glGenRenderbuffersEXT(1, &stencil);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
|
||||
@@ -203,13 +251,47 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
// check status
|
||||
return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT;
|
||||
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(1, &stencil);
|
||||
stencil = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil)
|
||||
virtual bool createMSAABuffer(int width, int height, int &samples, GLenum internalformat, GLuint &buffer)
|
||||
{
|
||||
if (!GLEE_EXT_framebuffer_multisample)
|
||||
return false;
|
||||
|
||||
glGenRenderbuffersEXT(1, &buffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER, buffer);
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
|
||||
internalformat, width, height);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, buffer);
|
||||
glGetRenderbufferParameterivEXT(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
|
||||
|
||||
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(1, &buffer);
|
||||
buffer = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint msaa_buffer)
|
||||
{
|
||||
if (depth_stencil != 0)
|
||||
glDeleteRenderbuffersEXT(1, &depth_stencil);
|
||||
if (msaa_buffer != 0)
|
||||
glDeleteRenderbuffersEXT(1, &msaa_buffer);
|
||||
if (framebuffer != 0)
|
||||
glDeleteFramebuffersEXT(1, &framebuffer);
|
||||
}
|
||||
@@ -257,7 +339,7 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
|
||||
virtual bool createStencil(int width, int height, GLuint &stencil)
|
||||
{
|
||||
// create stencil buffer
|
||||
glDeleteRenderbuffers(1, &stencil);
|
||||
glDeleteRenderbuffersEXT(1, &stencil);
|
||||
glGenRenderbuffersEXT(1, &stencil);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
|
||||
@@ -268,14 +350,21 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
// check status
|
||||
return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT;
|
||||
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(1, &stencil);
|
||||
stencil = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isSupported()
|
||||
{
|
||||
GLuint fb = 0, stencil = 0;
|
||||
GLenum status = createFBO(fb, 0);
|
||||
deleteFBO(fb, stencil);
|
||||
deleteFBO(fb, stencil, 0);
|
||||
return status == GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
};
|
||||
@@ -311,11 +400,15 @@ static void getStrategy()
|
||||
static int maxFBOColorAttachments = 0;
|
||||
static int maxDrawBuffers = 0;
|
||||
|
||||
Canvas::Canvas(int width, int height, TextureType texture_type)
|
||||
Canvas::Canvas(int width, int height, TextureType texture_type, int fsaa)
|
||||
: fbo(0)
|
||||
, resolve_fbo(0)
|
||||
, texture(0)
|
||||
, fsaa_buffer(0)
|
||||
, depth_stencil(0)
|
||||
, texture_type(texture_type)
|
||||
, fsaa_samples(fsaa)
|
||||
, fsaa_dirty(false)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
@@ -357,9 +450,50 @@ Canvas::~Canvas()
|
||||
unloadVolatile();
|
||||
}
|
||||
|
||||
bool Canvas::createFSAAFBO(GLenum internalformat)
|
||||
{
|
||||
// Create our FBO without a texture.
|
||||
status = strategy->createFBO(fbo, 0);
|
||||
|
||||
GLuint previous = 0;
|
||||
if (current != this)
|
||||
{
|
||||
if (current != nullptr)
|
||||
previous = current->fbo;
|
||||
|
||||
strategy->bindFBO(fbo);
|
||||
}
|
||||
|
||||
// Create and attach the MSAA buffer for our FBO.
|
||||
if (strategy->createMSAABuffer(width, height, fsaa_samples, internalformat, fsaa_buffer))
|
||||
status = GL_FRAMEBUFFER_COMPLETE;
|
||||
else
|
||||
status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
|
||||
|
||||
// Create the FBO used for the MSAA resolve, and attach the texture.
|
||||
if (status == GL_FRAMEBUFFER_COMPLETE)
|
||||
status = strategy->createFBO(resolve_fbo, texture);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
// Clean up.
|
||||
strategy->deleteFBO(fbo, 0, fsaa_buffer);
|
||||
strategy->deleteFBO(resolve_fbo, 0, 0);
|
||||
fbo = fsaa_buffer = resolve_fbo = 0;
|
||||
fsaa_samples = 0;
|
||||
}
|
||||
|
||||
if (current != this)
|
||||
strategy->bindFBO(previous);
|
||||
|
||||
return status == GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
bool Canvas::loadVolatile()
|
||||
{
|
||||
fbo = depth_stencil = texture = 0;
|
||||
resolve_fbo = fsaa_buffer = 0;
|
||||
status = GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
// glTexImage2D is guaranteed to error in this case.
|
||||
if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize())
|
||||
@@ -406,7 +540,25 @@ bool Canvas::loadVolatile()
|
||||
return false;
|
||||
}
|
||||
|
||||
status = strategy->createFBO(fbo, texture);
|
||||
int max_samples = 0;
|
||||
if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object
|
||||
|| GLEE_EXT_framebuffer_multisample)
|
||||
{
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
|
||||
}
|
||||
|
||||
if (fsaa_samples > max_samples)
|
||||
fsaa_samples = max_samples;
|
||||
|
||||
// Try to create a FSAA FBO if requested.
|
||||
bool fsaasuccess = false;
|
||||
if (fsaa_samples > 1)
|
||||
fsaasuccess = createFSAAFBO(internalformat);
|
||||
|
||||
// On failure (or no requested FSAA), fall back to a regular FBO.
|
||||
if (!fsaasuccess)
|
||||
status = strategy->createFBO(fbo, texture);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
|
||||
@@ -416,11 +568,13 @@ bool Canvas::loadVolatile()
|
||||
|
||||
void Canvas::unloadVolatile()
|
||||
{
|
||||
strategy->deleteFBO(fbo, depth_stencil);
|
||||
strategy->deleteFBO(fbo, depth_stencil, fsaa_buffer);
|
||||
strategy->deleteFBO(resolve_fbo, 0, 0);
|
||||
|
||||
gl.deleteTexture(texture);
|
||||
|
||||
fbo = depth_stencil = texture = 0;
|
||||
resolve_fbo = fsaa_buffer = 0;
|
||||
|
||||
for (size_t i = 0; i < attachedCanvases.size(); i++)
|
||||
attachedCanvases[i]->release();
|
||||
@@ -428,13 +582,12 @@ void Canvas::unloadVolatile()
|
||||
attachedCanvases.clear();
|
||||
}
|
||||
|
||||
void Canvas::drawv(const Matrix &t, const Vertex *v) const
|
||||
void Canvas::drawv(const Matrix &t, const Vertex *v)
|
||||
{
|
||||
glPushMatrix();
|
||||
|
||||
glMultMatrixf((const GLfloat *)t.getElements());
|
||||
|
||||
gl.bindTexture(texture);
|
||||
predraw();
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
@@ -447,11 +600,13 @@ void Canvas::drawv(const Matrix &t, const Vertex *v) const
|
||||
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
postdraw();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
static Matrix t;
|
||||
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
@@ -459,7 +614,7 @@ void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, f
|
||||
drawv(t, vertices);
|
||||
}
|
||||
|
||||
void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
static Matrix t;
|
||||
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
@@ -487,8 +642,12 @@ GLuint Canvas::getGLTexture() const
|
||||
return texture;
|
||||
}
|
||||
|
||||
void Canvas::predraw() const
|
||||
void Canvas::predraw()
|
||||
{
|
||||
// We need to make sure the texture is up-to-date by resolving the MSAA
|
||||
// buffer (which we render to when the canvas is active) to it.
|
||||
resolveMSAA();
|
||||
|
||||
gl.bindTexture(texture);
|
||||
}
|
||||
|
||||
@@ -520,6 +679,9 @@ void Canvas::setupGrab()
|
||||
|
||||
// indicate we are using this fbo
|
||||
current = this;
|
||||
|
||||
if (fsaa_buffer != 0)
|
||||
fsaa_dirty = true;
|
||||
}
|
||||
|
||||
void Canvas::startGrab(const std::vector<Canvas *> &canvases)
|
||||
@@ -535,6 +697,9 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
|
||||
|
||||
if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments))
|
||||
throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1);
|
||||
|
||||
if (fsaa_samples != 0)
|
||||
throw love::Exception("Multi-canvas rendering is not supported with FSAA.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < canvases.size(); i++)
|
||||
@@ -545,6 +710,9 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
|
||||
if (canvases[i]->getTextureType() != texture_type)
|
||||
throw love::Exception("All canvas arguments must have the same texture type.");
|
||||
|
||||
if (canvases[i]->getFSAA() != 0)
|
||||
throw love::Exception("Multi-canvas rendering is not supported with FSAA.");
|
||||
|
||||
if (!canvaseschanged && canvases[i] != attachedCanvases[i])
|
||||
canvaseschanged = true;
|
||||
}
|
||||
@@ -674,12 +842,22 @@ bool Canvas::checkCreateStencil()
|
||||
|
||||
love::image::ImageData *Canvas::getImageData(love::image::Image *image)
|
||||
{
|
||||
resolveMSAA();
|
||||
|
||||
int row = 4 * width;
|
||||
int size = row * height;
|
||||
GLubyte *pixels = new GLubyte[size];
|
||||
|
||||
strategy->bindFBO(fbo);
|
||||
// Our texture is attached to 'resolve_fbo' when we use MSAA.
|
||||
if (fsaa_samples > 1 && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object))
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
|
||||
else if (fsaa_samples > 1 && GLEE_EXT_framebuffer_multisample)
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo);
|
||||
else
|
||||
strategy->bindFBO(fbo);
|
||||
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
if (current)
|
||||
strategy->bindFBO(current->fbo);
|
||||
else
|
||||
@@ -692,10 +870,17 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image)
|
||||
|
||||
void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
|
||||
{
|
||||
if (current != this)
|
||||
resolveMSAA();
|
||||
|
||||
// Our texture is attached to 'resolve_fbo' when we use MSAA.
|
||||
if (fsaa_samples > 1 && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object))
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
|
||||
else if (fsaa_samples > 1 && GLEE_EXT_framebuffer_multisample)
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo);
|
||||
else if (current != this)
|
||||
strategy->bindFBO(fbo);
|
||||
|
||||
glReadPixels(x, height - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba);
|
||||
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba);
|
||||
|
||||
if (current && current != this)
|
||||
strategy->bindFBO(current->fbo);
|
||||
@@ -703,6 +888,44 @@ void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
|
||||
strategy->bindFBO(0);
|
||||
}
|
||||
|
||||
bool Canvas::resolveMSAA()
|
||||
{
|
||||
if (resolve_fbo == 0 || fsaa_buffer == 0)
|
||||
return false;
|
||||
|
||||
if (!fsaa_dirty)
|
||||
return true;
|
||||
|
||||
GLuint previous = 0;
|
||||
if (current != nullptr)
|
||||
previous = current->fbo;
|
||||
|
||||
// Do the MSAA resolve by blitting the MSAA renderbuffer to the texture.
|
||||
if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
else if (GLEE_EXT_framebuffer_multisample && GLEE_EXT_framebuffer_blit)
|
||||
{
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbo);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, resolve_fbo);
|
||||
glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
strategy->bindFBO(previous);
|
||||
|
||||
if (current != this)
|
||||
fsaa_dirty = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Canvas::isSupported()
|
||||
{
|
||||
getStrategy();
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
TYPE_MAX_ENUM
|
||||
};
|
||||
|
||||
Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL);
|
||||
Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL, int fsaa = 0);
|
||||
virtual ~Canvas();
|
||||
|
||||
// Implements Volatile.
|
||||
@@ -54,14 +54,14 @@ public:
|
||||
virtual void unloadVolatile();
|
||||
|
||||
// Implements Drawable.
|
||||
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
// Implements Texture.
|
||||
virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
virtual void setFilter(const Texture::Filter &f);
|
||||
virtual void setWrap(const Texture::Wrap &w);
|
||||
virtual GLuint getGLTexture() const;
|
||||
virtual void predraw() const;
|
||||
virtual void predraw();
|
||||
|
||||
/**
|
||||
* @param canvases A list of other canvases to temporarily attach to this one,
|
||||
@@ -97,6 +97,13 @@ public:
|
||||
return texture_type;
|
||||
}
|
||||
|
||||
inline int getFSAA() const
|
||||
{
|
||||
return fsaa_samples;
|
||||
}
|
||||
|
||||
bool resolveMSAA();
|
||||
|
||||
static bool isSupported();
|
||||
static bool isHDRSupported();
|
||||
static bool isMultiCanvasSupported();
|
||||
@@ -112,8 +119,13 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
bool createFSAAFBO(GLenum internalformat);
|
||||
|
||||
GLuint fbo;
|
||||
GLuint resolve_fbo;
|
||||
|
||||
GLuint texture;
|
||||
GLuint fsaa_buffer;
|
||||
GLuint depth_stencil;
|
||||
|
||||
TextureType texture_type;
|
||||
@@ -122,8 +134,11 @@ private:
|
||||
|
||||
std::vector<Canvas *> attachedCanvases;
|
||||
|
||||
int fsaa_samples;
|
||||
bool fsaa_dirty;
|
||||
|
||||
void setupGrab();
|
||||
void drawv(const Matrix &t, const Vertex *v) const;
|
||||
void drawv(const Matrix &t, const Vertex *v);
|
||||
|
||||
static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
|
||||
static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes;
|
||||
|
||||
@@ -392,7 +392,7 @@ ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
|
||||
return new ParticleSystem(texture, size);
|
||||
}
|
||||
|
||||
Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type)
|
||||
Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type, int fsaa)
|
||||
{
|
||||
if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported())
|
||||
throw Exception("HDR Canvases are not supported by your OpenGL implementation");
|
||||
@@ -405,7 +405,7 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_t
|
||||
while (GL_NO_ERROR != glGetError())
|
||||
/* clear opengl error flag */;
|
||||
|
||||
Canvas *canvas = new Canvas(width, height, texture_type);
|
||||
Canvas *canvas = new Canvas(width, height, texture_type, fsaa);
|
||||
GLenum err = canvas->getStatus();
|
||||
|
||||
// everything ok, return canvas (early out)
|
||||
|
||||
@@ -208,7 +208,7 @@ public:
|
||||
|
||||
ParticleSystem *newParticleSystem(Texture *texture, int size);
|
||||
|
||||
Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL);
|
||||
Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL, int fsaa = 0);
|
||||
|
||||
Shader *newShader(const Shader::ShaderSources &sources);
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ love::image::CompressedData *Image::getCompressedData() const
|
||||
return cdata;
|
||||
}
|
||||
|
||||
void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
Matrix t;
|
||||
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
@@ -99,7 +99,7 @@ void Image::draw(float x, float y, float angle, float sx, float sy, float ox, fl
|
||||
drawv(t, vertices);
|
||||
}
|
||||
|
||||
void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
Matrix t;
|
||||
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||
@@ -107,7 +107,7 @@ void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy,
|
||||
drawv(t, quad->getVertices());
|
||||
}
|
||||
|
||||
void Image::predraw() const
|
||||
void Image::predraw()
|
||||
{
|
||||
bind();
|
||||
|
||||
@@ -121,7 +121,7 @@ void Image::predraw() const
|
||||
}
|
||||
}
|
||||
|
||||
void Image::postdraw() const
|
||||
void Image::postdraw()
|
||||
{
|
||||
if (width != paddedWidth || height != paddedHeight)
|
||||
{
|
||||
@@ -511,7 +511,7 @@ void Image::uploadDefaultTexture()
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, px);
|
||||
}
|
||||
|
||||
void Image::drawv(const Matrix &t, const Vertex *v) const
|
||||
void Image::drawv(const Matrix &t, const Vertex *v)
|
||||
{
|
||||
predraw();
|
||||
|
||||
|
||||
@@ -76,20 +76,20 @@ public:
|
||||
/**
|
||||
* @copydoc Drawable::draw()
|
||||
**/
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
/**
|
||||
* @copydoc Texture::drawq()
|
||||
**/
|
||||
void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
/**
|
||||
* Call before using this Image's texture to draw. Binds the texture,
|
||||
* globally scales texture coordinates if the Image has NPOT dimensions and
|
||||
* NPOT isn't supported, etc.
|
||||
**/
|
||||
virtual void predraw() const;
|
||||
virtual void postdraw() const;
|
||||
virtual void predraw();
|
||||
virtual void postdraw();
|
||||
|
||||
virtual GLuint getGLTexture() const;
|
||||
|
||||
@@ -137,7 +137,7 @@ private:
|
||||
|
||||
void uploadDefaultTexture();
|
||||
|
||||
void drawv(const Matrix &t, const Vertex *v) const;
|
||||
void drawv(const Matrix &t, const Vertex *v);
|
||||
|
||||
// The ImageData from which the texture is created. May be null if
|
||||
// Compressed image data was used to create the texture.
|
||||
|
||||
@@ -288,7 +288,7 @@ bool Mesh::isWireframe() const
|
||||
return wireframe;
|
||||
}
|
||||
|
||||
void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
const size_t pos_offset = offsetof(Vertex, x);
|
||||
const size_t tex_offset = offsetof(Vertex, s);
|
||||
|
||||
@@ -172,7 +172,7 @@ public:
|
||||
bool isWireframe() const;
|
||||
|
||||
// Implements Drawable.
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
static bool getConstant(const char *in, DrawMode &out);
|
||||
static bool getConstant(DrawMode in, const char *&out);
|
||||
|
||||
@@ -230,6 +230,18 @@ void OpenGL::prepareDraw()
|
||||
glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, 0.0f);
|
||||
state.lastPseudoInstanceID = 0;
|
||||
}
|
||||
|
||||
// We need to make sure antialiased Canvases are properly resolved
|
||||
// before sampling from their textures in a shader.
|
||||
// This is kind of a big hack. :(
|
||||
const std::map<std::string, Object *> &r = shader->getBoundRetainables();
|
||||
for (auto it = r.begin(); it != r.end(); ++it)
|
||||
{
|
||||
// Even bigger hack! D:
|
||||
Canvas *canvas = dynamic_cast<Canvas *>(it->second);
|
||||
if (canvas != nullptr)
|
||||
canvas->resolveMSAA();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -780,7 +780,7 @@ bool ParticleSystem::isFull() const
|
||||
return activeParticles == maxParticles;
|
||||
}
|
||||
|
||||
void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
uint32 pCount = getCount();
|
||||
if (pCount == 0 || texture == nullptr || pMem == nullptr || particleVerts == nullptr)
|
||||
|
||||
@@ -470,7 +470,7 @@ public:
|
||||
* @param x The x-coordinate.
|
||||
* @param y The y-coordinate.
|
||||
**/
|
||||
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
/**
|
||||
* Updates the particle system.
|
||||
|
||||
@@ -719,6 +719,11 @@ void Shader::checkSetScreenParams()
|
||||
lastCanvas = Canvas::current;
|
||||
}
|
||||
|
||||
const std::map<std::string, Object *> &Shader::getBoundRetainables() const
|
||||
{
|
||||
return boundRetainables;
|
||||
}
|
||||
|
||||
std::string Shader::getGLSLVersion()
|
||||
{
|
||||
const char *tmp = nullptr;
|
||||
|
||||
@@ -143,6 +143,8 @@ public:
|
||||
bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count);
|
||||
void checkSetScreenParams();
|
||||
|
||||
const std::map<std::string, Object *> &getBoundRetainables() const;
|
||||
|
||||
static std::string getGLSLVersion();
|
||||
static bool isSupported();
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ int SpriteBatch::getBufferSize() const
|
||||
return size;
|
||||
}
|
||||
|
||||
void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
||||
void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
||||
{
|
||||
const size_t vertex_offset = offsetof(Vertex, x);
|
||||
const size_t texel_offset = offsetof(Vertex, s);
|
||||
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
int getBufferSize() const;
|
||||
|
||||
// Implements Drawable.
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
static bool getConstant(const char *in, UsageHint &out);
|
||||
static bool getConstant(UsageHint in, const char *&out);
|
||||
|
||||
@@ -48,12 +48,12 @@ public:
|
||||
* Any setup the texture might need to do before drawing, e.g. binding
|
||||
* the OpenGL texture for use.
|
||||
**/
|
||||
virtual void predraw() const {}
|
||||
virtual void predraw() {}
|
||||
|
||||
/**
|
||||
* Any cleanup the texture might need to do directly after drawing.
|
||||
**/
|
||||
virtual void postdraw() const {}
|
||||
virtual void postdraw() {}
|
||||
|
||||
|
||||
}; // Texture
|
||||
|
||||
@@ -120,6 +120,13 @@ int w_Canvas_getType(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Canvas_getFSAA(lua_State *L)
|
||||
{
|
||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||
lua_pushinteger(L, canvas->getFSAA());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
// From wrap_Texture.
|
||||
@@ -136,6 +143,7 @@ static const luaL_Reg functions[] =
|
||||
{ "getPixel", w_Canvas_getPixel },
|
||||
{ "clear", w_Canvas_clear },
|
||||
{ "getType", w_Canvas_getType },
|
||||
{ "getFSAA", w_Canvas_getFSAA },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ int w_Canvas_getImageData(lua_State *L);
|
||||
int w_Canvas_getPixel(lua_State * L);
|
||||
int w_Canvas_clear(lua_State *L);
|
||||
int w_Canvas_getType(lua_State *L);
|
||||
int w_Canvas_getFSAA(lua_State *L);
|
||||
extern "C" int luaopen_canvas(lua_State *L);
|
||||
|
||||
} // opengl
|
||||
|
||||
@@ -323,15 +323,16 @@ int w_newCanvas(lua_State *L)
|
||||
int width = luaL_optint(L, 1, instance->getWidth());
|
||||
int height = luaL_optint(L, 2, instance->getHeight());
|
||||
const char *str = luaL_optstring(L, 3, "normal");
|
||||
int fsaa = luaL_optint(L, 4, 0);
|
||||
|
||||
Canvas::TextureType texture_type;
|
||||
if (!Canvas::getConstant(str, texture_type))
|
||||
return luaL_error(L, "Invalid canvas type: %s", str);
|
||||
|
||||
Canvas *canvas = 0;
|
||||
EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type);)
|
||||
Canvas *canvas = nullptr;
|
||||
EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type, fsaa);)
|
||||
|
||||
if (canvas == 0)
|
||||
if (canvas == nullptr)
|
||||
return luaL_error(L, "Canvas not created, but no error thrown. I don't even...");
|
||||
|
||||
luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, canvas);
|
||||
|
||||
Reference in New Issue
Block a user