Render pass API. Replaces love.graphics.setCanvas and friends.

- Removed love.graphics.set/getCanvas, Canvas:renderTo, Canvas:newImageData, love.graphics.clear, love.graphics.discard, and love.graphics.newScreenshot.

- Added love.graphics.beginPass and love.graphics.endPass. All rendering must happen within a pass. love.draw is now called while a render pass to the main screen is active.
- Added love.graphics.renderPass, which is a wrapper for begin/endPass which calls the supplied function argument in between a begin/end. This is similar to the old Canvas:renderTo.
- Added love.graphics.isPassActive, getPassCanvases, getPassWidth, getPassHeight, and getPassDimensions.
- Added love.graphics.captureScreenshot.

- Added a new love.run callback love.drawpasses, which is called after love.update and before love.draw. It is the place to render to Canvases using beginPass or renderPass, since love.draw now always draws to the main screen.

- Renamed the ‘canvasswitches’ field in the table returned by love.graphics.getStats to ‘renderpasses’.

love.graphics.beginPass has the following variants (and renderPass mirrors them with an additional function argument at the end):

- love.graphics.beginPass(), begins rendering to the main screen without clearing it.
- love.graphics.beginPass(r, g, b [, a]), begins rendering to the main screen and clears the screen to the specified color.

- love.graphics.beginPass(canvas [, willstencil]), begins rendering to the specified Canvas without clearing it. love.graphics.stencil can only be used within the Canvas if ‘willstencil’ is true.
- love.graphics.beginPass(canvas, r, g, b [, a] [, willstencil]), beings rendering to the specified Canvas and clears it to the specified color. love.graphics.stencil can only be used within the Canvas if ‘willstencil’ is true.

- love.graphics.beginPass(info), where ‘info’ is a table in the following form:
{
    {canvas [, r, g, b, a]}, — A canvas and an optional color to clear the Canvas to when the pass begins.
    {canvas2, [r, g, b, a]}, — Additional Canvases and optional clear colors for multi-canvas rendering.
    …,
    stencil = false, — Optional boolean field to specify whether love.graphics.stencil is allowed within this pass. False by default.
}

The pass info table can be created once up-front and used for multiple beginPass/renderPass calls.

love.graphics.endPass can take an optional callback function argument, which causes endPass to capture the contents of the Canvas drawn to in the render pass to a new ImageData and passes it to the supplied function (this replaces Canvas:newImageData). This does not work on the main screen.

