updated to latest mobile-common (0cf55b7da58e), removed libtiff, libpng, libmng, devil, jasper, jpeg-8d, added libturbo-jpeg

This commit is contained in:
fysx
2014-08-27 23:19:11 +02:00
parent aba2f47b31
commit abb819335b
1910 changed files with 78167 additions and 922995 deletions
+19 -1
View File
@@ -109,6 +109,16 @@ bool Graphics::getConstant(SystemLimit in, const char *&out)
return systemLimits.find(in, out);
}
bool Graphics::getConstant(const char *in, StackType &out)
{
return stackTypes.find(in, out);
}
bool Graphics::getConstant(StackType in, const char *&out)
{
return stackTypes.find(in, out);
}
StringMap<Graphics::DrawMode, Graphics::DRAW_MAX_ENUM>::Entry Graphics::drawModeEntries[] =
{
{ "line", Graphics::DRAW_LINE },
@@ -178,7 +188,6 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
{ "bc5", Graphics::SUPPORT_BC5 },
{ "etc1", Graphics::SUPPORT_ETC1 },
{ "pvrtc1", Graphics::SUPPORT_PVRTC1 },
{ "instancing", Graphics::SUPPORT_INSTANCING },
{ "srgb", Graphics::SUPPORT_SRGB },
};
@@ -190,9 +199,18 @@ StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM>::Entry Graphics::syst
{"texturesize", Graphics::LIMIT_TEXTURE_SIZE},
{"multicanvas", Graphics::LIMIT_MULTI_CANVAS},
{"canvasfsaa", Graphics::LIMIT_CANVAS_FSAA},
{"canvasmsaa", Graphics::LIMIT_CANVAS_MSAA},
};
StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM> Graphics::systemLimits(Graphics::systemLimitEntries, sizeof(Graphics::systemLimitEntries));
StringMap<Graphics::StackType, Graphics::STACK_MAX_ENUM>::Entry Graphics::stackTypeEntries[] =
{
{"all", Graphics::STACK_ALL},
{"transform", Graphics::STACK_TRANSFORM},
};
StringMap<Graphics::StackType, Graphics::STACK_MAX_ENUM> Graphics::stackTypes(Graphics::stackTypeEntries, sizeof(Graphics::stackTypeEntries));
} // graphics
} // love
+36 -18
View File
@@ -25,6 +25,9 @@
#include "common/Module.h"
#include "common/StringMap.h"
// C++
#include <string>
namespace love
{
namespace graphics
@@ -36,14 +39,14 @@ public:
enum DrawMode
{
DRAW_LINE = 1,
DRAW_LINE,
DRAW_FILL,
DRAW_MAX_ENUM
};
enum AlignMode
{
ALIGN_LEFT = 1,
ALIGN_LEFT,
ALIGN_CENTER,
ALIGN_RIGHT,
ALIGN_JUSTIFY,
@@ -52,7 +55,7 @@ public:
enum BlendMode
{
BLEND_ALPHA = 1,
BLEND_ALPHA,
BLEND_ADDITIVE,
BLEND_SUBTRACTIVE,
BLEND_MULTIPLICATIVE,
@@ -64,14 +67,14 @@ public:
enum LineStyle
{
LINE_ROUGH = 1,
LINE_ROUGH,
LINE_SMOOTH,
LINE_MAX_ENUM
};
enum LineJoin
{
LINE_JOIN_NONE = 1,
LINE_JOIN_NONE,
LINE_JOIN_MITER,
LINE_JOIN_BEVEL,
LINE_JOIN_MAX_ENUM
@@ -79,14 +82,14 @@ public:
enum PointStyle
{
POINT_ROUGH = 1,
POINT_ROUGH,
POINT_SMOOTH,
POINT_MAX_ENUM
};
enum Support
{
SUPPORT_CANVAS = 1,
SUPPORT_CANVAS,
SUPPORT_HDR_CANVAS,
SUPPORT_MULTI_CANVAS,
SUPPORT_SHADER,
@@ -97,7 +100,6 @@ public:
SUPPORT_BC5,
SUPPORT_ETC1,
SUPPORT_PVRTC1,
SUPPORT_INSTANCING,
SUPPORT_SRGB,
SUPPORT_MAX_ENUM
};
@@ -109,26 +111,36 @@ public:
RENDERER_MAX_ENUM
};
enum RendererInfo
{
RENDERER_INFO_NAME = 1,
RENDERER_INFO_VERSION,
RENDERER_INFO_VENDOR,
RENDERER_INFO_DEVICE,
RENDERER_INFO_MAX_ENUM
};
enum SystemLimit
{
LIMIT_POINT_SIZE,
LIMIT_TEXTURE_SIZE,
LIMIT_MULTI_CANVAS,
LIMIT_CANVAS_FSAA,
LIMIT_CANVAS_FSAA, // For backward-compatibility. TODO: remove!
LIMIT_CANVAS_MSAA,
LIMIT_MAX_ENUM
};
enum StackType
{
STACK_ALL,
STACK_TRANSFORM,
STACK_MAX_ENUM
};
struct RendererInfo
{
std::string name;
std::string version;
std::string vendor;
std::string device;
};
virtual ~Graphics();
// Implements Module.
virtual ModuleType getModuleType() const { return M_GRAPHICS; }
/**
* Sets the current graphics display viewport dimensions.
**/
@@ -185,6 +197,9 @@ public:
static bool getConstant(const char *in, SystemLimit &out);
static bool getConstant(SystemLimit in, const char *&out);
static bool getConstant(const char *in, StackType &out);
static bool getConstant(StackType in, const char *&out);
private:
static StringMap<DrawMode, DRAW_MAX_ENUM>::Entry drawModeEntries[];
@@ -211,6 +226,9 @@ private:
static StringMap<SystemLimit, LIMIT_MAX_ENUM>::Entry systemLimitEntries[];
static StringMap<SystemLimit, LIMIT_MAX_ENUM> systemLimits;
static StringMap<StackType, STACK_MAX_ENUM>::Entry stackTypeEntries[];
static StringMap<StackType, STACK_MAX_ENUM> stackTypes;
}; // Graphics
} // graphics
+1 -1
View File
@@ -96,7 +96,7 @@ public:
virtual void setFilter(const Filter &f) = 0;
virtual const Filter &getFilter() const;
virtual void setWrap(const Wrap &w) = 0;
virtual bool setWrap(const Wrap &w) = 0;
virtual const Wrap &getWrap() const;
virtual const Vertex *getVertices() const;
+62 -64
View File
@@ -451,15 +451,15 @@ static void getStrategy()
}
}
Canvas::Canvas(int width, int height, Format format, int fsaa)
Canvas::Canvas(int width, int height, Format format, int msaa)
: fbo(0)
, resolve_fbo(0)
, texture(0)
, fsaa_buffer(0)
, msaa_buffer(0)
, depth_stencil(0)
, format(format)
, fsaa_samples(fsaa)
, fsaa_dirty(false)
, msaa_samples(msaa)
, msaa_dirty(false)
{
this->width = width;
this->height = height;
@@ -501,7 +501,7 @@ Canvas::~Canvas()
unloadVolatile();
}
bool Canvas::createFSAAFBO(GLenum internalformat)
bool Canvas::createMSAAFBO(GLenum internalformat)
{
// Create our FBO without a texture.
status = strategy->createFBO(fbo, 0);
@@ -516,7 +516,7 @@ bool Canvas::createFSAAFBO(GLenum internalformat)
}
// Create and attach the MSAA buffer for our FBO.
if (strategy->createMSAABuffer(width, height, fsaa_samples, internalformat, fsaa_buffer))
if (strategy->createMSAABuffer(width, height, msaa_samples, internalformat, msaa_buffer))
status = GL_FRAMEBUFFER_COMPLETE;
else
status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
@@ -528,10 +528,10 @@ bool Canvas::createFSAAFBO(GLenum internalformat)
if (status != GL_FRAMEBUFFER_COMPLETE)
{
// Clean up.
strategy->deleteFBO(fbo, 0, fsaa_buffer);
strategy->deleteFBO(fbo, 0, msaa_buffer);
strategy->deleteFBO(resolve_fbo, 0, 0);
fbo = fsaa_buffer = resolve_fbo = 0;
fsaa_samples = 0;
fbo = msaa_buffer = resolve_fbo = 0;
msaa_samples = 0;
}
if (current != this)
@@ -543,7 +543,7 @@ bool Canvas::createFSAAFBO(GLenum internalformat)
bool Canvas::loadVolatile()
{
fbo = depth_stencil = texture = 0;
resolve_fbo = fsaa_buffer = 0;
resolve_fbo = msaa_buffer = 0;
status = GL_FRAMEBUFFER_COMPLETE;
// glTexImage2D is guaranteed to error in this case.
@@ -597,16 +597,16 @@ bool Canvas::loadVolatile()
glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
}
if (fsaa_samples > max_samples)
fsaa_samples = max_samples;
if (msaa_samples > max_samples)
msaa_samples = max_samples;
// Try to create a FSAA FBO if requested.
bool fsaasuccess = false;
if (fsaa_samples > 1)
fsaasuccess = createFSAAFBO(internalformat);
// Try to create a MSAA FBO if requested.
bool msaasuccess = false;
if (msaa_samples > 1)
msaasuccess = createMSAAFBO(internalformat);
// On failure (or no requested FSAA), fall back to a regular FBO.
if (!fsaasuccess)
// On failure (or no requested MSAA), fall back to a regular FBO.
if (!msaasuccess)
status = strategy->createFBO(fbo, texture);
if (status != GL_FRAMEBUFFER_COMPLETE)
@@ -614,31 +614,28 @@ bool Canvas::loadVolatile()
clear(Color(0, 0, 0, 0));
fsaa_dirty = (fsaa_buffer != 0);
msaa_dirty = (msaa_buffer != 0);
return true;
}
void Canvas::unloadVolatile()
{
strategy->deleteFBO(fbo, depth_stencil, fsaa_buffer);
strategy->deleteFBO(fbo, depth_stencil, msaa_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();
resolve_fbo = msaa_buffer = 0;
attachedCanvases.clear();
}
void Canvas::drawv(const Matrix &t, const Vertex *v)
{
gl.matrices.transform.push(gl.matrices.transform.top());
gl.matrices.transform.top() *= t;
OpenGL::TempTransform transform(gl);
transform.get() *= t;
gl.prepareDraw();
@@ -656,8 +653,6 @@ void Canvas::drawv(const Matrix &t, const Vertex *v)
gl.disableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
postdraw();
gl.matrices.transform.pop();
}
void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
@@ -684,11 +679,24 @@ void Canvas::setFilter(const Texture::Filter &f)
gl.setTextureFilter(filter);
}
void Canvas::setWrap(const Texture::Wrap &w)
bool Canvas::setWrap(const Texture::Wrap &w)
{
bool success = true;
wrap = w;
if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
{
if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP)
success = false;
// If we only have limited NPOT support then the wrap mode must be CLAMP.
wrap.s = wrap.t = WRAP_CLAMP;
}
gl.bindTexture(texture);
gl.setTextureWrap(wrap);
return success;
}
GLuint Canvas::getGLTexture() const
@@ -727,8 +735,8 @@ void Canvas::setupGrab()
strategy->bindFBO(fbo);
gl.setViewport(OpenGL::Viewport(0, 0, width, height));
// Set up orthographic view (no depth)
gl.matrices.projection.push(Matrix::ortho(0.0, width, 0.0, height));
// Set up the projection matrix
gl.matrices.projection.push_back(Matrix::ortho(0.0, width, 0.0, height));
// Make sure the correct sRGB setting is used when drawing to the canvas.
if (GLAD_VERSION_1_1 || GLAD_EXT_sRGB_write_control)
@@ -739,8 +747,8 @@ void Canvas::setupGrab()
glDisable(GL_FRAMEBUFFER_SRGB);
}
if (fsaa_buffer != 0)
fsaa_dirty = true;
if (msaa_buffer != 0)
msaa_dirty = true;
}
void Canvas::startGrab(const std::vector<Canvas *> &canvases)
@@ -757,8 +765,8 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if ((int) canvases.size() + 1 > gl.getMaxRenderTargets())
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.");
if (msaa_samples != 0)
throw love::Exception("Multi-canvas rendering is not supported with MSAA.");
}
for (size_t i = 0; i < canvases.size(); i++)
@@ -769,8 +777,8 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if (canvases[i]->getTextureFormat() != format)
throw love::Exception("All canvas arguments must have the same texture format.");
if (canvases[i]->getFSAA() != 0)
throw love::Exception("Multi-canvas rendering is not supported with FSAA.");
if (canvases[i]->getMSAA() != 0)
throw love::Exception("Multi-canvas rendering is not supported with MSAA.");
if (!canvaseschanged && canvases[i] != attachedCanvases[i])
canvaseschanged = true;
@@ -785,11 +793,8 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
// Attach the canvas textures to the active FBO and set up MRTs.
strategy->setAttachments(canvases);
for (size_t i = 0; i < canvases.size(); i++)
canvases[i]->retain();
for (size_t i = 0; i < attachedCanvases.size(); i++)
attachedCanvases[i]->release();
// We want to avoid reference cycles, so we don't retain the attached
// Canvases here. The code in Graphics::setCanvas retains them.
attachedCanvases = canvases;
}
@@ -804,10 +809,6 @@ void Canvas::startGrab()
// make sure the FBO is only using a single canvas
strategy->setAttachments();
// release any previously attached canvases
for (size_t i = 0; i < attachedCanvases.size(); i++)
attachedCanvases[i]->release();
attachedCanvases.clear();
}
@@ -824,6 +825,8 @@ void Canvas::stopGrab(bool switchingToOtherCanvas)
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, attachments);
}
gl.matrices.projection.pop_back();
if (switchingToOtherCanvas)
{
if (GLAD_VERSION_1_1 || GLAD_EXT_sRGB_write_control)
@@ -847,8 +850,6 @@ void Canvas::stopGrab(bool switchingToOtherCanvas)
glEnable(GL_FRAMEBUFFER_SRGB);
}
}
gl.matrices.projection.pop();
}
void Canvas::clear(Color c)
@@ -902,8 +903,8 @@ void Canvas::clear(Color c)
if (current != this)
strategy->bindFBO(previous);
if (fsaa_buffer != 0)
fsaa_dirty = true;
if (msaa_buffer != 0)
msaa_dirty = true;
}
bool Canvas::checkCreateStencil()
@@ -915,7 +916,7 @@ bool Canvas::checkCreateStencil()
if (current != this)
strategy->bindFBO(fbo);
bool success = strategy->createStencil(width, height, fsaa_samples, depth_stencil);
bool success = strategy->createStencil(width, height, msaa_samples, depth_stencil);
if (current && current != this)
strategy->bindFBO(current->fbo);
@@ -934,9 +935,9 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image)
GLubyte *pixels = new GLubyte[size];
// Our texture is attached to 'resolve_fbo' when we use MSAA.
if (fsaa_samples > 1 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
if (msaa_samples > 1 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
else if (fsaa_samples > 1 && GLAD_EXT_framebuffer_multisample)
else if (msaa_samples > 1 && GLAD_EXT_framebuffer_multisample)
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo);
else
strategy->bindFBO(fbo);
@@ -955,12 +956,15 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image)
void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
{
if (x < 0 || x >= width || y < 0 || y >= width)
throw love::Exception("Attempt to get out-of-range pixel (%d,%d)!", x, y);
resolveMSAA();
// Our texture is attached to 'resolve_fbo' when we use MSAA.
if (fsaa_samples > 1 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
if (msaa_samples > 1 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
else if (fsaa_samples > 1 && GLAD_EXT_framebuffer_multisample)
else if (msaa_samples > 1 && GLAD_EXT_framebuffer_multisample)
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo);
else if (current != this)
strategy->bindFBO(fbo);
@@ -975,10 +979,10 @@ void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
bool Canvas::resolveMSAA()
{
if (resolve_fbo == 0 || fsaa_buffer == 0)
if (resolve_fbo == 0 || msaa_buffer == 0)
return false;
if (!fsaa_dirty)
if (!msaa_dirty)
return true;
GLuint previous = 0;
@@ -1006,7 +1010,7 @@ bool Canvas::resolveMSAA()
strategy->bindFBO(previous);
if (current != this)
fsaa_dirty = false;
msaa_dirty = false;
return true;
}
@@ -1203,12 +1207,6 @@ bool Canvas::isFormatSupported(Canvas::Format format)
return supported;
}
void Canvas::bindDefaultCanvas()
{
if (current != nullptr)
current->stopGrab();
}
bool Canvas::getConstant(const char *in, Format &out)
{
return formats.find(in, out);
@@ -57,7 +57,7 @@ public:
FORMAT_MAX_ENUM
};
Canvas(int width, int height, Format format = FORMAT_NORMAL, int fsaa = 0);
Canvas(int width, int height, Format format = FORMAT_NORMAL, int msaa = 0);
virtual ~Canvas();
// Implements Volatile.
@@ -70,7 +70,7 @@ public:
// 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);
virtual void setFilter(const Texture::Filter &f);
virtual void setWrap(const Texture::Wrap &w);
virtual bool setWrap(const Texture::Wrap &w);
virtual GLuint getGLTexture() const;
virtual void predraw();
@@ -108,9 +108,9 @@ public:
return format;
}
inline int getFSAA() const
inline int getMSAA() const
{
return fsaa_samples;
return msaa_samples;
}
bool resolveMSAA();
@@ -120,7 +120,6 @@ public:
static bool isFormatSupported(Format format);
static Canvas *current;
static void bindDefaultCanvas();
// The viewport dimensions of the system (default) framebuffer.
static OpenGL::Viewport systemViewport;
@@ -133,7 +132,7 @@ public:
private:
bool createFSAAFBO(GLenum internalformat);
bool createMSAAFBO(GLenum internalformat);
static Format getSizedFormat(Format format);
static void convertFormat(Format format, GLenum &internalformat, GLenum &externalformat, GLenum &type);
@@ -142,7 +141,7 @@ private:
GLuint resolve_fbo;
GLuint texture;
GLuint fsaa_buffer;
GLuint msaa_buffer;
GLuint depth_stencil;
Format format;
@@ -151,8 +150,8 @@ private:
std::vector<Canvas *> attachedCanvases;
int fsaa_samples;
bool fsaa_dirty;
int msaa_samples;
bool msaa_dirty;
void setupGrab();
void drawv(const Matrix &t, const Vertex *v);
@@ -90,14 +90,11 @@ Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter)
}
delete gd;
rasterizer->retain();
}
Font::~Font()
{
delete indexBuffer;
rasterizer->release();
unloadVolatile();
}
@@ -385,11 +382,11 @@ void Font::print(const std::string &text, float x, float y, float extra_spacing,
indexBuffer = newIndexBuffer;
}
gl.matrices.transform.push(gl.matrices.transform.top());
Matrix t;
t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
gl.matrices.transform.top() *= t;
OpenGL::TempTransform transform(gl);
transform.get() *= t;
gl.enableVertexAttribArray(OpenGL::ATTRIB_POS);
gl.enableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
@@ -430,8 +427,6 @@ void Font::print(const std::string &text, float x, float y, float extra_spacing,
gl.disableVertexAttribArray(OpenGL::ATTRIB_POS);
gl.disableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
gl.matrices.transform.pop();
}
int Font::getWidth(const std::string &str)
+2 -2
View File
@@ -143,7 +143,7 @@ private:
enum FontType
{
FONT_TRUETYPE = 1,
FONT_TRUETYPE,
FONT_IMAGE,
FONT_UNKNOWN
};
@@ -184,7 +184,7 @@ private:
Glyph *addGlyph(uint32 glyph);
Glyph *findGlyph(uint32 glyph);
love::font::Rasterizer *rasterizer;
Object::StrongRef<love::font::Rasterizer> rasterizer;
VertexIndex *indexBuffer;
File diff suppressed because it is too large Load Diff
+70 -60
View File
@@ -57,48 +57,7 @@ namespace opengl
// During display mode changing, certain
// variables about the OpenGL context are
// lost.
struct DisplayState
{
// Colors.
Color color;
Color backgroundColor;
// Blend mode.
Graphics::BlendMode blendMode;
// Line.
Graphics::LineStyle lineStyle;
Graphics::LineJoin lineJoin;
// Point.
float pointSize;
Graphics::PointStyle pointStyle;
// Scissor.
bool scissor;
OpenGL::Viewport scissorBox;
// Color mask.
bool colorMask[4];
bool wireframe;
// Default values.
DisplayState()
{
color.set(255,255,255,255);
backgroundColor.set(0, 0, 0, 255);
blendMode = Graphics::BLEND_ALPHA;
lineStyle = Graphics::LINE_SMOOTH;
lineJoin = Graphics::LINE_JOIN_MITER;
pointSize = 1.0f;
pointStyle = Graphics::POINT_SMOOTH;
scissor = false;
colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true;
wireframe = false;
}
};
class Graphics : public love::graphics::Graphics
{
@@ -110,10 +69,6 @@ public:
// Implements Module.
const char *getName() const;
DisplayState saveState();
void restoreState(const DisplayState &s);
virtual void setViewportSize(int width, int height);
virtual bool setMode(int width, int height, bool &sRGB);
virtual void unSetMode();
@@ -211,7 +166,7 @@ public:
ParticleSystem *newParticleSystem(Texture *texture, int size);
Canvas *newCanvas(int width, int height, Canvas::Format format = Canvas::FORMAT_NORMAL, int fsaa = 0);
Canvas *newCanvas(int width, int height, Canvas::Format format = Canvas::FORMAT_NORMAL, int msaa = 0);
Shader *newShader(const Shader::ShaderSources &sources);
@@ -249,10 +204,22 @@ public:
**/
Font *getFont() const;
void setShader(Shader *shader);
void setShader();
Shader *getShader() const;
void setCanvas(Canvas *canvas);
void setCanvas(const std::vector<Canvas *> &canvases);
void setCanvas(const std::vector<Object::StrongRef<Canvas>> &canvases);
void setCanvas();
std::vector<Canvas *> getCanvas() const;
/**
* Sets the enabled color components when rendering.
**/
void setColorMask(bool r, bool g, bool b, bool a);
void setColorMask(const bool mask[4]);
/**
* Gets the current color mask.
@@ -447,20 +414,25 @@ public:
love::image::ImageData *newScreenshot(love::image::Image *image, bool copyAlpha = true);
/**
* Returns a string containing system-dependent renderer information.
* Returned string can vary greatly between systems! Do not rely on it for
* Returns system-dependent renderer information.
* Returned string s can vary greatly between systems! Do not rely on it for
* anything!
* @param infotype The type of information to return.
**/
std::string getRendererInfo(Graphics::RendererInfo infotype) const;
RendererInfo getRendererInfo() const;
/**
* Gets the system-dependent numeric limit for the specified parameter.
**/
double getSystemLimit(SystemLimit limittype) const;
void push();
/**
* Gets whether a graphics feature is supported on this system.
**/
bool isSupported(Support feature) const;
void push(StackType type = STACK_TRANSFORM);
void pop();
void rotate(float r);
void scale(float x, float y = 1.0f);
void translate(float x, float y);
@@ -469,16 +441,51 @@ public:
private:
Font *currentFont;
struct DisplayState
{
// Colors.
Color color;
Color backgroundColor;
// Blend mode.
BlendMode blendMode;
// Line.
float lineWidth;
LineStyle lineStyle;
LineJoin lineJoin;
// Point.
float pointSize;
PointStyle pointStyle;
// Scissor.
bool scissor;
OpenGL::Viewport scissorBox;
Object::StrongRef<Font> font;
Object::StrongRef<Shader> shader;
std::vector<Object::StrongRef<Canvas>> canvases;
// Color mask.
bool colorMask[4];
bool wireframe;
DisplayState();
DisplayState(const DisplayState &other);
~DisplayState();
DisplayState &operator = (const DisplayState &other);
};
void restoreState(const DisplayState &s);
void restoreStateChecked(const DisplayState &s);
love::window::Window *currentWindow;
std::vector<double> pixel_size_stack; // stores current size of a pixel (needed for line drawing)
LineStyle lineStyle;
LineJoin lineJoin;
float lineWidth;
size_t matrixLimit;
bool colorMask[4];
bool wireframe;
int width;
int height;
@@ -487,7 +494,10 @@ private:
bool activeStencil;
DisplayState savedState;
std::vector<DisplayState> states;
std::vector<StackType> stackTypes; // Keeps track of the pushed stack types.
static const size_t MAX_USER_STACK_DEPTH = 64;
}; // Graphics
+42 -29
View File
@@ -50,8 +50,6 @@ Image::Image(love::image::ImageData *data, Format format)
{
width = data->getWidth();
height = data->getHeight();
data->retain();
preload();
}
@@ -69,28 +67,22 @@ Image::Image(love::image::CompressedData *cdata, Format format)
{
width = cdata->getWidth(0);
height = cdata->getHeight(0);
cdata->retain();
preload();
}
Image::~Image()
{
if (data != nullptr)
data->release();
if (cdata != nullptr)
cdata->release();
unload();
}
love::image::ImageData *Image::getImageData() const
{
return data;
return data.get();
}
love::image::CompressedData *Image::getCompressedData() const
{
return cdata;
return cdata.get();
}
void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
@@ -140,7 +132,11 @@ GLuint Image::getGLTexture() const
void Image::uploadCompressedMipmaps()
{
if (!isCompressed() || !cdata || !hasCompressedTextureSupport(cdata->getFormat()))
if (!isCompressed() || !cdata.get() || !hasCompressedTextureSupport(cdata->getFormat()))
return;
// NPOT textures don't support mipmapping without full NPOT support.
if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
return;
bind();
@@ -175,7 +171,7 @@ void Image::uploadCompressedMipmaps()
void Image::createMipmaps()
{
// Only valid for Images created with ImageData.
if (!data || isCompressed())
if (!data.get() || isCompressed())
return;
if (!hasMipmapSupport())
@@ -222,6 +218,7 @@ void Image::createMipmaps()
GL_RGBA,
GL_UNSIGNED_BYTE,
data->getData());
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
}
}
@@ -230,9 +227,9 @@ void Image::checkMipmapsCreated()
if (mipmapsCreated || filter.mipmap == FILTER_NONE || usingDefaultTexture)
return;
if (isCompressed() && cdata && hasCompressedTextureSupport(cdata->getFormat()))
if (isCompressed() && cdata.get() && hasCompressedTextureSupport(cdata->getFormat()))
uploadCompressedMipmaps();
else if (data)
else if (data.get())
createMipmaps();
else
return;
@@ -251,17 +248,35 @@ void Image::setFilter(const Texture::Filter &f)
filter.min = filter.mag = FILTER_NEAREST;
}
if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
{
// If we only have limited NPOT support then mipmapping isn't supported.
filter.mipmap = FILTER_NONE;
}
bind();
gl.setTextureFilter(filter);
checkMipmapsCreated();
}
void Image::setWrap(const Texture::Wrap &w)
bool Image::setWrap(const Texture::Wrap &w)
{
bool success = true;
wrap = w;
if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
{
if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP)
success = false;
// If we only have limited NPOT support then the wrap mode must be CLAMP.
wrap.s = wrap.t = WRAP_CLAMP;
}
bind();
gl.setTextureWrap(w);
return success;
}
void Image::setMipmapSharpness(float sharpness)
@@ -333,7 +348,7 @@ bool Image::loadVolatile()
if (format == FORMAT_SRGB && !hasSRGBSupport())
throw love::Exception("sRGB images are not supported on this system.");
if (isCompressed() && cdata && !hasCompressedTextureSupport(cdata->getFormat()))
if (isCompressed() && cdata.get() && !hasCompressedTextureSupport(cdata->getFormat()))
{
const char *str;
if (image::CompressedData::getConstant(cdata->getFormat(), str))
@@ -351,8 +366,8 @@ bool Image::loadVolatile()
glGenTextures(1, &texture);
gl.bindTexture(texture);
filter.anisotropy = gl.setTextureFilter(filter);
gl.setTextureWrap(wrap);
setFilter(filter);
setWrap(wrap);
setMipmapSharpness(mipmapSharpness);
paddedWidth = width;
@@ -374,7 +389,7 @@ bool Image::loadVolatile()
// Mutex lock will potentially cover texture loading and mipmap creation.
love::thread::EmptyLock lock;
if (data)
if (data.get())
lock.setLock(data->getMutex());
while (glGetError() != GL_NO_ERROR); // Clear errors.
@@ -397,13 +412,13 @@ bool Image::loadVolatile()
void Image::uploadTexturePadded()
{
if (isCompressed() && cdata)
if (isCompressed() && cdata.get())
{
// Padded textures don't really work if they're compressed...
throw love::Exception("Cannot create image: "
"compressed NPOT images are not supported on this system.");
}
else if (data)
else if (data.get())
{
GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB_ALPHA : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D,
@@ -429,7 +444,7 @@ void Image::uploadTexturePadded()
void Image::uploadTexture()
{
if (isCompressed() && cdata)
if (isCompressed() && cdata.get())
{
GLenum format = getCompressedFormat(cdata->getFormat());
glCompressedTexImage2D(GL_TEXTURE_2D,
@@ -441,7 +456,7 @@ void Image::uploadTexture()
GLsizei(cdata->getSize(0)),
cdata->getData(0));
}
else if (data)
else if (data.get())
{
GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB_ALPHA : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D,
@@ -483,7 +498,7 @@ bool Image::refresh()
bind();
if (data && !isCompressed())
if (data.get() && !isCompressed())
lock.setLock(data->getMutex());
while (glGetError() != GL_NO_ERROR); // Clear errors.
@@ -525,10 +540,10 @@ void Image::uploadDefaultTexture()
void Image::drawv(const Matrix &t, const Vertex *v)
{
predraw();
OpenGL::TempTransform transform(gl);
transform.get() *= t;
gl.matrices.transform.push(gl.matrices.transform.top());
gl.matrices.transform.top() *= t;
predraw();
gl.prepareDraw();
@@ -543,8 +558,6 @@ void Image::drawv(const Matrix &t, const Vertex *v)
gl.disableVertexAttribArray(OpenGL::ATTRIB_POS);
gl.disableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
gl.matrices.transform.pop();
postdraw();
}
+3 -3
View File
@@ -102,7 +102,7 @@ public:
virtual GLuint getGLTexture() const;
virtual void setFilter(const Texture::Filter &f);
virtual void setWrap(const Texture::Wrap &w);
virtual bool setWrap(const Texture::Wrap &w);
void setMipmapSharpness(float sharpness);
float getMipmapSharpness() const;
@@ -155,11 +155,11 @@ private:
// The ImageData from which the texture is created. May be null if
// Compressed image data was used to create the texture.
love::image::ImageData *data;
Object::StrongRef<love::image::ImageData> data;
// Or the Compressed Image Data from which the texture is created. May be
// null if raw ImageData was used to create the texture.
love::image::CompressedData *cdata;
Object::StrongRef<love::image::CompressedData> cdata;
// Real dimensions of the texture, if it was auto-padded to POT size.
int paddedWidth, paddedHeight;
+37 -67
View File
@@ -39,7 +39,6 @@ Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
, ibo(nullptr)
, element_count(0)
, element_data_type(getGLDataTypeFromMax(verts.size()))
, instance_count(1)
, draw_mode(mode)
, range_min(-1)
, range_max(-1)
@@ -175,20 +174,7 @@ void Mesh::setVertexMap(const std::vector<uint32> &map)
GLenum datatype = getGLDataTypeFromMax(vertex_count);
// Calculate the size in bytes of the index buffer data.
size_t size = map.size();
switch (datatype)
{
case GL_UNSIGNED_BYTE:
size *= sizeof(uint8);
break;
case GL_UNSIGNED_SHORT:
size *= sizeof(uint16);
break;
case GL_UNSIGNED_INT:
default:
size *= sizeof(uint32);
break;
}
size_t size = map.size() * getGLDataTypeSize(datatype);
if (ibo && size > ibo->getSize())
{
@@ -232,10 +218,10 @@ void Mesh::setVertexMap(const std::vector<uint32> &map)
* Copies index data from a mapped buffer to a vector.
**/
template <typename T>
static void copyFromIndexBuffer(void *buffer, std::vector<uint32> &indices, size_t maxval)
static void copyFromIndexBuffer(void *buffer, size_t count, std::vector<uint32> &indices)
{
T *elems = (T *) buffer;
for (size_t i = 0; i < maxval; i++)
for (size_t i = 0; i < count; i++)
indices.push_back((uint32) elems[i]);
}
@@ -256,14 +242,14 @@ void Mesh::getVertexMap(std::vector<uint32> &map) const
switch (element_data_type)
{
case GL_UNSIGNED_BYTE:
copyFromIndexBuffer<uint8>(buffer, map, vertex_count);
copyFromIndexBuffer<uint8>(buffer, element_count, map);
break;
case GL_UNSIGNED_SHORT:
copyFromIndexBuffer<uint16>(buffer, map, vertex_count);
copyFromIndexBuffer<uint16>(buffer, element_count, map);
break;
case GL_UNSIGNED_INT:
default:
copyFromIndexBuffer<uint32>(buffer, map, vertex_count);
copyFromIndexBuffer<uint32>(buffer, element_count, map);
break;
}
}
@@ -273,37 +259,19 @@ size_t Mesh::getVertexMapCount() const
return element_count;
}
void Mesh::setInstanceCount(int count)
{
instance_count = std::max(count, 1);
}
int Mesh::getInstanceCount() const
{
return instance_count;
}
void Mesh::setTexture(Texture *tex)
{
tex->retain();
if (texture)
texture->release();
texture = tex;
texture.set(tex);
}
void Mesh::setTexture()
{
if (texture)
texture->release();
texture = nullptr;
texture.set(nullptr);
}
Texture *Mesh::getTexture() const
{
return texture;
return texture.get();
}
void Mesh::setDrawMode(Mesh::DrawMode mode)
@@ -355,7 +323,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
if (vertex_count == 0)
return;
if (texture)
if (texture.get())
texture->predraw();
else
gl.bindTexture(gl.getDefaultTexture());
@@ -363,8 +331,8 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
Matrix m;
m.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
gl.matrices.transform.push(gl.matrices.transform.top());
gl.matrices.transform.top() *= m;
OpenGL::TempTransform transform(gl);
transform.get() *= m;
VertexBuffer::Bind vbo_bind(*vbo);
@@ -398,35 +366,29 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
int max = element_count - 1;
if (range_max >= 0)
max = std::min(std::max(range_max, 0), (int) element_count - 1);
max = std::min(range_max, max);
int min = 0;
if (range_min >= 0)
min = std::min(std::max(range_min, 0), max);
min = std::min(range_min, max);
const void *indices = ibo->getPointer(min * sizeof(uint32));
GLenum type = element_data_type;
const void *indices = ibo->getPointer(min * getGLDataTypeSize(type));
if (instance_count > 1)
gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count);
else
glDrawElements(mode, max - min + 1, type, indices);
glDrawElements(mode, max - min + 1, type, indices);
}
else
{
int max = vertex_count - 1;
if (range_max >= 0)
max = std::min(std::max(range_max, 0), (int) vertex_count - 1);
max = std::min(range_max, max);
int min = 0;
if (range_min >= 0)
min = std::min(std::max(range_min, 0), max);
min = std::min(range_min, max);
// Normal non-indexed drawing (no custom vertex map.)
if (instance_count > 1)
gl.drawArraysInstanced(mode, min, max - min + 1, instance_count);
else
glDrawArrays(mode, min, max - min + 1);
glDrawArrays(mode, min, max - min + 1);
}
gl.disableVertexAttribArray(OpenGL::ATTRIB_POS);
@@ -439,9 +401,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
gl.setColor(gl.getColor());
}
gl.matrices.transform.pop();
if (texture)
if (texture.get())
texture->postdraw();
}
@@ -454,24 +414,34 @@ GLenum Mesh::getGLDrawMode(DrawMode mode) const
case DRAW_MODE_STRIP:
return GL_TRIANGLE_STRIP;
case DRAW_MODE_TRIANGLES:
default:
return GL_TRIANGLES;
case DRAW_MODE_POINTS:
return GL_POINTS;
default:
break;
}
return GL_TRIANGLES;
}
GLenum Mesh::getGLDataTypeFromMax(size_t maxvalue) const
{
if (maxvalue > LOVE_UINT16_MAX)
return GL_UNSIGNED_INT;
else if (maxvalue > LOVE_UINT8_MAX)
return GL_UNSIGNED_SHORT;
else
return GL_UNSIGNED_BYTE;
return GL_UNSIGNED_SHORT;
}
size_t Mesh::getGLDataTypeSize(GLenum datatype) const
{
switch (datatype)
{
case GL_UNSIGNED_BYTE:
return sizeof(uint8);
case GL_UNSIGNED_SHORT:
return sizeof(uint16);
case GL_UNSIGNED_INT:
return sizeof(uint32);
default:
return 0;
}
}
bool Mesh::getConstant(const char *in, Mesh::DrawMode &out)
+2 -12
View File
@@ -119,15 +119,6 @@ public:
**/
size_t getVertexMapCount() const;
/**
* Sets the number of instances of this Mesh to draw (uses hardware
* instancing when possible.)
* A custom vertex shader is necessary in order to introduce differences
* in each instance.
**/
void setInstanceCount(int count);
int getInstanceCount() const;
/**
* Sets the texture used when drawing the Mesh.
**/
@@ -171,6 +162,7 @@ private:
GLenum getGLDrawMode(DrawMode mode) const;
GLenum getGLDataTypeFromMax(size_t maxvalue) const;
size_t getGLDataTypeSize(GLenum datatype) const;
// Vertex buffer.
VertexBuffer *vbo;
@@ -181,14 +173,12 @@ private:
size_t element_count;
GLenum element_data_type;
int instance_count;
DrawMode draw_mode;
int range_min;
int range_max;
Texture *texture;
Object::StrongRef<Texture> texture;
// Whether the per-vertex colors are used when drawing.
bool colors_enabled;
+54 -16
View File
@@ -28,6 +28,7 @@
// C++
#include <algorithm>
#include <limits>
// C
#include <cstring>
@@ -47,6 +48,8 @@ OpenGL::OpenGL()
, vendor(VENDOR_UNKNOWN)
, state()
{
matrices.transform.reserve(10);
matrices.projection.reserve(2);
}
bool OpenGL::initContext()
@@ -135,6 +138,14 @@ bool OpenGL::initContext()
state.lastPseudoInstanceID = -1;
// Invalidate the cached matrices by setting some elements to NaN.
float nan = std::numeric_limits<float>::quiet_NaN();
state.lastProjectionMatrix.setTranslation(nan, nan);
state.lastTransformMatrix.setTranslation(nan, nan);
if (GLAD_VERSION_1_1)
glMatrixMode(GL_MODELVIEW);
contextInitialized = true;
return true;
}
@@ -234,14 +245,11 @@ void OpenGL::initMaxValues()
void OpenGL::initMatrices()
{
while (matrices.transform.size() > 0)
matrices.transform.pop();
matrices.transform.clear();
matrices.projection.clear();
while (matrices.projection.size() > 0)
matrices.projection.pop();
matrices.transform.push(Matrix());
matrices.projection.push(Matrix());
matrices.transform.push_back(Matrix());
matrices.projection.push_back(Matrix());
}
void OpenGL::createDefaultTexture()
@@ -268,10 +276,25 @@ void OpenGL::createDefaultTexture()
bindTexture(curtexture);
}
void OpenGL::pushTransform()
{
matrices.transform.push_back(matrices.transform.back());
}
void OpenGL::popTransform()
{
matrices.transform.pop_back();
}
Matrix &OpenGL::getTransform()
{
return matrices.transform.back();
}
void OpenGL::prepareDraw()
{
const Matrix &transform = matrices.transform.top();
const Matrix &proj = matrices.projection.top();
const Matrix &transform = matrices.transform.back();
const Matrix &proj = matrices.projection.back();
Shader *shader = Shader::current;
@@ -292,11 +315,10 @@ void OpenGL::prepareDraw()
// 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)
for (auto &r : shader->getBoundRetainables())
{
// Even bigger hack! D:
Canvas *canvas = dynamic_cast<Canvas *>(it->second);
Canvas *canvas = dynamic_cast<Canvas *>(r.second);
if (canvas != nullptr)
canvas->resolveMSAA();
}
@@ -315,10 +337,26 @@ void OpenGL::prepareDraw()
}
else if (GLAD_VERSION_1_0)
{
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(proj.getElements());
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(transform.getElements());
const float *lastproj = state.lastProjectionMatrix.getElements();
// We only need to re-upload the projection matrix if it's changed.
if (memcmp(proj.getElements(), lastproj, sizeof(float) * 16) != 0)
{
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(proj.getElements());
glMatrixMode(GL_MODELVIEW);
state.lastProjectionMatrix = proj;
}
const float *lastxform = state.lastTransformMatrix.getElements();
// Same with the transform matrix.
if (memcmp(transform.getElements(), lastxform, sizeof(float) * 16) != 0)
{
glLoadMatrixf(transform.getElements());
state.lastTransformMatrix = transform;
}
}
}
+35 -3
View File
@@ -21,6 +21,8 @@
#ifndef LOVE_GRAPHICS_OPENGL_OPENGL_H
#define LOVE_GRAPHICS_OPENGL_OPENGL_H
#include <stddef.h>
// LOVE
#include "graphics/Color.h"
#include "graphics/Texture.h"
@@ -115,13 +117,36 @@ public:
GLenum func;
};
// Transformation matrix stacks.
struct
{
std::stack<Matrix> transform;
std::stack<Matrix> projection;
std::vector<Matrix> transform;
std::vector<Matrix> projection;
} matrices;
class TempTransform
{
public:
TempTransform(OpenGL &gl)
: gl(gl)
{
gl.pushTransform();
}
~TempTransform()
{
gl.popTransform();
}
Matrix &get()
{
return gl.getTransform();
}
private:
OpenGL &gl;
};
OpenGL();
virtual ~OpenGL() {}
@@ -138,6 +163,10 @@ public:
**/
void deInitContext();
void pushTransform();
void popTransform();
Matrix &getTransform();
/**
* Set up necessary state (matrices etc.) for drawing. This *must* be called
* directly before GL draws.
@@ -360,6 +389,9 @@ private:
// The last ID value used for pseudo-instancing.
int lastPseudoInstanceID;
Matrix lastProjectionMatrix;
Matrix lastTransformMatrix;
} state;
}; // OpenGL
@@ -103,7 +103,6 @@ ParticleSystem::ParticleSystem(Texture *texture, uint32 size)
sizes.push_back(1.0f);
colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
setBufferSize(size);
texture->retain();
}
ParticleSystem::ParticleSystem(const ParticleSystem &p)
@@ -147,19 +146,14 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p)
, offsetX(p.offsetX)
, offsetY(p.offsetY)
, colors(p.colors)
, quads(p.quads)
, relativeRotation(p.relativeRotation)
{
setBufferSize(maxParticles);
if (texture != nullptr)
texture->retain();
}
ParticleSystem::~ParticleSystem()
{
if (texture != nullptr)
texture->release();
deleteBuffers();
}
@@ -315,6 +309,8 @@ void ParticleSystem::initParticle(Particle *p, float t)
p->angle += atan2f(p->velocity.y, p->velocity.x);
p->color = colors[0];
p->quadIndex = 0;
}
void ParticleSystem::insertTop(Particle *p)
@@ -423,19 +419,14 @@ ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p)
return pNext;
}
void ParticleSystem::setTexture(Texture *texture)
void ParticleSystem::setTexture(Texture *tex)
{
Object::AutoRelease imagerelease(this->texture);
this->texture = texture;
if (texture)
texture->retain();
texture.set(tex);
}
Texture *ParticleSystem::getTexture() const
{
return texture;
return texture.get();
}
void ParticleSystem::setInsertMode(InsertMode mode)
@@ -731,6 +722,33 @@ std::vector<Color> ParticleSystem::getColor() const
return ncolors;
}
void ParticleSystem::setQuads(const std::vector<Quad *> &newQuads)
{
std::vector<StrongRef<Quad>> quadlist;
quadlist.reserve(newQuads.size());
for (Quad *q : newQuads)
quadlist.push_back(q);
quads = quadlist;
}
void ParticleSystem::setQuads()
{
quads.clear();
}
std::vector<Quad *> ParticleSystem::getQuads() const
{
std::vector<Quad *> quadlist;
quadlist.reserve(quads.size());
for (const Object::StrongRef<Quad> &q : quads)
quadlist.push_back(q.get());
return quadlist;
}
void ParticleSystem::setRelativeRotation(bool enable)
{
relativeRotation = enable;
@@ -815,7 +833,7 @@ bool ParticleSystem::isFull() 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)
if (pCount == 0 || texture.get() == nullptr || pMem == nullptr || particleVerts == nullptr)
return;
Color curcolor = gl.getColor();
@@ -823,16 +841,21 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
gl.matrices.transform.push(gl.matrices.transform.top());
gl.matrices.transform.top() *= t;
OpenGL::TempTransform transform(gl);
transform.get() *= t;
const Vertex *textureVerts = texture->getVertices();
Vertex *pVerts = particleVerts;
Particle *p = pHead;
bool useQuads = !quads.empty();
// set the vertex data for each particle (transformation, texcoords, color)
while (p)
{
if (useQuads)
textureVerts = quads[p->quadIndex]->getVertices();
// particle vertices are image vertices transformed by particle information
t.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
t.transform(pVerts, textureVerts, 4);
@@ -876,8 +899,6 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
texture->postdraw();
gl.matrices.transform.pop();
gl.setColor(curcolor);
}
@@ -961,6 +982,15 @@ void ParticleSystem::update(float dt)
s -= (float)i; // 0 <= s <= 1
p->color = colors[i] * (1.0f - s) + colors[k] * s;
// Update the quad index.
k = quads.size();
if (k > 0)
{
s = t * (float) k; // [0:numquads-1] (clamped below)
i = (s > 0.0f) ? (size_t) s : 0;
p->quadIndex = (i < k) ? i : k - 1;
}
// Next particle.
p = p->next;
}
@@ -28,6 +28,7 @@
#include "graphics/Drawable.h"
#include "graphics/Color.h"
#include "VertexBuffer.h"
#include "graphics/Quad.h"
#include "Texture.h"
// STL
@@ -422,6 +423,17 @@ public:
**/
std::vector<Color> getColor() const;
/**
* Sets a list of Quads to use for particles over their lifetime.
**/
void setQuads(const std::vector<Quad *> &newQuads);
void setQuads();
/**
* Gets the Quads used when drawing the particles.
**/
std::vector<Quad *> getQuads() const;
/**
* sets whether particle angles & rotations are relative to their velocities.
**/
@@ -532,6 +544,8 @@ protected:
float spinEnd;
Colorf color;
int quadIndex;
};
// Pointer to the beginning of the allocated memory.
@@ -553,7 +567,7 @@ protected:
VertexIndex *ibo;
// The texture to be drawn.
Texture *texture;
Object::StrongRef<Texture> texture;
// Whether the particle emitter is active.
bool active;
@@ -629,6 +643,9 @@ protected:
// Color.
std::vector<Colorf> colors;
// Quads.
std::vector<Object::StrongRef<Quad>> quads;
bool relativeRotation;
void createBuffers(size_t size);
@@ -18,14 +18,14 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
#include <algorithm>
// LOVE
#include "Polyline.h"
// OpenGL
#include "OpenGL.h"
#include <algorithm>
// treat adjacent segments with angles between their directions <5 degree as straight
static const float LINES_PARALLEL_EPS = 0.05f;
@@ -36,6 +36,16 @@ namespace graphics
namespace opengl
{
Polyline::Polyline(GLenum mode, bool quadindices)
: vertices(nullptr)
, overdraw(nullptr)
, vertex_count(0)
, overdraw_vertex_count(0)
, draw_mode(mode)
, use_quad_indices(quadindices)
{
}
void Polyline::render(const float *coords, size_t count, size_t size_hint, float halfwidth, float pixel_size, bool draw_overdraw)
{
static std::vector<Vector> anchors;
@@ -327,13 +337,43 @@ Polyline::~Polyline()
void Polyline::draw()
{
GLushort *indices = nullptr;
if (use_quad_indices)
{
size_t numindices = (vertex_count / 4) * 6;
if (overdraw)
numindices = std::max(numindices, (overdraw_vertex_count / 4) * 6);
indices = new GLushort[numindices];
// Fill the index array to make the draw call render 2 triangles from
// a 4-vertex quad.
for (size_t i = 0; i < numindices / 6; i++)
{
// First triangle: vertices 0-1-2.
indices[i * 6 + 0] = GLushort(i * 4 + 0);
indices[i * 6 + 1] = GLushort(i * 4 + 1);
indices[i * 6 + 2] = GLushort(i * 4 + 2);
// Second triangle: vertices 0-2-3.
indices[i * 6 + 3] = GLushort(i * 4 + 0);
indices[i * 6 + 4] = GLushort(i * 4 + 2);
indices[i * 6 + 5] = GLushort(i * 4 + 3);
}
}
gl.prepareDraw();
// draw the core line
gl.bindTexture(gl.getDefaultTexture());
gl.enableVertexAttribArray(OpenGL::ATTRIB_POS);
gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, 0, (GLvoid *) vertices);
glDrawArrays(draw_mode, 0, vertex_count);
gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, 0, vertices);
if (use_quad_indices)
glDrawElements(draw_mode, (vertex_count / 4) * 6, GL_UNSIGNED_SHORT, indices);
else
glDrawArrays(draw_mode, 0, vertex_count);
if (overdraw)
{
@@ -344,10 +384,13 @@ void Polyline::draw()
gl.enableVertexAttribArray(OpenGL::ATTRIB_COLOR);
gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, 0, (GLvoid *) overdraw);
gl.setVertexAttribArray(OpenGL::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 0, (GLvoid *) colors);
gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, 0, overdraw);
gl.setVertexAttribArray(OpenGL::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, 0, colors);
glDrawArrays(draw_mode, 0, overdraw_vertex_count);
if (use_quad_indices)
glDrawElements(draw_mode, (overdraw_vertex_count / 4) * 6, GL_UNSIGNED_SHORT, indices);
else
glDrawArrays(draw_mode, 0, overdraw_vertex_count);
gl.disableVertexAttribArray(OpenGL::ATTRIB_COLOR);
gl.setColor(c);
@@ -356,6 +399,8 @@ void Polyline::draw()
}
gl.disableVertexAttribArray(OpenGL::ATTRIB_POS);
delete[] indices;
}
void Polyline::fill_color_array(Color *colors, const Color &c)
@@ -24,6 +24,7 @@
#include <vector>
// LOVE
#include "common/config.h"
#include "common/Vector.h"
// OpenGL
@@ -43,13 +44,8 @@ namespace opengl
class Polyline
{
public:
Polyline(GLenum mode = GL_TRIANGLE_STRIP)
: vertices(NULL)
, overdraw(NULL)
, vertex_count(0)
, overdraw_vertex_count(0)
, draw_mode(mode)
{}
Polyline(GLenum mode = GL_TRIANGLE_STRIP, bool quadindices = false);
virtual ~Polyline();
/**
@@ -90,6 +86,7 @@ protected:
size_t vertex_count;
size_t overdraw_vertex_count;
GLenum draw_mode;
bool use_quad_indices;
}; // Polyline
@@ -102,8 +99,8 @@ class NoneJoinPolyline : public Polyline
{
public:
NoneJoinPolyline()
// TODO: replace GL_QUADS (indexed triangles?)
: Polyline(GL_QUADS)
// Draw quads using GL_TRIANGLES and a vertex index array.
: Polyline(GL_TRIANGLES, true)
{}
void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw)
+18 -19
View File
@@ -100,8 +100,8 @@ Shader::~Shader()
if (current == this)
detach();
for (auto it = boundRetainables.begin(); it != boundRetainables.end(); ++it)
it->second->release();
for (const auto &retainable : boundRetainables)
retainable.second->release();
boundRetainables.clear();
@@ -181,9 +181,8 @@ void Shader::createProgram(const std::vector<GLuint> &shaderids)
if (program == 0)
throw love::Exception("Cannot create shader program object.");
std::vector<GLuint>::const_iterator it;
for (it = shaderids.begin(); it != shaderids.end(); ++it)
glAttachShader(program, *it);
for (GLuint id : shaderids)
glAttachShader(program, id);
// Bind generic vertex attribute indices to names in the shader.
for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++)
@@ -208,8 +207,8 @@ void Shader::createProgram(const std::vector<GLuint> &shaderids)
glLinkProgram(program);
// flag shaders for auto-deletion when the program object is deleted.
for (it = shaderids.begin(); it != shaderids.end(); ++it)
glDeleteShader(*it);
for (GLuint id : shaderids)
glDeleteShader(id);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
@@ -272,6 +271,10 @@ void Shader::mapActiveUniforms()
bool Shader::loadVolatile()
{
// Creating the shader will invalidate the uniforms that rely on these.
lastCanvas = (Canvas *) -1;
lastViewport = OpenGL::Viewport();
// zero out active texture list
activeTexUnits.clear();
activeTexUnits.insert(activeTexUnits.begin(), maxTexUnits, 0);
@@ -282,10 +285,9 @@ bool Shader::loadVolatile()
std::vector<GLuint> shaderids;
ShaderSources::const_iterator source;
for (source = shaderSources.begin(); source != shaderSources.end(); ++source)
for (const auto &source : shaderSources)
{
GLuint shaderid = compileCode(source->first, source->second);
GLuint shaderid = compileCode(source.first, source.second);
shaderids.push_back(shaderid);
}
@@ -294,7 +296,7 @@ bool Shader::loadVolatile()
{
ShaderSources &defaults = defaultCode[Graphics::RENDERER_OPENGLES];
source = shaderSources.find(TYPE_VERTEX);
ShaderSources::const_iterator source = shaderSources.find(TYPE_VERTEX);
if (source == shaderSources.end())
shaderids.push_back(compileCode(TYPE_VERTEX, defaults[TYPE_VERTEX]));
@@ -325,6 +327,7 @@ bool Shader::loadVolatile()
// make sure glUseProgram gets called.
current = nullptr;
attach();
checkSetScreenParams();
}
return true;
@@ -385,11 +388,10 @@ std::string Shader::getWarnings() const
const char *typestr;
// Get the individual shader stage warnings
std::map<ShaderType, std::string>::const_iterator it;
for (it = shaderWarnings.begin(); it != shaderWarnings.end(); ++it)
for (const auto &warning : shaderWarnings)
{
if (typeNames.find(it->first, typestr))
warnings += std::string(typestr) + std::string(" shader:\n") + it->second;
if (typeNames.find(warning.first, typestr))
warnings += std::string(typestr) + std::string(" shader:\n") + warning.second;
}
warnings += getProgramWarnings();
@@ -403,12 +405,9 @@ void Shader::attach(bool temporary)
if (oldshader != this)
{
glUseProgram(program);
current = this;
current->retain();
if (oldshader != nullptr)
oldshader->release();
// retain/release happens in Graphics::setShader.
}
if (!temporary)
@@ -46,8 +46,10 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, int usage)
, size(size)
, next(0)
, color(0)
, array_buf(0)
, element_buf(0)
, array_buf(nullptr)
, element_buf(nullptr)
, buffer_used_offset(0)
, buffer_used_size(0)
{
if (size <= 0)
throw love::Exception("Invalid SpriteBatch size.");
@@ -86,14 +88,10 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, int usage)
delete element_buf;
throw love::Exception("Out of memory.");
}
texture->retain();
}
SpriteBatch::~SpriteBatch()
{
texture->release();
delete color;
delete array_buf;
delete element_buf;
@@ -160,31 +158,22 @@ void SpriteBatch::clear()
next = 0;
}
void *SpriteBatch::lock()
void SpriteBatch::flush()
{
VertexBuffer::Bind bind(*array_buf);
array_buf->unmap(buffer_used_offset, buffer_used_size);
return array_buf->map();
}
void SpriteBatch::unlock()
{
VertexBuffer::Bind bind(*array_buf);
array_buf->unmap();
buffer_used_offset = buffer_used_size = 0;
}
void SpriteBatch::setTexture(Texture *newtexture)
{
Object::AutoRelease imagerelease(texture);
newtexture->retain();
texture = newtexture;
texture.set(newtexture);
}
Texture *SpriteBatch::getTexture()
{
return texture;
return texture.get();
}
void SpriteBatch::setColor(const Color &color)
@@ -220,33 +209,31 @@ void SpriteBatch::setBufferSize(int newsize)
return;
// Map (lock) the old VertexBuffer to get a pointer to its data.
void *old_data = lock();
void *old_data = nullptr;
{
VertexBuffer::Bind bind(*array_buf);
old_data = array_buf->map();
}
size_t vertex_size = sizeof(Vertex) * 4 * newsize;
VertexBuffer *new_array_buf = 0;
VertexIndex *new_element_buf = 0;
void *new_data = 0;
VertexBuffer *new_array_buf = nullptr;
VertexIndex *new_element_buf = nullptr;
try
{
new_array_buf = VertexBuffer::Create(vertex_size, array_buf->getTarget(), array_buf->getUsage());
new_element_buf = new VertexIndex(newsize);
// VBO::map can throw an exception. Also we want to scope the bind.
VertexBuffer::Bind bind(*new_array_buf);
new_data = new_array_buf->map();
}
catch (love::Exception &)
{
delete new_array_buf;
delete new_element_buf;
unlock();
throw;
}
// Copy as much of the old data into the new VertexBuffer as can fit.
memcpy(new_data, old_data, sizeof(Vertex) * 4 * std::min(newsize, size));
new_array_buf->fill(0, sizeof(Vertex) * 4 * std::min(newsize, size), old_data);
// We don't need to unmap the old VertexBuffer since we're deleting it.
delete array_buf;
@@ -258,8 +245,8 @@ void SpriteBatch::setBufferSize(int newsize)
next = std::min(next, newsize);
// But we should unmap (unlock) the new one!
unlock();
// The new VertexBuffer isn't mapped, so we should reset these variables.
buffer_used_offset = buffer_used_size = 0;
}
int SpriteBatch::getBufferSize() const
@@ -269,29 +256,27 @@ int SpriteBatch::getBufferSize() 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 pos_offset = offsetof(Vertex, x);
const size_t texel_offset = offsetof(Vertex, s);
const size_t color_offset = offsetof(Vertex, r);
if (next == 0)
return;
Matrix t;
static Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
gl.matrices.transform.push(gl.matrices.transform.top());
gl.matrices.transform.top() *= t;
OpenGL::TempTransform transform(gl);
transform.get() *= t;
texture->predraw();
VertexBuffer::Bind array_bind(*array_buf);
VertexBuffer::Bind element_bind(*element_buf->getVertexBuffer());
gl.enableVertexAttribArray(OpenGL::ATTRIB_POS);
gl.enableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, sizeof(Vertex), array_buf->getPointer(vertex_offset));
gl.setVertexAttribArray(OpenGL::ATTRIB_TEXCOORD, 2, GL_FLOAT, sizeof(Vertex), array_buf->getPointer(texel_offset));
// Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.)
array_buf->unmap(buffer_used_offset, buffer_used_size);
buffer_used_offset = buffer_used_size = 0;
Color curcolor = gl.getColor();
@@ -302,6 +287,12 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
gl.setVertexAttribArray(OpenGL::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, sizeof(Vertex), array_buf->getPointer(color_offset));
}
gl.enableVertexAttribArray(OpenGL::ATTRIB_POS);
gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, sizeof(Vertex), array_buf->getPointer(pos_offset));
gl.enableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
gl.setVertexAttribArray(OpenGL::ATTRIB_TEXCOORD, 2, GL_FLOAT, sizeof(Vertex), array_buf->getPointer(texel_offset));
gl.prepareDraw();
glDrawElements(GL_TRIANGLES, element_buf->getIndexCount(next), element_buf->getType(), element_buf->getPointer(0));
@@ -315,15 +306,22 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
}
texture->postdraw();
gl.matrices.transform.pop();
}
void SpriteBatch::addv(const Vertex *v, int index)
{
static const int sprite_size = 4 * sizeof(Vertex); // bytecount
static const size_t sprite_size = 4 * sizeof(Vertex); // bytecount
VertexBuffer::Bind bind(*array_buf);
// Always keep the VBO mapped when adding data for now (it'll be unmapped
// on draw.)
array_buf->map();
array_buf->fill(index * sprite_size, sprite_size, v);
buffer_used_offset = std::min(buffer_used_offset, index * sprite_size);
buffer_used_size = std::max(buffer_used_size, (index + 1) * sprite_size - buffer_used_offset);
}
void SpriteBatch::setColorv(Vertex *v, const Color &color)
@@ -52,7 +52,7 @@ public:
enum UsageHint
{
USAGE_DYNAMIC = 1,
USAGE_DYNAMIC,
USAGE_STATIC,
USAGE_STREAM,
USAGE_MAX_ENUM
@@ -65,8 +65,7 @@ public:
int addq(Quad *quad, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index = -1);
void clear();
void *lock();
void unlock();
void flush();
void setTexture(Texture *newtexture);
Texture *getTexture();
@@ -127,7 +126,7 @@ private:
*/
void setColorv(Vertex *v, const Color &color);
Texture *texture;
Object::StrongRef<Texture> texture;
// Max number of sprites in the batch.
int size;
@@ -142,6 +141,10 @@ private:
VertexBuffer *array_buf;
VertexIndex *element_buf;
// The portion of the vertex buffer that's been modified while mapped.
size_t buffer_used_offset;
size_t buffer_used_size;
static StringMap<UsageHint, USAGE_MAX_ENUM>::Entry usageHintEntries[];
static StringMap<UsageHint, USAGE_MAX_ENUM> usageHints;
@@ -55,6 +55,14 @@ public:
**/
virtual void postdraw() {}
/**
* Unextended OpenGL ES 2 doesn't support non-clamp wrap modes or mipmapping
* with non-power-of-two textures.
**/
static bool hasLimitedNpot()
{
return GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot);
}
}; // Texture
@@ -21,7 +21,6 @@
#include "VertexBuffer.h"
#include "common/Exception.h"
#include "common/config.h"
#include <cstdlib>
#include <cstring>
@@ -89,7 +88,7 @@ void *VertexArray::map()
return buf;
}
void VertexArray::unmap()
void VertexArray::unmap(size_t /*usedOffset*/, size_t /*usedSize*/)
{
is_mapped = false;
}
@@ -121,7 +120,7 @@ VBO::VBO(size_t size, GLenum target, GLenum usage, MemoryBacking backing)
// ES2 can't do glGetBufferSubData.
: VertexBuffer(size, target, usage, GLAD_ES_VERSION_2_0 ? BACKING_FULL : backing)
, vbo(0)
, memory_map(0)
, memory_map(nullptr)
, is_dirty(false)
{
if (!(GLAD_ARB_vertex_buffer_object || GLAD_VERSION_1_5 || GLAD_ES_VERSION_2_0))
@@ -133,7 +132,7 @@ VBO::VBO(size_t size, GLenum target, GLenum usage, MemoryBacking backing)
backing = BACKING_FULL;
if (getMemoryBacking() == BACKING_FULL)
memory_map = malloc(getSize());
memory_map = (char *) malloc(getSize());
bool ok = load(false);
@@ -160,7 +159,7 @@ void *VBO::map()
if (!memory_map)
{
memory_map = malloc(getSize());
memory_map = (char * ) malloc(getSize());
if (!memory_map)
throw love::Exception("Out of memory (oh the humanity!)");
}
@@ -176,11 +175,28 @@ void *VBO::map()
return memory_map;
}
void VBO::unmap()
void VBO::unmapStatic(size_t offset, size_t size)
{
// Upload the mapped data to the buffer.
glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, memory_map + offset);
}
void VBO::unmapStream()
{
// "orphan" current buffer to avoid implicit synchronisation on the GPU:
// http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf
glBufferData(getTarget(), (GLsizeiptr) getSize(), nullptr, getUsage());
glBufferData(getTarget(), (GLsizeiptr) getSize(), memory_map, getUsage());
}
void VBO::unmap(size_t usedOffset, size_t usedSize)
{
if (!is_mapped)
return;
usedOffset = std::min(usedOffset, getSize());
usedSize = std::min(usedSize, getSize() - usedOffset);
// VBO::bind is a no-op when the VBO is mapped, so we have to make sure it's
// bound here.
if (!is_bound)
@@ -189,17 +205,23 @@ void VBO::unmap()
is_bound = true;
}
if (getUsage() == GL_STATIC_DRAW)
switch (getUsage())
{
// Upload the mapped data to the buffer.
glBufferSubData(getTarget(), 0, (GLsizeiptr) getSize(), memory_map);
}
else
{
// "orphan" current buffer to avoid implicit synchronisation on the GPU:
// http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf
glBufferData(getTarget(), (GLsizeiptr) getSize(), NULL, getUsage());
glBufferData(getTarget(), (GLsizeiptr) getSize(), memory_map, getUsage());
case GL_STATIC_DRAW:
unmapStatic(usedOffset, usedSize);
break;
case GL_STREAM_DRAW:
unmapStream();
break;
case GL_DYNAMIC_DRAW:
default:
// It's probably more efficient to treat it like a streaming buffer if
// more than a third of its contents have been modified during the map().
if (usedSize >= getSize() / 3)
unmapStream();
else
unmapStatic(usedOffset, usedSize);
break;
}
is_mapped = false;
@@ -225,31 +247,11 @@ void VBO::unbind()
void VBO::fill(size_t offset, size_t size, const void *data)
{
if (is_mapped || getMemoryBacking() == BACKING_FULL)
memcpy(static_cast<char *>(memory_map) + offset, data, size);
memcpy(memory_map + offset, data, size);
if (!is_mapped)
{
// Not all systems have access to some faster paths...
if (GLAD_APPLE_flush_buffer_range)
{
void *mapdata = glMapBuffer(getTarget(), GL_WRITE_ONLY);
if (mapdata)
{
// We specified in VBO::load that we'll do manual flushing.
// Now we tell the driver it only needs to deal with the data
// we changed.
memcpy(static_cast<char *>(mapdata) + offset, data, size);
glFlushMappedBufferRangeAPPLE(getTarget(), (GLintptr) offset, (GLsizei) size);
}
glUnmapBuffer(getTarget());
}
else
{
// Fall back to a possibly slower SubData (more chance of syncing.)
glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, data);
}
glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, data);
if (getMemoryBacking() != BACKING_FULL)
is_dirty = true;
@@ -278,17 +280,11 @@ bool VBO::load(bool restore)
VertexBuffer::Bind bind(*this);
// Copy the old buffer only if 'restore' was requested.
const GLvoid *src = restore ? memory_map : 0;
const GLvoid *src = restore ? memory_map : nullptr;
while (GL_NO_ERROR != glGetError())
/* clear error messages */;
// We don't want to flush the entire buffer when we just modify a small
// portion of it (VBO::fill without VBO::map), so we'll handle the flushing
// ourselves when we can.
if (GLAD_APPLE_flush_buffer_range)
glBufferParameteriAPPLE(getTarget(), GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
// Note that if 'src' is '0', no data will be copied.
glBufferData(getTarget(), (GLsizeiptr) getSize(), src, getUsage());
GLenum err = glGetError();
@@ -302,13 +298,11 @@ void VBO::unload(bool save)
if (save && getMemoryBacking() == BACKING_PARTIAL)
{
VertexBuffer::Bind bind(*this);
bool mapped = is_mapped;
map(); // saves buffer content to memory_map.
is_mapped = mapped;
}
is_mapped = false;
glDeleteBuffers(1, &vbo);
vbo = 0;
}
@@ -23,11 +23,15 @@
#define LOVE_GRAPHICS_OPENGL_VERTEX_BUFFER_H
// LOVE
#include "common/config.h"
#include "graphics/Volatile.h"
// OpenGL
#include "OpenGL.h"
// C
#include <stddef.h>
namespace love
{
namespace graphics
@@ -152,8 +156,12 @@ public:
* when used to draw elements.
*
* The VertexBuffer must be bound to use this function.
*
* @param usedOffset The offset into the mapped buffer indicating the
* sub-range of data modified. Optional.
* @param usedSize The size of the sub-range of modified data. Optional.
*/
virtual void unmap() = 0;
virtual void unmap(size_t usedOffset = 0, size_t usedSize = -1) = 0;
/**
* Bind the VertexBuffer to its specified target.
@@ -294,7 +302,7 @@ public:
// Implements VertexBuffer.
virtual void *map();
virtual void unmap();
virtual void unmap(size_t usedOffset = 0, size_t usedSize = -1);
virtual void bind();
virtual void unbind();
virtual void fill(size_t offset, size_t size, const void *data);
@@ -328,7 +336,7 @@ public:
// Implements VertexBuffer.
virtual void *map();
virtual void unmap();
virtual void unmap(size_t usedOffset = 0, size_t usedSize = -1);
virtual void bind();
virtual void unbind();
virtual void fill(size_t offset, size_t size, const void *data);
@@ -355,12 +363,15 @@ private:
*/
void unload(bool save);
void unmapStatic(size_t offset, size_t size);
void unmapStream();
// The VBO identifier. Assigned by OpenGL.
GLuint vbo;
// A pointer to mapped memory. Will be inialized on the first
// call to map().
void *memory_map;
char *memory_map;
// Set if the buffer was modified while operating on gpu memory
// and needs to be synchronized.
@@ -19,6 +19,7 @@
**/
#include "wrap_Canvas.h"
#include "Graphics.h"
namespace love
{
@@ -37,18 +38,26 @@ int w_Canvas_renderTo(lua_State *L)
Canvas *canvas = luax_checkcanvas(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION);
// Save the current Canvas so we can restore it when we're done.
Canvas *oldcanvas = Canvas::current;
Graphics *graphics = Module::getInstance<Graphics>(Module::M_GRAPHICS);
EXCEPT_GUARD(canvas->startGrab();)
if (graphics)
{
// Save the current Canvas so we can restore it when we're done.
std::vector<Canvas *> oldcanvases = graphics->getCanvas();
lua_settop(L, 2); // make sure the function is on top of the stack
lua_call(L, 0, 0);
for (Canvas *c : oldcanvases)
c->retain();
if (oldcanvas != nullptr)
oldcanvas->startGrab(oldcanvas->getAttachedCanvases());
else
Canvas::bindDefaultCanvas();
luax_catchexcept(L, [&](){ graphics->setCanvas(canvas); });
lua_settop(L, 2); // make sure the function is on top of the stack
lua_call(L, 0, 0);
graphics->setCanvas(oldcanvases);
for (Canvas *c : oldcanvases)
c->release();
}
return 0;
}
@@ -59,6 +68,7 @@ int w_Canvas_getImageData(lua_State *L)
love::image::Image *image = luax_getmodule<love::image::Image>(L, "image", MODULE_IMAGE_T);
love::image::ImageData *img = canvas->getImageData(image);
luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, img);
img->release();
return 1;
}
@@ -69,7 +79,7 @@ int w_Canvas_getPixel(lua_State * L)
int y = luaL_checkint(L, 3);
unsigned char c[4];
EXCEPT_GUARD(canvas->getPixel(c, x, y);)
luax_catchexcept(L, [&](){ canvas->getPixel(c, x, y); });
lua_pushnumber(L, c[0]);
lua_pushnumber(L, c[1]);
@@ -122,10 +132,10 @@ int w_Canvas_getFormat(lua_State *L)
return 1;
}
int w_Canvas_getFSAA(lua_State *L)
int w_Canvas_getMSAA(lua_State *L)
{
Canvas *canvas = luax_checkcanvas(L, 1);
lua_pushinteger(L, canvas->getFSAA());
lua_pushinteger(L, canvas->getMSAA());
return 1;
}
@@ -145,10 +155,14 @@ static const luaL_Reg functions[] =
{ "getPixel", w_Canvas_getPixel },
{ "clear", w_Canvas_clear },
{ "getFormat", w_Canvas_getFormat },
{ "getFSAA", w_Canvas_getFSAA },
{ "getMSAA", w_Canvas_getMSAA },
// Deprecated since 0.9.1.
{ "getType", w_Canvas_getFormat },
// Deprecated since 0.9.2.
{ "getFSAA", w_Canvas_getMSAA },
{ 0, 0 }
};
@@ -40,7 +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_getFormat(lua_State *L);
int w_Canvas_getFSAA(lua_State *L);
int w_Canvas_getMSAA(lua_State *L);
extern "C" int luaopen_canvas(lua_State *L);
} // opengl
@@ -45,7 +45,7 @@ int w_Font_getWidth(lua_State *L)
Font *t = luax_checkfont(L, 1);
const char *str = luaL_checkstring(L, 2);
EXCEPT_GUARD(lua_pushinteger(L, t->getWidth(str));)
luax_catchexcept(L, [&](){ lua_pushinteger(L, t->getWidth(str)); });
return 1;
}
@@ -56,10 +56,10 @@ int w_Font_getWrap(lua_State *L)
float wrap = (float) luaL_checknumber(L, 3);
int max_width = 0, numlines = 0;
EXCEPT_GUARD(
luax_catchexcept(L, [&]() {
std::vector<std::string> lines = t->getWrap(str, wrap, &max_width);
numlines = lines.size();
)
});
lua_pushinteger(L, max_width);
lua_pushinteger(L, numlines);
@@ -96,7 +96,7 @@ int w_Font_setFilter(lua_State *L)
f.anisotropy = (float) luaL_optnumber(L, 4, 1.0);
EXCEPT_GUARD(t->setFilter(f);)
luax_catchexcept(L, [&](){ t->setFilter(f); });
return 0;
}
@@ -143,7 +143,7 @@ int w_Font_hasGlyphs(lua_State *L)
int count = lua_gettop(L) - 1;
count = count < 1 ? 1 : count;
EXCEPT_GUARD(
luax_catchexcept(L, [&]() {
for (int i = 2; i < count + 2; i++)
{
if (lua_type(L, i) == LUA_TSTRING)
@@ -154,7 +154,7 @@ int w_Font_hasGlyphs(lua_State *L)
if (!hasglyph)
break;
}
)
});
luax_pushboolean(L, hasglyph);
return 1;
File diff suppressed because it is too large Load Diff
@@ -95,7 +95,8 @@ int w_setShader(lua_State *L);
int w_getShader(lua_State *L);
int w_setDefaultShaderCode(lua_State *L);
int w_isSupported(lua_State *L);
int w_hasCanvasFormat(lua_State *L);
int w_getCanvasFormats(lua_State *L);
int w_getCompressedImageFormats(lua_State *L);
int w_getRendererInfo(lua_State *L);
int w_getSystemLimit(lua_State *L);
int w_draw(lua_State *L);
@@ -47,7 +47,7 @@ int w_Image_setMipmapFilter(lua_State *L)
return luaL_error(L, "Invalid filter mode: %s", mipmapstr);
}
EXCEPT_GUARD(t->setFilter(f);)
luax_catchexcept(L, [&](){ t->setFilter(f); });
float sharpness = (float) luaL_optnumber(L, 3, 0);
t->setMipmapSharpness(sharpness);
@@ -81,7 +81,7 @@ int w_Image_isCompressed(lua_State *L)
int w_Image_refresh(lua_State *L)
{
Image *i = luax_checkimage(L, 1);
EXCEPT_GUARD(i->refresh();)
luax_catchexcept(L, [&](){ i->refresh(); });
return 0;
}
@@ -93,10 +93,7 @@ int w_Image_getData(lua_State *L)
{
love::image::CompressedData *t = i->getCompressedData();
if (t)
{
t->retain();
luax_pushtype(L, "CompressedData", IMAGE_COMPRESSED_DATA_T, t);
}
else
lua_pushnil(L);
}
@@ -104,10 +101,7 @@ int w_Image_getData(lua_State *L)
{
love::image::ImageData *t = i->getImageData();
if (t)
{
t->retain();
luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, t);
}
else
lua_pushnil(L);
}
@@ -74,7 +74,7 @@ int w_Mesh_setVertex(lua_State *L)
v.a = luaL_optinteger(L, 10, 255);
}
EXCEPT_GUARD(t->setVertex(i, v);)
luax_catchexcept(L, [&](){ t->setVertex(i, v); });
return 0;
}
@@ -84,7 +84,7 @@ int w_Mesh_getVertex(lua_State *L)
size_t i = (size_t) (luaL_checkinteger(L, 2) - 1);
Vertex v;
EXCEPT_GUARD(v = t->getVertex(i);)
luax_catchexcept(L, [&](){ v = t->getVertex(i); });
lua_pushnumber(L, v.x);
lua_pushnumber(L, v.y);
@@ -134,7 +134,7 @@ int w_Mesh_setVertices(lua_State *L)
vertices.push_back(v);
}
EXCEPT_GUARD(t->setVertices(vertices);)
luax_catchexcept(L, [&](){ t->setVertices(vertices); });
return 0;
}
@@ -216,7 +216,7 @@ int w_Mesh_setVertexMap(lua_State *L)
vertexmap.push_back(uint32(luaL_checkinteger(L, i + 2) - 1));
}
EXCEPT_GUARD(t->setVertexMap(vertexmap);)
luax_catchexcept(L, [&](){ t->setVertexMap(vertexmap); });
return 0;
}
@@ -225,7 +225,7 @@ int w_Mesh_getVertexMap(lua_State *L)
Mesh *t = luax_checkmesh(L, 1);
std::vector<uint32> vertex_map;
EXCEPT_GUARD(t->getVertexMap(vertex_map);)
luax_catchexcept(L, [&](){ t->getVertexMap(vertex_map); });
size_t element_count = vertex_map.size();
@@ -240,20 +240,6 @@ int w_Mesh_getVertexMap(lua_State *L)
return 1;
}
int w_Mesh_setInstanceCount(lua_State *L)
{
Mesh *t = luax_checkmesh(L, 1);
t->setInstanceCount(luaL_checkint(L, 2));
return 0;
}
int w_Mesh_getInstanceCount(lua_State *L)
{
Mesh *t = luax_checkmesh(L, 1);
lua_pushinteger(L, t->getInstanceCount());
return 1;
}
int w_Mesh_setTexture(lua_State *L)
{
Mesh *t = luax_checkmesh(L, 1);
@@ -277,18 +263,13 @@ int w_Mesh_getTexture(lua_State *L)
if (tex == nullptr)
return 0;
tex->retain();
// FIXME: big hack right here.
if (typeid(*tex) == typeid(Image))
luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, tex);
else if (typeid(*tex) == typeid(Canvas))
luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, tex);
else
{
tex->release();
return luaL_error(L, "Unable to determine texture type.");
}
return 1;
}
@@ -329,7 +310,7 @@ int w_Mesh_setDrawRange(lua_State *L)
{
int rangemin = luaL_checkint(L, 2) - 1;
int rangemax = luaL_checkint(L, 3) - 1;
EXCEPT_GUARD(t->setDrawRange(rangemin, rangemax);)
luax_catchexcept(L, [&](){ t->setDrawRange(rangemin, rangemax); });
}
return 0;
@@ -374,12 +355,6 @@ static const luaL_Reg functions[] =
{ "getVertexCount", w_Mesh_getVertexCount },
{ "setVertexMap", w_Mesh_setVertexMap },
{ "getVertexMap", w_Mesh_getVertexMap },
// Disabled for now, since implementation is incomplete and might change
// if/when VertexBuffers / custom vertex attributes are added.
// { "setInstanceCount", w_Mesh_setInstanceCount },
// { "getInstanceCount", w_Mesh_getInstanceCount },
{ "setTexture", w_Mesh_setTexture },
{ "getTexture", w_Mesh_getTexture },
{ "setDrawMode", w_Mesh_setDrawMode },
@@ -41,8 +41,6 @@ int w_Mesh_getVertices(lua_State *L);
int w_Mesh_getVertexCount(lua_State *L);
int w_Mesh_setVertexMap(lua_State *L);
int w_Mesh_getVertexMap(lua_State *L);
int w_Mesh_setInstanceCount(lua_State *L);
int w_Mesh_getInstanceCount(lua_State *L);
int w_Mesh_setTexture(lua_State *L);
int w_Mesh_getTexture(lua_State *L);
int w_Mesh_setDrawMode(lua_State *L);
@@ -49,9 +49,10 @@ int w_ParticleSystem_clone(lua_State *L)
ParticleSystem *t = luax_checkparticlesystem(L, 1);
ParticleSystem *clone = nullptr;
EXCEPT_GUARD(clone = t->clone();)
luax_catchexcept(L, [&](){ clone = t->clone(); });
luax_pushtype(L, "ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_T, clone);
clone->release();
return 1;
}
@@ -67,7 +68,6 @@ int w_ParticleSystem_getTexture(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
Texture *tex = t->getTexture();
tex->retain();
// FIXME: big hack right here.
if (typeid(*tex) == typeid(Image))
@@ -75,10 +75,7 @@ int w_ParticleSystem_getTexture(lua_State *L)
else if (typeid(*tex) == typeid(Canvas))
luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, tex);
else
{
tex->release();
return luaL_error(L, "Unable to determine texture type.");
}
return 1;
}
@@ -90,7 +87,7 @@ int w_ParticleSystem_setBufferSize(lua_State *L)
if (arg1 < 1.0 || arg1 > ParticleSystem::MAX_PARTICLES)
return luaL_error(L, "Invalid buffer size");
EXCEPT_GUARD(t->setBufferSize((uint32) arg1);)
luax_catchexcept(L, [&](){ t->setBufferSize((uint32) arg1); });
return 0;
}
@@ -128,7 +125,7 @@ int w_ParticleSystem_setEmissionRate(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
float arg1 = (float) luaL_checknumber(L, 2);
EXCEPT_GUARD(t->setEmissionRate(arg1);)
luax_catchexcept(L, [&](){ t->setEmissionRate(arg1); });
return 0;
}
@@ -569,6 +566,52 @@ int w_ParticleSystem_getColors(lua_State *L)
return colors.size();
}
int w_ParticleSystem_setQuads(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
std::vector<Quad *> quads;
if (lua_istable(L, 2))
{
for (size_t i = 1; i <= lua_objlen(L, 2); i++)
{
lua_rawgeti(L, 2, i);
Quad *q = luax_checktype<Quad>(L, -1, "Quad", GRAPHICS_QUAD_T);
quads.push_back(q);
lua_pop(L, 1);
}
}
else
{
for (int i = 2; i <= lua_gettop(L); i++)
{
Quad *q = luax_checktype<Quad>(L, i, "Quad", GRAPHICS_QUAD_T);
quads.push_back(q);
}
}
t->setQuads(quads);
return 0;
}
int w_ParticleSystem_getQuads(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
const std::vector<Quad *> quads = t->getQuads();
lua_createtable(L, (int) quads.size(), 0);
for (size_t i = 0; i < quads.size(); i++)
{
luax_pushtype(L, "Quad", GRAPHICS_QUAD_T, quads[i]);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
int w_ParticleSystem_setRelativeRotation(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
@@ -699,6 +742,8 @@ static const luaL_Reg functions[] =
{ "getSpinVariation", w_ParticleSystem_getSpinVariation },
{ "setColors", w_ParticleSystem_setColors },
{ "getColors", w_ParticleSystem_getColors },
{ "setQuads", w_ParticleSystem_setQuads },
{ "getQuads", w_ParticleSystem_getQuads },
{ "setOffset", w_ParticleSystem_setOffset },
{ "getOffset", w_ParticleSystem_getOffset },
{ "setRelativeRotation", w_ParticleSystem_setRelativeRotation },
@@ -75,6 +75,8 @@ int w_ParticleSystem_setSpinVariation(lua_State *L);
int w_ParticleSystem_getSpinVariation(lua_State *L);
int w_ParticleSystem_setColors(lua_State *L);
int w_ParticleSystem_getColors(lua_State *L);
int w_ParticleSystem_setQuads(lua_State *L);
int w_ParticleSystem_getQuads(lua_State *L);
int w_ParticleSystem_setOffset(lua_State *L);
int w_ParticleSystem_getOffset(lua_State *L);
int w_ParticleSystem_setRelativeRotation(lua_State *L);
@@ -232,22 +232,10 @@ int w_Shader_sendMatrix(lua_State *L)
lua_pop(L, 1 + dimension);
}
bool should_error = false;
try
{
shader->sendMatrix(name, dimension, values, count);
}
catch(love::Exception &e)
{
should_error = true;
lua_pushstring(L, e.what());
}
delete[] values;
if (should_error)
return luaL_error(L, "%s", lua_tostring(L, -1));
luax_catchexcept(L,
[&]() { shader->sendMatrix(name, dimension, values, count); },
[&]() { delete[] values; }
);
return 0;
}
@@ -258,7 +246,7 @@ int w_Shader_sendTexture(lua_State *L)
const char *name = luaL_checkstring(L, 2);
Texture *texture = luax_checktexture(L, 3);
EXCEPT_GUARD(shader->sendTexture(name, texture);)
luax_catchexcept(L, [&](){ shader->sendTexture(name, texture); });
return 0;
}
@@ -64,12 +64,12 @@ int w_SpriteBatch_add(lua_State *L)
float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
int id = 0;
EXCEPT_GUARD(
luax_catchexcept(L, [&]() {
if (quad)
id = t->addq(quad, x, y, a, sx, sy, ox, oy, kx, ky);
else
id = t->add(x, y, a, sx, sy, ox, oy, kx, ky);
)
});
lua_pushinteger(L, id);
return 1;
@@ -101,12 +101,12 @@ int w_SpriteBatch_set(lua_State *L)
float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
EXCEPT_GUARD(
luax_catchexcept(L, [&]() {
if (quad)
t->addq(quad, x, y, a, sx, sy, ox, oy, kx, ky, id);
else
t->add(x, y, a, sx, sy, ox, oy, kx, ky, id);
)
});
return 0;
}
@@ -118,17 +118,16 @@ int w_SpriteBatch_clear(lua_State *L)
return 0;
}
int w_SpriteBatch_bind(lua_State *L)
int w_SpriteBatch_bind(lua_State* /*L*/)
{
SpriteBatch *t = luax_checkspritebatch(L, 1);
EXCEPT_GUARD(t->lock();)
// No-op (deprecated.)
return 0;
}
int w_SpriteBatch_unbind(lua_State *L)
int w_SpriteBatch_flush(lua_State *L)
{
SpriteBatch *t = luax_checkspritebatch(L, 1);
t->unlock();
t->flush();
return 0;
}
@@ -144,7 +143,6 @@ int w_SpriteBatch_getTexture(lua_State *L)
{
SpriteBatch *t = luax_checkspritebatch(L, 1);
Texture *tex = t->getTexture();
tex->retain();
// FIXME: big hack right here.
if (typeid(*tex) == typeid(Image))
@@ -152,10 +150,7 @@ int w_SpriteBatch_getTexture(lua_State *L)
else if (typeid(*tex) == typeid(Canvas))
luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, tex);
else
{
tex->release();
return luaL_error(L, "Unable to determine texture type.");
}
return 1;
}
@@ -223,7 +218,7 @@ int w_SpriteBatch_setBufferSize(lua_State *L)
{
SpriteBatch *t = luax_checkspritebatch(L, 1);
int size = luaL_checkint(L, 2);
EXCEPT_GUARD(t->setBufferSize(size);)
luax_catchexcept(L, [&]() {t->setBufferSize(size); });
return 0;
}
@@ -239,8 +234,7 @@ static const luaL_Reg functions[] =
{ "add", w_SpriteBatch_add },
{ "set", w_SpriteBatch_set },
{ "clear", w_SpriteBatch_clear },
{ "bind", w_SpriteBatch_bind },
{ "unbind", w_SpriteBatch_unbind },
{ "flush", w_SpriteBatch_flush },
{ "setTexture", w_SpriteBatch_setTexture },
{ "getTexture", w_SpriteBatch_getTexture },
{ "setColor", w_SpriteBatch_setColor },
@@ -252,6 +246,11 @@ static const luaL_Reg functions[] =
// Deprecated since 0.9.1.
{ "setImage", w_SpriteBatch_setTexture },
{ "getImage", w_SpriteBatch_getTexture },
// Deprecated since 0.9.2.
{ "bind", w_SpriteBatch_bind },
{ "unbind", w_SpriteBatch_flush },
{ 0, 0 }
};
@@ -38,7 +38,7 @@ int w_SpriteBatch_set(lua_State *L);
int w_SpriteBatch_setg(lua_State *L);
int w_SpriteBatch_clear(lua_State *L);
int w_SpriteBatch_bind(lua_State *L);
int w_SpriteBatch_unbind(lua_State *L);
int w_SpriteBatch_flush(lua_State *L);
int w_SpriteBatch_setTexture(lua_State *L);
int w_SpriteBatch_getTexture(lua_State *L);
int w_SpriteBatch_setColor(lua_State *L);
@@ -69,7 +69,7 @@ int w_Texture_setFilter(lua_State *L)
f.anisotropy = (float) luaL_optnumber(L, 4, 1.0);
EXCEPT_GUARD(t->setFilter(f);)
luax_catchexcept(L, [&](){ t->setFilter(f); });
return 0;
}
@@ -105,8 +105,8 @@ int w_Texture_setWrap(lua_State *L)
if (!Texture::getConstant(tstr, w.t))
return luaL_error(L, "Invalid wrap mode, %s", tstr);
t->setWrap(w);
return 0;
luax_pushboolean(L, t->setWrap(w));
return 1;
}
int w_Texture_getWrap(lua_State *L)