mirror of
https://github.com/love2d/love-android.git
synced 2026-08-20 04:31:26 +02:00
updated to latest mobile-common (0cf55b7da58e), removed libtiff, libpng, libmng, devil, jasper, jpeg-8d, added libturbo-jpeg
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ≷
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user