love.graphics.captureScreenshot replaces love.graphics.newScreenshot. It takes a callback function argument which causes love.graphics.present to capture the contents of the screen to a new ImageData and passes it to the supplied function. captureScreenshot can only be called before drawing to the main screen begins in the current frame (e.g. in love.keypressed, love.update, etc.)

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2016-11-19 19:13:26 -04:00
parent aeca14a35a
commit 3e80ec2257
24 changed files with 2562 additions and 1123 deletions
+98 -37
View File
@@ -24,6 +24,7 @@
// STD
#include <stack>
#include <vector>
#include <unordered_map>
// OpenGL
#include "OpenGL.h"
@@ -35,8 +36,6 @@
#include "image/Image.h"
#include "image/ImageData.h"
#include "window/Window.h"
#include "video/VideoStream.h"
#include "Font.h"
@@ -53,21 +52,63 @@
namespace love
{
class Reference;
namespace graphics
{
namespace opengl
{
struct PassInfo
{
enum BeginAction
{
BEGIN_LOAD,
BEGIN_CLEAR,
BEGIN_DISCARD,
};
enum EndAction
{
END_STORE,
END_DISCARD,
};
struct ColorAttachment
{
Canvas *canvas = nullptr;
Colorf clearColor = Colorf(0.0f, 0.0f, 0.0f, 0.0f);
BeginAction beginAction = BEGIN_LOAD;
};
ColorAttachment colorAttachments[MAX_COLOR_RENDER_TARGETS];
int colorAttachmentCount = 0;
bool stencil = false;
bool addColorAttachment(const ColorAttachment &attachment)
{
if (colorAttachmentCount + 1 < MAX_COLOR_RENDER_TARGETS)
{
colorAttachments[colorAttachmentCount++] = attachment;
return true;
}
return false;
}
};
class Graphics : public love::graphics::Graphics
{
public:
struct OptionalColorf
{
float r, g, b, a;
bool enabled;
typedef void (*ScreenshotCallback)(love::image::ImageData *i, Reference *ref, void *ud);
Colorf toColor() const { return Colorf(r, g, b, a); }
struct ScreenshotInfo
{
ScreenshotCallback callback;
Reference *ref;
};
Graphics();
@@ -92,25 +133,19 @@ public:
**/
void reset();
/**
* Clears the screen to a specific color.
**/
void clear(Colorf c);
void beginPass(PassInfo::BeginAction beginAction, Colorf clearColor);
void beginPass(const PassInfo &info);
/**
* Clears each active canvas to a different color.
**/
void clear(const std::vector<OptionalColorf> &colors);
void endPass();
void endPass(int sX, int sY, int sW, int sH, const ScreenshotInfo *info, void *screenshotCallbackData);
/**
* Discards the contents of the screen.
**/
void discard(const std::vector<bool> &colorbuffers, bool stencil);
const PassInfo &getActivePass() const;
virtual bool isPassActive() const;
/**
* Flips buffers. (Rendered geometry is presented on screen).
**/
void present();
void present(void *screenshotCallbackData);
/**
* Gets the width of the current graphics viewport.
@@ -122,6 +157,9 @@ public:
**/
int getHeight() const;
int getPassWidth() const;
int getPassHeight() const;
/**
* True if a graphics viewport is set.
**/
@@ -231,13 +269,6 @@ public:
Shader *getShader() const;
void setCanvas(Canvas *canvas);
void setCanvas(const std::vector<Canvas *> &canvases);
void setCanvas(const std::vector<StrongRef<Canvas>> &canvases);
void setCanvas();
std::vector<Canvas *> getCanvas() const;
/**
* Sets the enabled color components when rendering.
**/
@@ -330,6 +361,9 @@ public:
**/
bool isWireframe() const;
void draw(Drawable *drawable, const Matrix4 &m);
void drawq(Texture *texture, Quad *quad, const Matrix4 &m);
/**
* Draws text at the specified coordinates
**/
@@ -422,12 +456,7 @@ public:
**/
void polygon(DrawMode mode, const float *coords, size_t count);
/**
* Creates a screenshot of the view and saves it to the default folder.
* @param image The love.image module.
* @param copyAlpha If the alpha channel should be copied or set to full opacity (1.0).
**/
love::image::ImageData *newScreenshot(love::image::Image *image, bool copyAlpha = true);
void captureScreenshot(const ScreenshotInfo &info);
/**
* Returns system-dependent renderer information.
@@ -488,8 +517,6 @@ private:
StrongRef<Font> font;
StrongRef<Shader> shader;
std::vector<StrongRef<Canvas>> canvases;
ColorMask colorMask = ColorMask(true, true, true, true);
bool wireframe = false;
@@ -500,19 +527,47 @@ private:
float defaultMipmapSharpness = 0.0f;
};
struct CurrentPass
{
PassInfo info;
bool active;
};
struct PassBufferInfo
{
bool stencil;
Canvas *canvases[MAX_COLOR_RENDER_TARGETS];
};
struct CachedRenderbuffer
{
int w;
int h;
int samples;
GLenum attachments[2];
GLuint renderbuffer;
};
void restoreState(const DisplayState &s);
void restoreStateChecked(const DisplayState &s);
void bindCachedFBOForPass(const PassInfo &pass);
void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
GLuint attachCachedStencilBuffer(int w, int h, int samples);
void checkSetDefaultFont();
int calculateEllipsePoints(float rx, float ry) const;
StrongRef<love::window::Window> currentWindow;
StrongRef<Font> defaultFont;
std::vector<double> pixelSizeStack; // stores current size of a pixel (needed for line drawing)
std::vector<ScreenshotInfo> pendingScreenshotCallbacks;
std::unordered_map<uint32, GLuint> framebufferObjects;
std::vector<CachedRenderbuffer> stencilBuffers;
QuadIndices *quadIndices;
int width;
@@ -520,11 +575,17 @@ private:
bool created;
bool active;
bool canCaptureScreenshot;
CurrentPass currentPass;
bool writingToStencil;
std::vector<DisplayState> states;
std::vector<StackType> stackTypes; // Keeps track of the pushed stack types.
int renderPassCount;
static const size_t MAX_USER_STACK_DEPTH = 64;
}; // Graphics