From 809ea8691f19b9a62a8e30290dcb8a9d6c62819a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 4 Aug 2014 22:02:47 -0300 Subject: [PATCH 1/6] Fixed wireframe mode not being saved and restored properly on love.window.setMode. --- src/modules/graphics/opengl/Graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 151d48da7..fecc889ba 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -105,7 +105,7 @@ DisplayState Graphics::saveState() for (int i = 0; i < 4; i++) s.colorMask[i] = colorMask[i]; - wireframe = isWireframe(); + s.wireframe = isWireframe(); return s; } From 028108ea6438484374e4a79dec2df275d474c4eb Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 6 Aug 2014 20:16:15 -0300 Subject: [PATCH 2/6] Improved the error message when physfs fails to open a filepath. --- src/modules/filesystem/physfs/File.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 95eafa800..be137c4b0 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -69,23 +69,36 @@ bool File::open(Mode mode) if (file != 0) return false; - this->mode = mode; + PHYSFS_getLastError(); // Clear the error buffer. + PHYSFS_File *handle = nullptr; switch (mode) { case READ: - file = PHYSFS_openRead(filename.c_str()); + handle = PHYSFS_openRead(filename.c_str()); break; case APPEND: - file = PHYSFS_openAppend(filename.c_str()); + handle = PHYSFS_openAppend(filename.c_str()); break; case WRITE: - file = PHYSFS_openWrite(filename.c_str()); + handle = PHYSFS_openWrite(filename.c_str()); break; default: break; } + if (handle == nullptr) + { + const char *err = PHYSFS_getLastError(); + if (err == nullptr) + err = "unknown error"; + throw love::Exception("Could not open file %s (%s)", filename.c_str(), err); + } + + file = handle; + + this->mode = mode; + if (file != 0 && !setBuffer(bufferMode, bufferSize)) { // Revert to buffer defaults if we don't successfully set the buffer. From afc505e183036f436291f930f3d3a7a757a20a07 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Wed, 6 Aug 2014 22:25:29 -0300 Subject: [PATCH 3/6] Added stack type enums to love.graphics.push (resolves issue #906.) Current enums are "transform" and "all". "transform" is the default (for compatibility.) When love.graphics.push("all") is used, love.graphics.pop() will restore all love.graphics module state to what it was when push was called. Updated the graphics code to use a custom matrix stack rather than OpenGL1's APIs. --- src/common/Matrix.cpp | 14 + src/common/Matrix.h | 6 + src/modules/graphics/Graphics.cpp | 18 + src/modules/graphics/Graphics.h | 13 + src/modules/graphics/opengl/Canvas.cpp | 42 +- src/modules/graphics/opengl/Canvas.h | 1 - src/modules/graphics/opengl/Font.cpp | 8 +- src/modules/graphics/opengl/Graphics.cpp | 668 ++++++++++++------ src/modules/graphics/opengl/Graphics.h | 115 +-- src/modules/graphics/opengl/Image.cpp | 9 +- src/modules/graphics/opengl/Mesh.cpp | 6 +- src/modules/graphics/opengl/OpenGL.cpp | 63 +- src/modules/graphics/opengl/OpenGL.h | 40 ++ .../graphics/opengl/ParticleSystem.cpp | 8 +- src/modules/graphics/opengl/Shader.cpp | 31 +- src/modules/graphics/opengl/SpriteBatch.cpp | 9 +- src/modules/graphics/opengl/wrap_Canvas.cpp | 27 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 63 +- 18 files changed, 726 insertions(+), 415 deletions(-) diff --git a/src/common/Matrix.cpp b/src/common/Matrix.cpp index a8a8c5e68..d403e8b02 100644 --- a/src/common/Matrix.cpp +++ b/src/common/Matrix.cpp @@ -194,5 +194,19 @@ void Matrix::transform(Vertex *dst, const Vertex *src, int size) const } } +Matrix Matrix::ortho(float left, float right, float bottom, float top) +{ + Matrix m; + + m.e[0] = 2.0f / (right - left); + m.e[5] = 2.0f / (top - bottom); + m.e[10] = -1.0; + + m.e[12] = -(right + left) / (right - left); + m.e[13] = -(top + bottom) / (top - bottom); + + return m; +} + } // love diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 2a0091448..0e33b37d9 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -150,6 +150,12 @@ public: **/ void transform(Vertex *dst, const Vertex *src, int size) const; + /** + * Creates a new orthographic projection matrix with depth in the range of + * [-1, 1]. + **/ + static Matrix ortho(float left, float right, float bottom, float top); + private: /** diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 5688e5650..d6e16cd37 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -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::Entry Graphics::drawModeEntries[] = { { "line", Graphics::DRAW_LINE }, @@ -192,5 +202,13 @@ StringMap::Entry Graphics::syst StringMap Graphics::systemLimits(Graphics::systemLimitEntries, sizeof(Graphics::systemLimitEntries)); +StringMap::Entry Graphics::stackTypeEntries[] = +{ + {"all", Graphics::STACK_ALL}, + {"transform", Graphics::STACK_TRANSFORM}, +}; + +StringMap Graphics::stackTypes(Graphics::stackTypeEntries, sizeof(Graphics::stackTypeEntries)); + } // graphics } // love diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index ed66de5d2..8cdeb68d2 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -112,6 +112,13 @@ public: LIMIT_MAX_ENUM }; + enum StackType + { + STACK_ALL, + STACK_TRANSFORM, + STACK_MAX_ENUM + }; + struct RendererInfo { std::string name; @@ -167,6 +174,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::Entry drawModeEntries[]; @@ -193,6 +203,9 @@ private: static StringMap::Entry systemLimitEntries[]; static StringMap systemLimits; + static StringMap::Entry stackTypeEntries[]; + static StringMap stackTypes; + }; // Graphics } // graphics diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 854dd938e..e6739d695 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -594,16 +594,13 @@ void Canvas::unloadVolatile() fbo = depth_stencil = texture = 0; resolve_fbo = msaa_buffer = 0; - for (size_t i = 0; i < attachedCanvases.size(); i++) - attachedCanvases[i]->release(); - attachedCanvases.clear(); } void Canvas::drawv(const Matrix &t, const Vertex *v) { - glPushMatrix(); - glMultMatrixf((const GLfloat *)t.getElements()); + OpenGL::TempTransform transform(gl); + transform.get() *= t; predraw(); @@ -620,8 +617,6 @@ void Canvas::drawv(const Matrix &t, const Vertex *v) glDisableClientState(GL_VERTEX_ARRAY); postdraw(); - - glPopMatrix(); } void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) @@ -691,16 +686,8 @@ void Canvas::setupGrab() strategy->bindFBO(fbo); gl.setViewport(OpenGL::Viewport(0, 0, width, height)); - // Reset the projection matrix - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - // Set up orthographic view (no depth) - glOrtho(0.0, width, 0.0, height, -1.0, 1.0); - - // Switch back to modelview matrix - glMatrixMode(GL_MODELVIEW); + // 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 (format == FORMAT_SRGB) @@ -754,11 +741,8 @@ void Canvas::startGrab(const std::vector &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; } @@ -773,10 +757,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(); } @@ -786,9 +766,7 @@ void Canvas::stopGrab(bool switchingToOtherCanvas) if (current != this) return; - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + gl.matrices.projection.pop_back(); if (switchingToOtherCanvas) { @@ -1123,12 +1101,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); diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index d12d5ed42..a0fd6f1a1 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -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; diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 5cb062cb3..578c8e465 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -368,11 +368,11 @@ void Font::print(const std::string &text, float x, float y, float extra_spacing, // second (using the struct's < operator). std::sort(glyphinfolist.begin(), glyphinfolist.end()); - glPushMatrix(); - Matrix t; t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky); - glMultMatrixf((const GLfloat *)t.getElements()); + + OpenGL::TempTransform transform(gl); + transform.get() *= t; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -393,8 +393,6 @@ void Font::print(const std::string &text, float x, float y, float extra_spacing, glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - - glPopMatrix(); } int Font::getWidth(const std::string &str) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index fecc889ba..735d5852a 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -44,19 +44,14 @@ namespace opengl { Graphics::Graphics() - : currentFont(0) - , lineStyle(LINE_SMOOTH) - , lineJoin(LINE_JOIN_MITER) - , lineWidth(1) - , matrixLimit(0) - , userMatrices(0) - , colorMask() - , width(0) + : width(0) , height(0) , created(false) , activeStencil(false) - , savedState() { + states.reserve(10); + states.push_back(DisplayState()); + currentWindow = love::window::sdl::Window::createSingleton(); int w, h; @@ -70,8 +65,8 @@ Graphics::Graphics() Graphics::~Graphics() { - if (currentFont != 0) - currentFont->release(); + // We do this manually so the love objects get released before the window. + states.clear(); currentWindow->release(); } @@ -81,53 +76,90 @@ const char *Graphics::getName() const return "love.graphics.opengl"; } -DisplayState Graphics::saveState() -{ - DisplayState s; - - s.color = getColor(); - s.backgroundColor = getBackgroundColor(); - - s.blendMode = getBlendMode(); - //get line style - s.lineStyle = getLineStyle(); - s.lineJoin = getLineJoin(); - //get the point size - glGetFloatv(GL_POINT_SIZE, &s.pointSize); - //get point style - s.pointStyle = (glIsEnabled(GL_POINT_SMOOTH) == GL_TRUE) ? Graphics::POINT_SMOOTH : Graphics::POINT_ROUGH; - //get scissor status - s.scissor = (glIsEnabled(GL_SCISSOR_TEST) == GL_TRUE); - //do we have scissor, if so, store the box - if (s.scissor) - s.scissorBox = gl.getScissor(); - - for (int i = 0; i < 4; i++) - s.colorMask[i] = colorMask[i]; - - s.wireframe = isWireframe(); - - return s; -} - void Graphics::restoreState(const DisplayState &s) { setColor(s.color); setBackgroundColor(s.backgroundColor); + setBlendMode(s.blendMode); - setLineWidth(lineWidth); + + setLineWidth(s.lineWidth); setLineStyle(s.lineStyle); setLineJoin(s.lineJoin); + setPointSize(s.pointSize); setPointStyle(s.pointStyle); + if (s.scissor) setScissor(s.scissorBox.x, s.scissorBox.y, s.scissorBox.w, s.scissorBox.h); else setScissor(); - setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]); + + setFont(s.font); + setShader(s.shader); + setCanvas(s.canvases); + + setColorMask(s.colorMask); setWireframe(s.wireframe); } +void Graphics::restoreStateChecked(const DisplayState &s) +{ + const DisplayState &cur = states.back(); + + if (*(uint32 *) &s.color.r != *(uint32 *) &cur.color.r) + setColor(s.color); + + if (*(uint32 *) &s.backgroundColor.r != *(uint32 *) &cur.backgroundColor.r) + setBackgroundColor(s.backgroundColor); + + if (s.blendMode != cur.blendMode) + setBlendMode(s.blendMode); + + // These are just simple assignments. + setLineWidth(s.lineWidth); + setLineStyle(s.lineStyle); + setLineJoin(s.lineJoin); + + if (s.pointSize != cur.pointSize) + setPointSize(s.pointSize); + + if (s.pointStyle != cur.pointStyle) + setPointStyle(s.pointStyle); + + if (s.scissor != cur.scissor || (s.scissor && !(s.scissorBox == cur.scissorBox))) + { + if (s.scissor) + setScissor(s.scissorBox.x, s.scissorBox.y, s.scissorBox.w, s.scissorBox.h); + else + setScissor(); + } + + setFont(s.font); + setShader(s.shader); + + for (size_t i = 0; i < s.canvases.size() && i < cur.canvases.size(); i++) + { + if (s.canvases[i] != cur.canvases[i]) + { + setCanvas(s.canvases); + break; + } + } + + for (int i = 0; i < 4; i++) + { + if (s.colorMask[i] != cur.colorMask[i]) + { + setColorMask(s.colorMask); + break; + } + } + + if (s.wireframe != cur.wireframe) + setWireframe(s.wireframe); +} + void Graphics::setViewportSize(int width, int height) { this->width = width; @@ -138,8 +170,8 @@ void Graphics::setViewportSize(int width, int height) // We want to affect the main screen, not any Canvas that's currently active // (not that any *should* be active when this is called.) - Canvas *c = Canvas::current; - Canvas::bindDefaultCanvas(); + std::vector canvases = getCanvas(); + setCanvas(); // Set the viewport to top-left corner. gl.setViewport(OpenGL::Viewport(0, 0, width, height)); @@ -148,18 +180,11 @@ void Graphics::setViewportSize(int width, int height) // made aware of the new system viewport size. Canvas::systemViewport = gl.getViewport(); - // Reset the projection matrix - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // Set up orthographic view (no depth) - glOrtho(0.0, width, height, 0.0, -1.0, 1.0); - - glMatrixMode(GL_MODELVIEW); + // Set up the projection matrix + gl.matrices.projection.back() = Matrix::ortho(0.0, width, height, 0.0); // Restore the previously active Canvas. - if (c != nullptr) - c->startGrab(c->getAttachedCanvases()); + setCanvas(canvases); } bool Graphics::setMode(int width, int height, bool &sRGB) @@ -182,7 +207,8 @@ bool Graphics::setMode(int width, int height, bool &sRGB) glEnable(GL_BLEND); // Enable all color component writes. - setColorMask(true, true, true, true); + bool colormask[] = {true, true, true, true}; + setColorMask(colormask); // Enable line/point smoothing. setLineStyle(LINE_SMOOTH); @@ -197,28 +223,9 @@ bool Graphics::setMode(int width, int height, bool &sRGB) glEnable(GL_TEXTURE_2D); gl.setTextureUnit(0); - // Reset modelview matrix - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - // Set pixel row alignment glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // Reload all volatile objects. - if (!Volatile::loadAll()) - std::cerr << "Could not reload all volatile objects." << std::endl; - - // Restore the display state. - restoreState(savedState); - pixel_size_stack.clear(); - pixel_size_stack.reserve(5); - pixel_size_stack.push_back(1); - - // Get the maximum number of matrices - // subtract a few to give the engine some room. - glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &matrixLimit); - matrixLimit -= 5; - // Set whether drawing converts input from linear -> sRGB colorspace. if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_sRGB || GLEE_EXT_framebuffer_sRGB) { @@ -244,6 +251,17 @@ bool Graphics::setMode(int width, int height, bool &sRGB) setDebug(enabledebug); + // Reload all volatile objects. + if (!Volatile::loadAll()) + std::cerr << "Could not reload all volatile objects." << std::endl; + + // Restore the graphics state. + restoreState(states.back()); + + pixel_size_stack.clear(); + pixel_size_stack.reserve(5); + pixel_size_stack.push_back(1); + return true; } @@ -252,9 +270,6 @@ void Graphics::unSetMode() if (!isCreated()) return; - // Window re-creation may destroy the GL context, so we must save the state. - savedState = saveState(); - // Unload all volatile objects. These must be reloaded after the display // mode change. Volatile::unloadAll(); @@ -323,8 +338,6 @@ void Graphics::reset() { DisplayState s; discardStencil(); - Canvas::bindDefaultCanvas(); - Shader::detach(); origin(); restoreState(s); } @@ -356,13 +369,18 @@ bool Graphics::isCreated() const void Graphics::setScissor(int x, int y, int width, int height) { + OpenGL::Viewport box(x, y, width, height); + + states.back().scissor = true; glEnable(GL_SCISSOR_TEST); // OpenGL's reversed y-coordinate is compensated for in OpenGL::setScissor. - gl.setScissor(OpenGL::Viewport(x, y, width, height)); + gl.setScissor(box); + states.back().scissorBox = box; } void Graphics::setScissor() { + states.back().scissor = false; glDisable(GL_SCISSOR_TEST); } @@ -375,7 +393,7 @@ bool Graphics::getScissor(int &x, int &y, int &width, int &height) const width = scissor.w; height = scissor.h; - return glIsEnabled(GL_SCISSOR_TEST) == GL_TRUE; + return states.back().scissor; } void Graphics::defineStencil() @@ -399,7 +417,7 @@ void Graphics::useStencil(bool invert) { glStencilFunc(GL_EQUAL, (GLint)(!invert), 1); // invert ? 0 : 1 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - setColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); + setColorMask(states.back().colorMask); } void Graphics::discardStencil() @@ -407,7 +425,7 @@ void Graphics::discardStencil() if (!activeStencil) return; - setColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); + setColorMask(states.back().colorMask); glDisable(GL_STENCIL_TEST); activeStencil = false; } @@ -566,65 +584,160 @@ Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode mode) void Graphics::setColor(const Color &c) { gl.setColor(c); + states.back().color = c; } Color Graphics::getColor() const { - return gl.getColor(); + return states.back().color; } void Graphics::setBackgroundColor(const Color &c) { gl.setClearColor(c); + states.back().backgroundColor = c; } Color Graphics::getBackgroundColor() const { - return gl.getClearColor(); + return states.back().backgroundColor; } void Graphics::setFont(Font *font) { - Object::AutoRelease fontrelease(currentFont); + DisplayState &state = states.back(); - currentFont = font; + if (font != nullptr) + font->retain(); - if (font != 0) - currentFont->retain(); + if (state.font != nullptr) + state.font->release(); + + state.font = font; } Font *Graphics::getFont() const { - return currentFont; + return states.back().font; } -void Graphics::setColorMask(bool r, bool g, bool b, bool a) +void Graphics::setShader(Shader *shader) { - colorMask[0] = r; - colorMask[1] = g; - colorMask[2] = b; - colorMask[3] = a; + if (shader == nullptr) + return setShader(); - glColorMask((GLboolean) r, (GLboolean) g, (GLboolean) b, (GLboolean) a); + DisplayState &state = states.back(); + + shader->attach(); + + if (shader) + shader->retain(); + + if (state.shader) + state.shader->release(); + + state.shader = shader; +} + +void Graphics::setShader() +{ + DisplayState &state = states.back(); + + Shader::detach(); + + if (state.shader) + state.shader->release(); + + state.shader = nullptr; +} + +Shader *Graphics::getShader() const +{ + return states.back().shader; +} + +void Graphics::setCanvas(Canvas *canvas) +{ + if (canvas == nullptr) + return setCanvas(); + + DisplayState &state = states.back(); + + canvas->startGrab(); + + canvas->retain(); + + for (Canvas *c : state.canvases) + c->release(); + + state.canvases.clear(); + state.canvases.push_back(canvas); +} + +void Graphics::setCanvas(const std::vector &canvases) +{ + if (canvases.size() == 0) + return setCanvas(); + else if (canvases.size() == 1) + return setCanvas(canvases[0]); + + DisplayState &state = states.back(); + + auto attachments = std::vector(canvases.begin() + 1, canvases.end()); + canvases[0]->startGrab(attachments); + + for (Canvas *c : canvases) + c->retain(); + + for (Canvas *c : state.canvases) + c->release(); + + state.canvases = canvases; +} + +void Graphics::setCanvas() +{ + DisplayState &state = states.back(); + + if (Canvas::current != nullptr) + Canvas::current->stopGrab(); + + for (Canvas *c : state.canvases) + c->release(); + + state.canvases.clear(); +} + +std::vector Graphics::getCanvas() const +{ + return states.back().canvases; +} + +void Graphics::setColorMask(const bool mask[4]) +{ + for (int i = 0; i < 4; i++) + states.back().colorMask[i] = mask[i]; + + glColorMask(mask[0], mask[1], mask[2], mask[3]); } const bool *Graphics::getColorMask() const { - return colorMask; + return states.back().colorMask; } void Graphics::setBlendMode(Graphics::BlendMode mode) { - OpenGL::BlendState state = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD}; + OpenGL::BlendState blend = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD}; switch (mode) { case BLEND_ALPHA: if (GLEE_VERSION_1_4 || GLEE_EXT_blend_func_separate) { - state.srcRGB = GL_SRC_ALPHA; - state.srcA = GL_ONE; - state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA; + blend.srcRGB = GL_SRC_ALPHA; + blend.srcA = GL_ONE; + blend.dstRGB = blend.dstA = GL_ONE_MINUS_SRC_ALPHA; } else { @@ -632,65 +745,42 @@ void Graphics::setBlendMode(Graphics::BlendMode mode) // This will most likely only be used for the Microsoft software renderer and // since it's still stuck with OpenGL 1.1, the only expected difference is a // different alpha value when reading back the default framebuffer (newScreenshot). - state.srcRGB = state.srcA = GL_SRC_ALPHA; - state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA; + blend.srcRGB = blend.srcA = GL_SRC_ALPHA; + blend.dstRGB = blend.dstA = GL_ONE_MINUS_SRC_ALPHA; } break; case BLEND_MULTIPLICATIVE: - state.srcRGB = state.srcA = GL_DST_COLOR; - state.dstRGB = state.dstA = GL_ZERO; + blend.srcRGB = blend.srcA = GL_DST_COLOR; + blend.dstRGB = blend.dstA = GL_ZERO; break; case BLEND_PREMULTIPLIED: - state.srcRGB = state.srcA = GL_ONE; - state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA; + blend.srcRGB = blend.srcA = GL_ONE; + blend.dstRGB = blend.dstA = GL_ONE_MINUS_SRC_ALPHA; break; case BLEND_SUBTRACTIVE: - state.func = GL_FUNC_REVERSE_SUBTRACT; + blend.func = GL_FUNC_REVERSE_SUBTRACT; case BLEND_ADDITIVE: - state.srcRGB = state.srcA = GL_SRC_ALPHA; - state.dstRGB = state.dstA = GL_ONE; + blend.srcRGB = blend.srcA = GL_SRC_ALPHA; + blend.dstRGB = blend.dstA = GL_ONE; break; case BLEND_SCREEN: - state.srcRGB = state.srcA = GL_ONE; - state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_COLOR; + blend.srcRGB = blend.srcA = GL_ONE; + blend.dstRGB = blend.dstA = GL_ONE_MINUS_SRC_COLOR; break; case BLEND_REPLACE: default: - state.srcRGB = state.srcA = GL_ONE; - state.dstRGB = state.dstA = GL_ZERO; + blend.srcRGB = blend.srcA = GL_ONE; + blend.dstRGB = blend.dstA = GL_ZERO; break; } - gl.setBlendState(state); + gl.setBlendState(blend); + states.back().blendMode = mode; } Graphics::BlendMode Graphics::getBlendMode() const { - OpenGL::BlendState state = gl.getBlendState(); - - if (state.func == GL_FUNC_REVERSE_SUBTRACT) // && src == GL_SRC_ALPHA && dst == GL_ONE - return BLEND_SUBTRACTIVE; - // Everything else has equation == GL_FUNC_ADD. - else if (state.srcRGB == state.srcA && state.dstRGB == state.dstA) - { - if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE) - return BLEND_ADDITIVE; - else if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA) - return BLEND_ALPHA; // alpha blend mode fallback for very old OpenGL versions. - else if (state.srcRGB == GL_DST_COLOR && state.dstRGB == GL_ZERO) - return BLEND_MULTIPLICATIVE; - else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA) - return BLEND_PREMULTIPLIED; - else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ONE_MINUS_SRC_COLOR) - return BLEND_SCREEN; - else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ZERO) - return BLEND_REPLACE; - } - else if (state.srcRGB == GL_SRC_ALPHA && state.srcA == GL_ONE && - state.dstRGB == GL_ONE_MINUS_SRC_ALPHA && state.dstA == GL_ONE_MINUS_SRC_ALPHA) - return BLEND_ALPHA; - - throw Exception("Unknown blend mode"); + return states.back().blendMode; } void Graphics::setDefaultFilter(const Texture::Filter &f) @@ -717,37 +807,38 @@ void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpn void Graphics::setLineWidth(float width) { - lineWidth = width; + states.back().lineWidth = width; } void Graphics::setLineStyle(Graphics::LineStyle style) { - lineStyle = style; + states.back().lineStyle = style; } void Graphics::setLineJoin(Graphics::LineJoin join) { - lineJoin = join; + states.back().lineJoin = join; } float Graphics::getLineWidth() const { - return lineWidth; + return states.back().lineWidth; } Graphics::LineStyle Graphics::getLineStyle() const { - return lineStyle; + return states.back().lineStyle; } Graphics::LineJoin Graphics::getLineJoin() const { - return lineJoin; + return states.back().lineJoin; } void Graphics::setPointSize(float size) { - glPointSize((GLfloat)size); + glPointSize(size); + states.back().pointSize = size; } void Graphics::setPointStyle(Graphics::PointStyle style) @@ -756,43 +847,44 @@ void Graphics::setPointStyle(Graphics::PointStyle style) glEnable(GL_POINT_SMOOTH); else // love::POINT_ROUGH glDisable(GL_POINT_SMOOTH); + + states.back().pointStyle = style; } float Graphics::getPointSize() const { - GLfloat size; - glGetFloatv(GL_POINT_SIZE, &size); - return (float)size; + return states.back().pointSize; } Graphics::PointStyle Graphics::getPointStyle() const { - if (glIsEnabled(GL_POINT_SMOOTH) == GL_TRUE) - return POINT_SMOOTH; - else - return POINT_ROUGH; + return states.back().pointStyle; } void Graphics::setWireframe(bool enable) { - wireframe = enable; glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL); + states.back().wireframe = enable; } bool Graphics::isWireframe() const { - return wireframe; + return states.back().wireframe; } void Graphics::print(const std::string &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky) { - if (currentFont != nullptr) - currentFont->print(str, x, y, 0.0, angle, sx, sy, ox, oy, kx, ky); + DisplayState &state = states.back(); + + if (state.font != nullptr) + state.font->print(str, x, y, 0.0, angle, sx, sy, ox, oy, kx, ky); } void Graphics::printf(const std::string &str, float x, float y, float wrap, AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky) { - if (currentFont == nullptr) + DisplayState &state = states.back(); + + if (state.font == nullptr) return; if (wrap < 0.0f) @@ -804,59 +896,49 @@ void Graphics::printf(const std::string &str, float x, float y, float wrap, Alig // wrappedlines indicates which lines were automatically wrapped. It's // guaranteed to have the same number of elements as lines_to_draw. vector wrappedlines; - vector lines_to_draw = currentFont->getWrap(str, wrap, 0, &wrappedlines); - - glPushMatrix(); + vector lines_to_draw = state.font->getWrap(str, wrap, 0, &wrappedlines); static Matrix t; t.setTransformation(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky); - glMultMatrixf((const GLfloat *)t.getElements()); + + OpenGL::TempTransform transform(gl); + transform.get() *= t; x = y = 0.0f; - try - { - // now for the actual printing - vector::const_iterator line_iter, line_end = lines_to_draw.end(); - float extra_spacing = 0.0f; - int num_spaces = 0; - int i = 0; + // now for the actual printing + vector::const_iterator line_iter, line_end = lines_to_draw.end(); + float extra_spacing = 0.0f; + int num_spaces = 0; + int i = 0; - for (line_iter = lines_to_draw.begin(); line_iter != line_end; ++line_iter) + for (line_iter = lines_to_draw.begin(); line_iter != line_end; ++line_iter) + { + float width = static_cast(state.font->getWidth(*line_iter)); + switch (align) { - float width = static_cast(currentFont->getWidth(*line_iter)); - switch (align) - { - case ALIGN_RIGHT: - currentFont->print(*line_iter, ceilf(x + (wrap - width)), ceilf(y), 0.0f); - break; - case ALIGN_CENTER: - currentFont->print(*line_iter, ceilf(x + (wrap - width) / 2), ceilf(y), 0.0f); - break; - case ALIGN_JUSTIFY: - num_spaces = std::count(line_iter->begin(), line_iter->end(), ' '); - if (wrappedlines[i] && num_spaces >= 1) - extra_spacing = (wrap - width) / float(num_spaces); - else - extra_spacing = 0.0f; - currentFont->print(*line_iter, ceilf(x), ceilf(y), extra_spacing); - break; - case ALIGN_LEFT: - default: - currentFont->print(*line_iter, ceilf(x), ceilf(y), 0.0f); - break; - } - y += currentFont->getHeight() * currentFont->getLineHeight(); - i++; + case ALIGN_RIGHT: + state.font->print(*line_iter, ceilf(x + (wrap - width)), ceilf(y), 0.0f); + break; + case ALIGN_CENTER: + state.font->print(*line_iter, ceilf(x + (wrap - width) / 2), ceilf(y), 0.0f); + break; + case ALIGN_JUSTIFY: + num_spaces = std::count(line_iter->begin(), line_iter->end(), ' '); + if (wrappedlines[i] && num_spaces >= 1) + extra_spacing = (wrap - width) / float(num_spaces); + else + extra_spacing = 0.0f; + state.font->print(*line_iter, ceilf(x), ceilf(y), extra_spacing); + break; + case ALIGN_LEFT: + default: + state.font->print(*line_iter, ceilf(x), ceilf(y), 0.0f); + break; } + y += state.font->getHeight() * state.font->getLineHeight(); + i++; } - catch (love::Exception &) - { - glPopMatrix(); - throw; - } - - glPopMatrix(); } /** @@ -874,22 +956,24 @@ void Graphics::point(float x, float y) void Graphics::polyline(const float *coords, size_t count) { - if (lineJoin == LINE_JOIN_NONE) + DisplayState &state = states.back(); + + if (state.lineJoin == LINE_JOIN_NONE) { NoneJoinPolyline line; - line.render(coords, count, lineWidth * .5f, float(pixel_size_stack.back()), lineStyle == LINE_SMOOTH); + line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH); line.draw(); } - else if (lineJoin == LINE_JOIN_BEVEL) + else if (state.lineJoin == LINE_JOIN_BEVEL) { BevelJoinPolyline line; - line.render(coords, count, lineWidth * .5f, float(pixel_size_stack.back()), lineStyle == LINE_SMOOTH); + line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH); line.draw(); } else // LINE_JOIN_MITER { MiterJoinPolyline line; - line.render(coords, count, lineWidth * .5f, float(pixel_size_stack.back()), lineStyle == LINE_SMOOTH); + line.render(coords, count, state.lineWidth * .5f, float(pixel_size_stack.back()), state.lineStyle == LINE_SMOOTH); line.draw(); } } @@ -996,9 +1080,8 @@ love::image::ImageData *Graphics::newScreenshot(love::image::Image *image, bool { // Temporarily unbind the currently active canvas (glReadPixels reads the // active framebuffer, not the main one.) - Canvas *curcanvas = Canvas::current; - if (curcanvas) - Canvas::bindDefaultCanvas(); + std::vector canvases = getCanvas(); + setCanvas(); int w = getWidth(); int h = getHeight(); @@ -1019,8 +1102,7 @@ love::image::ImageData *Graphics::newScreenshot(love::image::Image *image, bool { delete[] pixels; delete[] screenshot; - if (curcanvas) - curcanvas->startGrab(curcanvas->getAttachedCanvases()); + setCanvas(canvases); throw love::Exception("Out of memory."); } @@ -1052,14 +1134,12 @@ love::image::ImageData *Graphics::newScreenshot(love::image::Image *image, bool catch (love::Exception &) { delete[] screenshot; - if (curcanvas) - curcanvas->startGrab(curcanvas->getAttachedCanvases()); + setCanvas(canvases); throw; } // Re-bind the active canvas, if necessary. - if (curcanvas) - curcanvas->startGrab(curcanvas->getAttachedCanvases()); + setCanvas(canvases); return img; } @@ -1157,53 +1237,177 @@ bool Graphics::isSupported(Support feature) const } } -void Graphics::push() +void Graphics::push(StackType type) { - if (userMatrices == matrixLimit) - throw Exception("Maximum stack depth reached. (More pushes than pops?)"); - glPushMatrix(); - ++userMatrices; + if (stackTypes.size() == MAX_USER_STACK_DEPTH) + throw Exception("Maximum stack depth reached (more pushes than pops?)"); + + gl.pushTransform(); + pixel_size_stack.push_back(pixel_size_stack.back()); + + if (type == STACK_ALL) + states.push_back(states.back()); + + stackTypes.push_back(type); } void Graphics::pop() { - if (userMatrices < 1) - throw Exception("Minimum stack depth reached. (More pops than pushes?)"); - glPopMatrix(); - --userMatrices; + if (stackTypes.size() < 1) + throw Exception("Minimum stack depth reached (more pops than pushes?)"); + + gl.popTransform(); pixel_size_stack.pop_back(); + + if (stackTypes.back() == STACK_ALL) + { + DisplayState &newstate = states[states.size() - 2]; + + // Hack: the Lua-facing love.graphics.print function will set the current + // font if needed, but only on its first call... we always want a font. + if (newstate.font == nullptr) + { + newstate.font = states.back().font; + if (newstate.font != nullptr) + newstate.font->retain(); + } + + restoreStateChecked(newstate); + + // The last two states in the stack should be equal now. + states.pop_back(); + } + + stackTypes.pop_back(); } void Graphics::rotate(float r) { - glRotatef(LOVE_TODEG(r), 0, 0, 1); + gl.getTransform().rotate(r); } void Graphics::scale(float x, float y) { - glScalef(x, y, 1); + gl.getTransform().scale(x, y); pixel_size_stack.back() *= 2. / (fabs(x) + fabs(y)); } void Graphics::translate(float x, float y) { - glTranslatef(x, y, 0); + gl.getTransform().translate(x, y); } void Graphics::shear(float kx, float ky) { - Matrix t; - t.setShear(kx, ky); - glMultMatrixf((const GLfloat *)t.getElements()); + gl.getTransform().setShear(kx, ky); } void Graphics::origin() { - glLoadIdentity(); + gl.getTransform().setIdentity(); pixel_size_stack.back() = 1; } +Graphics::DisplayState::DisplayState() + : color(255, 255, 255, 255) + , backgroundColor(0, 0, 0, 255) + , blendMode(BLEND_ALPHA) + , lineWidth(1.0f) + , lineStyle(LINE_SMOOTH) + , lineJoin(LINE_JOIN_MITER) + , pointSize(1.0f) + , pointStyle(POINT_SMOOTH) + , scissor(false) + , scissorBox() + , font(nullptr) + , shader(nullptr) + , colorMask{true, true, true, true} + , wireframe(false) +{ +} + +Graphics::DisplayState::DisplayState(const DisplayState &other) + : color(other.color) + , backgroundColor(other.backgroundColor) + , blendMode(other.blendMode) + , lineWidth(other.lineWidth) + , lineStyle(other.lineStyle) + , lineJoin(other.lineJoin) + , pointSize(other.pointSize) + , pointStyle(other.pointStyle) + , scissor(other.scissor) + , scissorBox(other.scissorBox) + , font(other.font) + , shader(other.shader) + , canvases(other.canvases) + , wireframe(other.wireframe) +{ + for (int i = 0; i < 4; i++) + colorMask[i] = other.colorMask[i]; + + if (font) + font->retain(); + + if (shader) + shader->retain(); + + for (Canvas *c : canvases) + c->retain(); +} + +Graphics::DisplayState::~DisplayState() +{ + for (Canvas *c : canvases) + c->release(); + + if (shader) + shader->release(); + + if (font) + font->release(); +} + +Graphics::DisplayState &Graphics::DisplayState::operator = (const DisplayState &other) +{ + color = other.color; + backgroundColor = other.backgroundColor; + blendMode = other.blendMode; + lineWidth = other.lineWidth; + lineStyle = other.lineStyle; + lineJoin = other.lineJoin; + pointSize = other.pointSize; + pointStyle = other.pointStyle; + scissor = other.scissor; + scissorBox = other.scissorBox; + + Object::AutoRelease fontrelease(font); + + font = other.font; + if (font) + font->retain(); + + Object::AutoRelease shaderrelease(shader); + + shader = other.shader; + if (shader) + shader->retain(); + + for (Canvas *c : other.canvases) + c->retain(); + for (Canvas *c : canvases) + c->release(); + + canvases = other.canvases; + + for (int i = 0; i < 4; i++) + colorMask[i] = other.colorMask[i]; + + wireframe = other.wireframe; + + return *this; +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index bad07f0d9..bb52b2b6d 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -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(); @@ -246,10 +201,21 @@ public: **/ Font *getFont() const; + void setShader(Shader *shader); + void setShader(); + + Shader *getShader() const; + + void setCanvas(Canvas *canvas); + void setCanvas(const std::vector &canvases); + void setCanvas(); + + std::vector 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. @@ -460,8 +426,9 @@ public: **/ bool isSupported(Support feature) const; - void push(); + 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); @@ -470,17 +437,50 @@ 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; + + Font *font; + Shader *shader; + std::vector 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 pixel_size_stack; // stores current size of a pixel (needed for line drawing) - LineStyle lineStyle; - LineJoin lineJoin; - float lineWidth; - GLint matrixLimit; - GLint userMatrices; - bool colorMask[4]; - bool wireframe; int width; int height; @@ -488,7 +488,10 @@ private: bool activeStencil; - DisplayState savedState; + std::vector states; + std::vector stackTypes; // Keeps track of the pushed stack types. + + static const size_t MAX_USER_STACK_DEPTH = 64; }; // Graphics diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 2651e2292..7fdbe9886 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -526,12 +526,11 @@ void Image::uploadDefaultTexture() void Image::drawv(const Matrix &t, const Vertex *v) { + OpenGL::TempTransform transform(gl); + transform.get() *= t; + predraw(); - glPushMatrix(); - - glMultMatrixf((const GLfloat *)t.getElements()); - glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -544,8 +543,6 @@ void Image::drawv(const Matrix &t, const Vertex *v) glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - glPopMatrix(); - postdraw(); } diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index ec79b4b2c..467b7af2c 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -342,8 +342,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); - glPushMatrix(); - glMultMatrixf(m.getElements()); + OpenGL::TempTransform transform(gl); + transform.get() *= m; VertexBuffer::Bind vbo_bind(*vbo); @@ -412,8 +412,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo gl.setColor(gl.getColor()); } - glPopMatrix(); - if (texture) texture->postdraw(); } diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index fea9ca877..6798b0b00 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -28,6 +28,7 @@ // C++ #include +#include // C #include @@ -47,6 +48,8 @@ OpenGL::OpenGL() , vendor(VENDOR_UNKNOWN) , state() { + matrices.transform.reserve(10); + matrices.projection.reserve(2); } void OpenGL::initContext() @@ -56,6 +59,7 @@ void OpenGL::initContext() initOpenGLFunctions(); initVendor(); + initMatrices(); // Store the current color so we don't have to get it through GL later. GLfloat glcolor[4]; @@ -119,6 +123,13 @@ void OpenGL::initContext() state.lastPseudoInstanceID = -1; + // Invalidate the cached matrices by setting some elements to NaN. + float nan = std::numeric_limits::quiet_NaN(); + state.lastProjectionMatrix.setTranslation(nan, nan); + state.lastTransformMatrix.setTranslation(nan, nan); + + glMatrixMode(GL_MODELVIEW); + contextInitialized = true; } @@ -209,6 +220,15 @@ void OpenGL::initMaxValues() maxRenderTargets = 0; } +void OpenGL::initMatrices() +{ + matrices.transform.clear(); + matrices.projection.clear(); + + matrices.transform.push_back(Matrix()); + matrices.projection.push_back(Matrix()); +} + void OpenGL::createDefaultTexture() { // Set the 'default' texture (id 0) as a repeating white pixel. Otherwise, @@ -231,6 +251,21 @@ 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() { Shader *shader = Shader::current; @@ -251,15 +286,37 @@ 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 &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(it->second); + Canvas *canvas = dynamic_cast(r.second); if (canvas != nullptr) canvas->resolveMSAA(); } } + + const float *curproj = matrices.projection.back().getElements(); + const float *lastproj = state.lastProjectionMatrix.getElements(); + + // We only need to re-upload the projection matrix if it's changed. + if (memcmp(curproj, lastproj, sizeof(float) * 16) != 0) + { + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(curproj); + glMatrixMode(GL_MODELVIEW); + + state.lastProjectionMatrix = matrices.projection.back(); + } + + const float *curxform = matrices.transform.back().getElements(); + const float *lastxform = state.lastTransformMatrix.getElements(); + + // Same with the transform matrix. + if (memcmp(curxform, lastxform, sizeof(float) * 16) != 0) + { + glLoadMatrixf(curxform); + state.lastTransformMatrix = matrices.transform.back(); + } } void OpenGL::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index b912d4aac..1cc174ff3 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -26,9 +26,11 @@ // LOVE #include "graphics/Color.h" #include "graphics/Texture.h" +#include "common/Matrix.h" // C++ #include +#include // The last argument to AttribPointer takes a buffer offset casted to a pointer. #define BUFFER_OFFSET(i) ((char *) NULL + (i)) @@ -101,6 +103,36 @@ public: GLenum func; }; + struct + { + std::vector transform; + std::vector projection; + } matrices; + + class TempTransform + { + public: + + TempTransform(OpenGL &gl) + : gl(gl) + { + gl.pushTransform(); + } + + ~TempTransform() + { + gl.popTransform(); + } + + Matrix &get() + { + return gl.getTransform(); + } + + private: + OpenGL ≷ + }; + OpenGL(); /** @@ -116,6 +148,10 @@ public: **/ void deInitContext(); + void pushTransform(); + void popTransform(); + Matrix &getTransform(); + /** * Set up necessary state (LOVE-provided shader uniforms, etc.) for drawing. * This *MUST* be called directly before OpenGL drawing functions. @@ -258,6 +294,7 @@ private: void initVendor(); void initOpenGLFunctions(); void initMaxValues(); + void initMatrices(); void createDefaultTexture(); bool contextInitialized; @@ -290,6 +327,9 @@ private: // The last ID value used for pseudo-instancing. int lastPseudoInstanceID; + Matrix lastProjectionMatrix; + Matrix lastTransformMatrix; + } state; }; // OpenGL diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 8c1dd3484..b09ff8f17 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -843,11 +843,11 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo Color curcolor = gl.getColor(); - glPushMatrix(); - static Matrix t; t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); - glMultMatrixf((const GLfloat *)t.getElements()); + + OpenGL::TempTransform transform(gl); + transform.get() *= t; const Vertex *textureVerts = texture->getVertices(); Vertex *pVerts = particleVerts; @@ -901,8 +901,6 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo texture->postdraw(); - glPopMatrix(); - gl.setColor(curcolor); } diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 6cd08ad3a..698c58bd7 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -97,8 +97,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(); @@ -178,9 +178,8 @@ void Shader::createProgram(const std::vector &shaderids) if (program == 0) throw love::Exception("Cannot create shader program object."); - std::vector::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++) @@ -201,8 +200,8 @@ void Shader::createProgram(const std::vector &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); @@ -275,10 +274,9 @@ bool Shader::loadVolatile() std::vector 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); } @@ -364,11 +362,10 @@ std::string Shader::getWarnings() const const char *typestr; // Get the individual shader stage warnings - std::map::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(); @@ -380,13 +377,9 @@ void Shader::attach(bool temporary) { if (current != this) { - if (current != nullptr) - current->release(); - glUseProgram(program); current = this; - - current->retain(); + // retain/release happens in Graphics::setShader. } if (!temporary) diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index b59618ee3..82f026441 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -271,11 +271,10 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float return; static Matrix t; - - glPushMatrix(); - t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); - glMultMatrixf((const GLfloat *)t.getElements()); + + OpenGL::TempTransform transform(gl); + transform.get() *= t; texture->predraw(); @@ -314,8 +313,6 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float } texture->postdraw(); - - glPopMatrix(); } void SpriteBatch::addv(const Vertex *v, int index) diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 8d00e4dbe..92addd5ae 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -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(Module::M_GRAPHICS); - luax_catchexcept(L, [&](){ canvas->startGrab(); }); + if (graphics) + { + // Save the current Canvas so we can restore it when we're done. + std::vector 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; } diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index bd60c3b89..0a88cd2f4 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -651,8 +651,7 @@ int w_setColorMask(lua_State *L) mask[i] = luax_toboolean(L, i + 1); } - // r, g, b, a - instance()->setColorMask(mask[0], mask[1], mask[2], mask[3]); + instance()->setColorMask(mask); return 0; } @@ -893,43 +892,35 @@ int w_setCanvas(lua_State *L) instance()->discardStencil(); // called with none -> reset to default buffer - if (lua_isnoneornil(L,1)) + if (lua_isnoneornil(L, 1)) { - Canvas::bindDefaultCanvas(); + instance()->setCanvas(); return 0; } bool is_table = lua_istable(L, 1); - std::vector attachments; - - Canvas *canvas = 0; + std::vector canvases; if (is_table) { - // grab the first canvas in the array and attach the rest - lua_rawgeti(L, 1, 1); - canvas = luax_checkcanvas(L, -1); - lua_pop(L, 1); - - for (size_t i = 2; i <= lua_objlen(L, 1); i++) + for (size_t i = 1; i <= lua_objlen(L, 1); i++) { lua_rawgeti(L, 1, i); - attachments.push_back(luax_checkcanvas(L, -1)); + canvases.push_back(luax_checkcanvas(L, -1)); lua_pop(L, 1); } } else { - canvas = luax_checkcanvas(L, 1); - for (int i = 2; i <= lua_gettop(L); i++) - attachments.push_back(luax_checkcanvas(L, i)); + for (int i = 1; i <= lua_gettop(L); i++) + canvases.push_back(luax_checkcanvas(L, i)); } luax_catchexcept(L, [&]() { - if (attachments.size() > 0) - canvas->startGrab(attachments); + if (canvases.size() > 0) + instance()->setCanvas(canvases); else - canvas->startGrab(); + instance()->setCanvas(); }); return 0; @@ -937,24 +928,23 @@ int w_setCanvas(lua_State *L) int w_getCanvas(lua_State *L) { - Canvas *canvas = Canvas::current; - int n = 1; + const std::vector canvases = instance()->getCanvas(); + int n = 0; - if (canvas) + if (!canvases.empty()) { - canvas->retain(); - luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, canvas); - - const std::vector &attachments = canvas->getAttachedCanvases(); - for (size_t i = 0; i < attachments.size(); i++) + for (Canvas *c : canvases) { - attachments[i]->retain(); - luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, attachments[i]); + c->retain(); + luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, c); n++; } } else + { lua_pushnil(L); + n = 1; + } return n; } @@ -963,18 +953,18 @@ int w_setShader(lua_State *L) { if (lua_isnoneornil(L,1)) { - Shader::detach(); + instance()->setShader(); return 0; } Shader *shader = luax_checkshader(L, 1); - shader->attach(); + instance()->setShader(shader); return 0; } int w_getShader(lua_State *L) { - Shader *shader = Shader::current; + Shader *shader = instance()->getShader(); if (shader) { shader->retain(); @@ -1323,7 +1313,12 @@ int w_polygon(lua_State *L) int w_push(lua_State *L) { - luax_catchexcept(L, [&](){ instance()->push(); }); + Graphics::StackType stype = Graphics::STACK_TRANSFORM; + const char *sname = lua_isnoneornil(L, 1) ? nullptr : luaL_checkstring(L, 1); + if (sname && !Graphics::getConstant(sname, stype)) + return luaL_error(L, "Invalid graphics stack type: %s", sname); + + luax_catchexcept(L, [&](){ instance()->push(stype); }); return 0; } From a0fff798aab262306c5d269955266800bd250494 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 7 Aug 2014 01:12:48 -0300 Subject: [PATCH 4/6] Fixed compiling with Visual Studio. --- src/modules/graphics/opengl/Graphics.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 735d5852a..47c3e862e 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1322,9 +1322,11 @@ Graphics::DisplayState::DisplayState() , scissorBox() , font(nullptr) , shader(nullptr) - , colorMask{true, true, true, true} , wireframe(false) { + // We should just directly initialize the array in the initializer list, but + // that feature of C++11 is broken in Visual Studio 2013... + colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true; } Graphics::DisplayState::DisplayState(const DisplayState &other) From d59c76a55fcb3f15a5a61ef9f27386c0e31b7f3e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 7 Aug 2014 14:53:17 -0300 Subject: [PATCH 5/6] Reduced the number of explicit retain/release method calls on love objects. Less chance of bugs! --- src/common/Object.cpp | 2 + src/common/Object.h | 62 +++++++++ src/modules/audio/openal/Source.cpp | 21 ++-- src/modules/audio/openal/Source.h | 4 +- src/modules/font/ImageRasterizer.cpp | 2 - src/modules/font/ImageRasterizer.h | 2 +- .../font/freetype/TrueTypeRasterizer.cpp | 3 - .../font/freetype/TrueTypeRasterizer.h | 2 +- src/modules/graphics/opengl/Font.cpp | 3 - src/modules/graphics/opengl/Font.h | 2 +- src/modules/graphics/opengl/Graphics.cpp | 119 ++++++------------ src/modules/graphics/opengl/Graphics.h | 8 +- src/modules/graphics/opengl/Image.cpp | 34 ++--- src/modules/graphics/opengl/Image.h | 4 +- src/modules/graphics/opengl/Mesh.cpp | 21 +--- src/modules/graphics/opengl/Mesh.h | 2 +- .../graphics/opengl/ParticleSystem.cpp | 49 +++----- src/modules/graphics/opengl/ParticleSystem.h | 6 +- src/modules/graphics/opengl/SpriteBatch.cpp | 11 +- src/modules/graphics/opengl/SpriteBatch.h | 2 +- src/modules/mouse/sdl/Mouse.cpp | 20 ++- src/modules/mouse/sdl/Mouse.h | 2 +- src/modules/physics/box2d/Body.cpp | 7 +- src/modules/physics/box2d/Body.h | 2 +- src/modules/physics/box2d/Joint.cpp | 4 +- src/modules/physics/box2d/World.cpp | 9 +- src/modules/sound/lullaby/Decoder.cpp | 3 - src/modules/sound/lullaby/Decoder.h | 2 +- src/modules/sound/lullaby/FLACDecoder.cpp | 2 +- src/modules/sound/lullaby/GmeDecoder.cpp | 2 +- src/modules/sound/lullaby/ModPlugDecoder.cpp | 2 +- src/modules/sound/lullaby/Mpg123Decoder.cpp | 2 +- src/modules/sound/lullaby/VorbisDecoder.cpp | 2 +- src/modules/sound/lullaby/WaveDecoder.cpp | 2 +- src/modules/thread/LuaThread.cpp | 3 - src/modules/thread/LuaThread.h | 2 +- src/modules/window/sdl/Window.cpp | 14 +-- src/modules/window/sdl/Window.h | 2 +- 38 files changed, 194 insertions(+), 247 deletions(-) diff --git a/src/common/Object.cpp b/src/common/Object.cpp index 577f7dfa2..dc7df2306 100644 --- a/src/common/Object.cpp +++ b/src/common/Object.cpp @@ -21,6 +21,8 @@ // LOVE #include "Object.h" +#include + namespace love { diff --git a/src/common/Object.h b/src/common/Object.h index 348da1b63..791c1dac1 100644 --- a/src/common/Object.h +++ b/src/common/Object.h @@ -92,11 +92,73 @@ public: }; // AutoRelease + /** + * Partial re-implementation + specialization of std::shared_ptr. We can't + * use C++11's stdlib yet... + **/ + template + class StrongRef + { + public: + + StrongRef() + : object(nullptr) + { + } + + StrongRef(T *obj) + : object(obj) + { + if (object) object->retain(); + } + + StrongRef(const StrongRef &other) + : object(other.get()) + { + if (object) object->retain(); + } + + ~StrongRef() + { + if (object) object->release(); + } + + StrongRef &operator = (const StrongRef &other) + { + set(other.get()); + return *this; + } + + T *operator->() const + { + return object; + } + + void set(T *obj) + { + if (obj) obj->retain(); + if (object) object->release(); + object = obj; + } + + T *get() const + { + return object; + } + + private: + + T *object; + + }; // StrongRef + private: // The reference count. int count; + }; // Object + } // love #endif // LOVE_OBJECT_H diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index 20bf87fdd..a60907a79 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -98,7 +98,6 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder) , decoder(decoder) , toLoop(0) { - decoder->retain(); alGenBuffers(MAX_BUFFERS, streamBuffers); float z[3] = {0, 0, 0}; @@ -132,13 +131,15 @@ Source::Source(const Source &s) { if (type == TYPE_STREAM) { - if (s.decoder) - decoder = s.decoder->clone(); + if (s.decoder.get()) + { + love::sound::Decoder *dec = s.decoder->clone(); + decoder.set(dec); + dec->release(); + } alGenBuffers(MAX_BUFFERS, streamBuffers); } - else - staticBuffer->retain(); setFloatv(position, s.position); setFloatv(velocity, s.velocity); @@ -152,12 +153,6 @@ Source::~Source() if (type == TYPE_STREAM) alDeleteBuffers(MAX_BUFFERS, streamBuffers); - - if (staticBuffer) - staticBuffer->release(); - - if (decoder) - decoder->release(); } love::audio::Source *Source::clone() @@ -269,7 +264,7 @@ bool Source::update() offsetSamples += (curOffsetSamples - newOffsetSamples); offsetSeconds += (curOffsetSecs - newOffsetSecs); - streamAtomic(buffer, decoder); + streamAtomic(buffer, decoder.get()); alSourceQueueBuffers(source, 1, &buffer); } return true; @@ -510,7 +505,7 @@ bool Source::playAtomic() for (unsigned int i = 0; i < MAX_BUFFERS; i++) { - streamAtomic(streamBuffers[i], decoder); + streamAtomic(streamBuffers[i], decoder.get()); ++usedBuffers; if (decoder->isFinished()) break; diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index 5591c6b85..a8985aa30 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -148,7 +148,7 @@ private: static const unsigned int MAX_BUFFERS = 32; ALuint streamBuffers[MAX_BUFFERS]; - StaticDataBuffer *staticBuffer; + Object::StrongRef staticBuffer; float pitch; float volume; @@ -182,7 +182,7 @@ private: int channels; - love::sound::Decoder *decoder; + Object::StrongRef decoder; unsigned int toLoop; diff --git a/src/modules/font/ImageRasterizer.cpp b/src/modules/font/ImageRasterizer.cpp index fd0ec21b2..f7d1fada5 100644 --- a/src/modules/font/ImageRasterizer.cpp +++ b/src/modules/font/ImageRasterizer.cpp @@ -39,13 +39,11 @@ ImageRasterizer::ImageRasterizer(love::image::ImageData *data, uint32 *glyphs, i , glyphs(glyphs) , numglyphs(numglyphs) { - imageData->retain(); load(); } ImageRasterizer::~ImageRasterizer() { - imageData->release(); } int ImageRasterizer::getLineHeight() const diff --git a/src/modules/font/ImageRasterizer.h b/src/modules/font/ImageRasterizer.h index 482d442c6..59a16205e 100644 --- a/src/modules/font/ImageRasterizer.h +++ b/src/modules/font/ImageRasterizer.h @@ -53,7 +53,7 @@ private: void load(); // The image data - love::image::ImageData *imageData; + Object::StrongRef imageData; // The glyphs in the font uint32 *glyphs; diff --git a/src/modules/font/freetype/TrueTypeRasterizer.cpp b/src/modules/font/freetype/TrueTypeRasterizer.cpp index 3cdfac6c3..0cf92f873 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.cpp +++ b/src/modules/font/freetype/TrueTypeRasterizer.cpp @@ -51,14 +51,11 @@ TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, Data *data, int size) metrics.ascent = s.ascender >> 6; metrics.descent = s.descender >> 6; metrics.height = s.height >> 6; - - data->retain(); } TrueTypeRasterizer::~TrueTypeRasterizer() { FT_Done_Face(face); - data->release(); } int TrueTypeRasterizer::getLineHeight() const diff --git a/src/modules/font/freetype/TrueTypeRasterizer.h b/src/modules/font/freetype/TrueTypeRasterizer.h index 5600f324c..6ddaf0461 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.h +++ b/src/modules/font/freetype/TrueTypeRasterizer.h @@ -58,7 +58,7 @@ private: FT_Face face; // File data - Data *data; + Object::StrongRef data; }; // FreetypeRasterizer } // freetype diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 578c8e465..f2faee97e 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -87,13 +87,10 @@ Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter) } delete gd; - - rasterizer->retain(); } Font::~Font() { - rasterizer->release(); unloadVolatile(); } diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 403b0ef45..2ed3b931a 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -183,7 +183,7 @@ private: Glyph *addGlyph(uint32 glyph); Glyph *findGlyph(uint32 glyph); - love::font::Rasterizer *rasterizer; + Object::StrongRef rasterizer; int height; float lineHeight; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 47c3e862e..f42129f84 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -95,8 +95,8 @@ void Graphics::restoreState(const DisplayState &s) else setScissor(); - setFont(s.font); - setShader(s.shader); + setFont(s.font.get()); + setShader(s.shader.get()); setCanvas(s.canvases); setColorMask(s.colorMask); @@ -135,12 +135,12 @@ void Graphics::restoreStateChecked(const DisplayState &s) setScissor(); } - setFont(s.font); - setShader(s.shader); + setFont(s.font.get()); + setShader(s.shader.get()); for (size_t i = 0; i < s.canvases.size() && i < cur.canvases.size(); i++) { - if (s.canvases[i] != cur.canvases[i]) + if (s.canvases[i].get() != cur.canvases[i].get()) { setCanvas(s.canvases); break; @@ -606,19 +606,12 @@ Color Graphics::getBackgroundColor() const void Graphics::setFont(Font *font) { DisplayState &state = states.back(); - - if (font != nullptr) - font->retain(); - - if (state.font != nullptr) - state.font->release(); - - state.font = font; + state.font.set(font); } Font *Graphics::getFont() const { - return states.back().font; + return states.back().font.get(); } void Graphics::setShader(Shader *shader) @@ -630,13 +623,7 @@ void Graphics::setShader(Shader *shader) shader->attach(); - if (shader) - shader->retain(); - - if (state.shader) - state.shader->release(); - - state.shader = shader; + state.shader.set(shader); } void Graphics::setShader() @@ -645,15 +632,12 @@ void Graphics::setShader() Shader::detach(); - if (state.shader) - state.shader->release(); - - state.shader = nullptr; + state.shader.set(nullptr); } Shader *Graphics::getShader() const { - return states.back().shader; + return states.back().shader.get(); } void Graphics::setCanvas(Canvas *canvas) @@ -665,13 +649,10 @@ void Graphics::setCanvas(Canvas *canvas) canvas->startGrab(); - canvas->retain(); + std::vector> canvasref; + canvasref.push_back(canvas); - for (Canvas *c : state.canvases) - c->release(); - - state.canvases.clear(); - state.canvases.push_back(canvas); + std::swap(state.canvases, canvasref); } void Graphics::setCanvas(const std::vector &canvases) @@ -686,13 +667,24 @@ void Graphics::setCanvas(const std::vector &canvases) auto attachments = std::vector(canvases.begin() + 1, canvases.end()); canvases[0]->startGrab(attachments); + std::vector> canvasrefs; + canvasrefs.reserve(canvases.size()); + for (Canvas *c : canvases) - c->retain(); + canvasrefs.push_back(c); - for (Canvas *c : state.canvases) - c->release(); + std::swap(state.canvases, canvasrefs); +} - state.canvases = canvases; +void Graphics::setCanvas(const std::vector> &canvases) +{ + std::vector canvaslist; + canvaslist.reserve(canvases.size()); + + for (const Object::StrongRef &c : canvases) + canvaslist.push_back(c.get()); + + return setCanvas(canvaslist); } void Graphics::setCanvas() @@ -702,15 +694,18 @@ void Graphics::setCanvas() if (Canvas::current != nullptr) Canvas::current->stopGrab(); - for (Canvas *c : state.canvases) - c->release(); - state.canvases.clear(); } std::vector Graphics::getCanvas() const { - return states.back().canvases; + std::vector canvases; + canvases.reserve(states.back().canvases.size()); + + for (const Object::StrongRef &c : states.back().canvases) + canvases.push_back(c.get()); + + return canvases; } void Graphics::setColorMask(const bool mask[4]) @@ -876,7 +871,7 @@ void Graphics::print(const std::string &str, float x, float y , float angle, flo { DisplayState &state = states.back(); - if (state.font != nullptr) + if (state.font.get() != nullptr) state.font->print(str, x, y, 0.0, angle, sx, sy, ox, oy, kx, ky); } @@ -884,7 +879,7 @@ void Graphics::printf(const std::string &str, float x, float y, float wrap, Alig { DisplayState &state = states.back(); - if (state.font == nullptr) + if (state.font.get() == nullptr) return; if (wrap < 0.0f) @@ -1266,12 +1261,8 @@ void Graphics::pop() // Hack: the Lua-facing love.graphics.print function will set the current // font if needed, but only on its first call... we always want a font. - if (newstate.font == nullptr) - { - newstate.font = states.back().font; - if (newstate.font != nullptr) - newstate.font->retain(); - } + if (newstate.font.get() == nullptr) + newstate.font.set(states.back().font.get()); restoreStateChecked(newstate); @@ -1347,27 +1338,10 @@ Graphics::DisplayState::DisplayState(const DisplayState &other) { for (int i = 0; i < 4; i++) colorMask[i] = other.colorMask[i]; - - if (font) - font->retain(); - - if (shader) - shader->retain(); - - for (Canvas *c : canvases) - c->retain(); } Graphics::DisplayState::~DisplayState() { - for (Canvas *c : canvases) - c->release(); - - if (shader) - shader->release(); - - if (font) - font->release(); } Graphics::DisplayState &Graphics::DisplayState::operator = (const DisplayState &other) @@ -1383,23 +1357,8 @@ Graphics::DisplayState &Graphics::DisplayState::operator = (const DisplayState & scissor = other.scissor; scissorBox = other.scissorBox; - Object::AutoRelease fontrelease(font); - font = other.font; - if (font) - font->retain(); - - Object::AutoRelease shaderrelease(shader); - shader = other.shader; - if (shader) - shader->retain(); - - for (Canvas *c : other.canvases) - c->retain(); - for (Canvas *c : canvases) - c->release(); - canvases = other.canvases; for (int i = 0; i < 4; i++) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index bb52b2b6d..aebceb333 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -208,6 +208,7 @@ public: void setCanvas(Canvas *canvas); void setCanvas(const std::vector &canvases); + void setCanvas(const std::vector> &canvases); void setCanvas(); std::vector getCanvas() const; @@ -459,9 +460,10 @@ private: bool scissor; OpenGL::Viewport scissorBox; - Font *font; - Shader *shader; - std::vector canvases; + Object::StrongRef font; + Object::StrongRef shader; + + std::vector> canvases; // Color mask. bool colorMask[4]; diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 7fdbe9886..791bea74b 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -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,7 @@ GLuint Image::getGLTexture() const void Image::uploadCompressedMipmaps() { - if (!isCompressed() || !cdata || !hasCompressedTextureSupport(cdata->getFormat())) + if (!isCompressed() || !cdata.get() || !hasCompressedTextureSupport(cdata->getFormat())) return; bind(); @@ -175,7 +167,7 @@ void Image::uploadCompressedMipmaps() void Image::createMipmaps() { // Only valid for Images created with ImageData. - if (!data || isCompressed()) + if (!data.get() || isCompressed()) return; if (!hasMipmapSupport()) @@ -231,9 +223,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; @@ -334,7 +326,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)) @@ -375,7 +367,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. @@ -398,13 +390,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_SRGB8_ALPHA8 : GL_RGBA8; glTexImage2D(GL_TEXTURE_2D, @@ -430,7 +422,7 @@ void Image::uploadTexturePadded() void Image::uploadTexture() { - if (isCompressed() && cdata) + if (isCompressed() && cdata.get()) { GLenum format = getCompressedFormat(cdata->getFormat()); glCompressedTexImage2DARB(GL_TEXTURE_2D, @@ -442,7 +434,7 @@ void Image::uploadTexture() GLsizei(cdata->getSize(0)), cdata->getData(0)); } - else if (data) + else if (data.get()) { GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB8_ALPHA8 : GL_RGBA8; glTexImage2D(GL_TEXTURE_2D, @@ -484,7 +476,7 @@ bool Image::refresh() bind(); - if (data && !isCompressed()) + if (data.get() && !isCompressed()) lock.setLock(data->getMutex()); while (glGetError() != GL_NO_ERROR); // Clear errors. diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 6e24b17c6..f15b0aa4a 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -156,11 +156,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 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 cdata; // Real dimensions of the texture, if it was auto-padded to POT size. int paddedWidth, paddedHeight; diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 467b7af2c..0e11b2178 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -79,9 +79,6 @@ Mesh::Mesh(int vertexcount, Mesh::DrawMode mode) Mesh::~Mesh() { - if (texture) - texture->release(); - delete vbo; delete ibo; } @@ -264,25 +261,17 @@ size_t Mesh::getVertexMapCount() const 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) @@ -334,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(0); @@ -412,7 +401,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo gl.setColor(gl.getColor()); } - if (texture) + if (texture.get()) texture->postdraw(); } diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 64b50bd48..5836893de 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -178,7 +178,7 @@ private: int range_min; int range_max; - Texture *texture; + Object::StrongRef texture; // Whether the per-vertex colors are used when drawing. bool colors_enabled; diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index b09ff8f17..289bcfcc1 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -102,7 +102,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) @@ -150,22 +149,10 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) , relativeRotation(p.relativeRotation) { setBufferSize(maxParticles); - - if (texture != nullptr) - texture->retain(); - - for (Quad *quad : quads) - quad->retain(); } ParticleSystem::~ParticleSystem() { - if (texture != nullptr) - texture->release(); - - for (Quad *quad : quads) - quad->release(); - deleteBuffers(); } @@ -422,19 +409,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) @@ -732,26 +714,29 @@ std::vector ParticleSystem::getColor() const void ParticleSystem::setQuads(const std::vector &newQuads) { - for (Quad *quad : newQuads) - quad->retain(); + std::vector> quadlist; + quadlist.reserve(newQuads.size()); - for (Quad *quad : quads) - quad->release(); + for (Quad *q : newQuads) + quadlist.push_back(q); - quads = newQuads; + quads = quadlist; } void ParticleSystem::setQuads() { - for (Quad *quad : quads) - quad->release(); - quads.clear(); } -const std::vector &ParticleSystem::getQuads() const +std::vector ParticleSystem::getQuads() const { - return quads; + std::vector quadlist; + quadlist.reserve(quads.size()); + + for (const Object::StrongRef &q : quads) + quadlist.push_back(q.get()); + + return quadlist; } void ParticleSystem::setRelativeRotation(bool enable) @@ -838,7 +823,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(); diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 6f9e8750f..64b7b6244 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -431,7 +431,7 @@ public: /** * Gets the Quads used when drawing the particles. **/ - const std::vector &getQuads() const; + std::vector getQuads() const; /** * sets whether particle angles & rotations are relative to their velocities. @@ -563,7 +563,7 @@ protected: Vertex *particleVerts; // The texture to be drawn. - Texture *texture; + Object::StrongRef texture; // Whether the particle emitter is active. bool active; @@ -640,7 +640,7 @@ protected: std::vector colors; // Quads. - std::vector quads; + std::vector> quads; bool relativeRotation; diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 82f026441..e0a8a90e4 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -88,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; @@ -172,15 +168,12 @@ void SpriteBatch::flush() 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) diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h index 1f3de1c99..55a736929 100644 --- a/src/modules/graphics/opengl/SpriteBatch.h +++ b/src/modules/graphics/opengl/SpriteBatch.h @@ -126,7 +126,7 @@ private: */ void setColorv(Vertex *v, const Color &color); - Texture *texture; + Object::StrongRef texture; // Max number of sprites in the batch. int size; diff --git a/src/modules/mouse/sdl/Mouse.cpp b/src/modules/mouse/sdl/Mouse.cpp index 22f88fb05..cf1ccd0c9 100644 --- a/src/modules/mouse/sdl/Mouse.cpp +++ b/src/modules/mouse/sdl/Mouse.cpp @@ -77,11 +77,11 @@ Mouse::Mouse() Mouse::~Mouse() { - if (curCursor) + if (curCursor.get()) setCursor(); - for (auto it = systemCursors.begin(); it != systemCursors.end(); ++it) - it->second->release(); + for (auto &c : systemCursors) + c.second->release(); } love::mouse::Cursor *Mouse::newCursor(love::image::ImageData *data, int hotx, int hoty) @@ -91,7 +91,7 @@ love::mouse::Cursor *Mouse::newCursor(love::image::ImageData *data, int hotx, in love::mouse::Cursor *Mouse::getSystemCursor(Cursor::SystemCursor cursortype) { - Cursor *cursor = NULL; + Cursor *cursor = nullptr; auto it = systemCursors.find(cursortype); if (it != systemCursors.end()) @@ -107,25 +107,19 @@ love::mouse::Cursor *Mouse::getSystemCursor(Cursor::SystemCursor cursortype) void Mouse::setCursor(love::mouse::Cursor *cursor) { - Object::AutoRelease cursorrelease(curCursor); - - curCursor = cursor; - curCursor->retain(); - + curCursor.set(cursor); SDL_SetCursor((SDL_Cursor *) cursor->getHandle()); } void Mouse::setCursor() { - Object::AutoRelease cursorrelease(curCursor); - curCursor = NULL; - + curCursor.set(nullptr); SDL_SetCursor(SDL_GetDefaultCursor()); } love::mouse::Cursor *Mouse::getCursor() const { - return curCursor; + return curCursor.get(); } int Mouse::getX() const diff --git a/src/modules/mouse/sdl/Mouse.h b/src/modules/mouse/sdl/Mouse.h index 43b8dad61..d4ec75c7a 100644 --- a/src/modules/mouse/sdl/Mouse.h +++ b/src/modules/mouse/sdl/Mouse.h @@ -67,7 +67,7 @@ public: private: - love::mouse::Cursor *curCursor; + Object::StrongRef curCursor; std::map systemCursors; diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index 880e50b83..cc18e98bd 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -41,7 +41,6 @@ Body::Body(World *world, b2Vec2 p, Body::Type type) { udata = new bodyudata(); udata->ref = nullptr; - world->retain(); b2BodyDef def; def.position = Physics::scaleDown(p); def.userData = (void *) udata; @@ -57,8 +56,7 @@ Body::Body(b2Body *b) , udata(nullptr) { udata = (bodyudata *) b->GetUserData(); - world = (World *)Memoizer::find(b->GetWorld()); - world->retain(); + world.set((World *) Memoizer::find(b->GetWorld())); // Box2D body holds a reference to the love Body. this->retain(); Memoizer::add(body, this); @@ -69,7 +67,6 @@ Body::~Body() if (udata != nullptr) delete udata->ref; delete udata; - world->release(); } float Body::getX() @@ -420,7 +417,7 @@ bool Body::isFixedRotation() const World *Body::getWorld() const { - return world; + return world.get(); } int Body::getFixtureList(lua_State *L) const diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index 83dd0c6b1..e951d242b 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -436,7 +436,7 @@ private: // // This ensures that a World only can be destroyed // once all bodies have been destroyed too. - World *world; + Object::StrongRef world; bodyudata *udata; diff --git a/src/modules/physics/box2d/Joint.cpp b/src/modules/physics/box2d/Joint.cpp index 8ca574530..ee48d202f 100644 --- a/src/modules/physics/box2d/Joint.cpp +++ b/src/modules/physics/box2d/Joint.cpp @@ -40,7 +40,7 @@ namespace box2d { Joint::Joint(Body *body1) - : world(body1->world) + : world(body1->world.get()) , udata(nullptr) , body1(body1) , body2(nullptr) @@ -50,7 +50,7 @@ Joint::Joint(Body *body1) } Joint::Joint(Body *body1, Body *body2) - : world(body1->world) + : world(body1->world.get()) , udata(nullptr) , body1(body1) , body2(body2) diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 4f2177543..c08846ec4 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -259,23 +259,20 @@ void World::update(float dt) world->Step(dt, 8, 6); // Destroy all objects marked during the time step. - for (auto i = destructBodies.begin(); i < destructBodies.end(); i++) + for (Body *b : destructBodies) { - Body *b = *i; if (b->body != 0) b->destroy(); // Release for reference in vector. b->release(); } - for (auto i = destructFixtures.begin(); i < destructFixtures.end(); i++) + for (Fixture *f : destructFixtures) { - Fixture *f = *i; if (f->isValid()) f->destroy(); // Release for reference in vector. f->release(); } - for (auto i = destructJoints.begin(); i < destructJoints.end(); i++) + for (Joint *j : destructJoints) { - Joint *j = *i; if (j->isValid()) j->destroyJoint(); // Release for reference in vector. j->release(); diff --git a/src/modules/sound/lullaby/Decoder.cpp b/src/modules/sound/lullaby/Decoder.cpp index 8a591fc8d..62fc45780 100644 --- a/src/modules/sound/lullaby/Decoder.cpp +++ b/src/modules/sound/lullaby/Decoder.cpp @@ -37,7 +37,6 @@ Decoder::Decoder(Data *data, const std::string &ext, int bufferSize) , buffer(0) , eof(false) { - data->retain(); buffer = new char[bufferSize]; } @@ -45,8 +44,6 @@ Decoder::~Decoder() { if (buffer != 0) delete [](char *) buffer; - if (data != 0) - data->release(); } void *Decoder::getBuffer() const diff --git a/src/modules/sound/lullaby/Decoder.h b/src/modules/sound/lullaby/Decoder.h index 4a962960e..ae9571505 100644 --- a/src/modules/sound/lullaby/Decoder.h +++ b/src/modules/sound/lullaby/Decoder.h @@ -53,7 +53,7 @@ protected: // The encoded data. This should be replaced with buffered file // reads in the future. - Data *data; + Object::StrongRef data; // File extension. std::string ext; diff --git a/src/modules/sound/lullaby/FLACDecoder.cpp b/src/modules/sound/lullaby/FLACDecoder.cpp index 6762d9f7b..aa6bcd8bf 100644 --- a/src/modules/sound/lullaby/FLACDecoder.cpp +++ b/src/modules/sound/lullaby/FLACDecoder.cpp @@ -69,7 +69,7 @@ bool FLACDecoder::accepts(const std::string &ext) love::sound::Decoder *FLACDecoder::clone() { - return new FLACDecoder(data, ext, bufferSize, sampleRate); + return new FLACDecoder(data.get(), ext, bufferSize, sampleRate); } int FLACDecoder::decode() diff --git a/src/modules/sound/lullaby/GmeDecoder.cpp b/src/modules/sound/lullaby/GmeDecoder.cpp index 98d364829..a3131570d 100644 --- a/src/modules/sound/lullaby/GmeDecoder.cpp +++ b/src/modules/sound/lullaby/GmeDecoder.cpp @@ -86,7 +86,7 @@ bool GmeDecoder::accepts(const std::string &ext) love::sound::Decoder *GmeDecoder::clone() { - return new GmeDecoder(data, ext, bufferSize); + return new GmeDecoder(data.get(), ext, bufferSize); } int GmeDecoder::decode() diff --git a/src/modules/sound/lullaby/ModPlugDecoder.cpp b/src/modules/sound/lullaby/ModPlugDecoder.cpp index 4e383ea0a..ce62b4acd 100644 --- a/src/modules/sound/lullaby/ModPlugDecoder.cpp +++ b/src/modules/sound/lullaby/ModPlugDecoder.cpp @@ -98,7 +98,7 @@ bool ModPlugDecoder::accepts(const std::string &ext) love::sound::Decoder *ModPlugDecoder::clone() { - return new ModPlugDecoder(data, ext, bufferSize); + return new ModPlugDecoder(data.get(), ext, bufferSize); } int ModPlugDecoder::decode() diff --git a/src/modules/sound/lullaby/Mpg123Decoder.cpp b/src/modules/sound/lullaby/Mpg123Decoder.cpp index 01dc6c83f..1f4a58f08 100644 --- a/src/modules/sound/lullaby/Mpg123Decoder.cpp +++ b/src/modules/sound/lullaby/Mpg123Decoder.cpp @@ -96,7 +96,7 @@ void Mpg123Decoder::quit() love::sound::Decoder *Mpg123Decoder::clone() { - return new Mpg123Decoder(data, ext, bufferSize); + return new Mpg123Decoder(data.get(), ext, bufferSize); } int Mpg123Decoder::decode() diff --git a/src/modules/sound/lullaby/VorbisDecoder.cpp b/src/modules/sound/lullaby/VorbisDecoder.cpp index 576244d2a..052519204 100644 --- a/src/modules/sound/lullaby/VorbisDecoder.cpp +++ b/src/modules/sound/lullaby/VorbisDecoder.cpp @@ -179,7 +179,7 @@ bool VorbisDecoder::accepts(const std::string &ext) love::sound::Decoder *VorbisDecoder::clone() { - return new VorbisDecoder(data, ext, bufferSize); + return new VorbisDecoder(data.get(), ext, bufferSize); } int VorbisDecoder::decode() diff --git a/src/modules/sound/lullaby/WaveDecoder.cpp b/src/modules/sound/lullaby/WaveDecoder.cpp index 84f9fdf3d..5dce78e9d 100644 --- a/src/modules/sound/lullaby/WaveDecoder.cpp +++ b/src/modules/sound/lullaby/WaveDecoder.cpp @@ -117,7 +117,7 @@ bool WaveDecoder::accepts(const std::string &ext) love::sound::Decoder *WaveDecoder::clone() { - return new WaveDecoder(data, ext, bufferSize); + return new WaveDecoder(data.get(), ext, bufferSize); } int WaveDecoder::decode() diff --git a/src/modules/thread/LuaThread.cpp b/src/modules/thread/LuaThread.cpp index c05dc830a..5bb6515ea 100644 --- a/src/modules/thread/LuaThread.cpp +++ b/src/modules/thread/LuaThread.cpp @@ -37,14 +37,11 @@ LuaThread::LuaThread(const std::string &name, love::Data *code) , args(0) , nargs(0) { - code->retain(); threadName = name; } LuaThread::~LuaThread() { - code->release(); - // No args should still exist at this point, // but you never know. for (int i = 0; i < nargs; ++i) diff --git a/src/modules/thread/LuaThread.h b/src/modules/thread/LuaThread.h index e5722a750..122c2cc11 100644 --- a/src/modules/thread/LuaThread.h +++ b/src/modules/thread/LuaThread.h @@ -50,7 +50,7 @@ private: void onError(); - love::Data *code; + Object::StrongRef code; std::string name; std::string error; diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 4513b50d8..c149c9d35 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -48,9 +48,6 @@ Window::Window() Window::~Window() { - if (curMode.icon) - curMode.icon->release(); - if (window) SDL_DestroyWindow(window); @@ -185,8 +182,8 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) } // Make sure the window keeps any previously set icon. - if (window && curMode.icon) - setIcon(curMode.icon); + if (window && curMode.icon.get()) + setIcon(curMode.icon.get()); } if (!window) @@ -563,10 +560,7 @@ bool Window::setIcon(love::image::ImageData *imgd) if (!imgd) return false; - imgd->retain(); - if (curMode.icon) - curMode.icon->release(); - curMode.icon = imgd; + curMode.icon.set(imgd); if (!window) return false; @@ -607,7 +601,7 @@ bool Window::setIcon(love::image::ImageData *imgd) love::image::ImageData *Window::getIcon() { - return curMode.icon; + return curMode.icon.get(); } void Window::minimize() diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index c60cfa620..495dd6870 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -114,7 +114,7 @@ private: int width; int height; WindowSettings settings; - love::image::ImageData *icon; + Object::StrongRef icon; } curMode; From 30ff7d4659ed8694a5cd1419c80bf09467468f5d Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Thu, 7 Aug 2014 20:22:58 +0200 Subject: [PATCH 6/6] Make openURL call on linux non-blocking, because the spawned processes are not guaranteed to fork into the background, and enable automatic zombie cleanup to deal with that change (note: the return value is now slightly less accurate) --- src/modules/system/System.cpp | 23 ++++++++++++++++++++--- src/modules/system/System.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/modules/system/System.cpp b/src/modules/system/System.cpp index dd74c120f..8b1367f8b 100755 --- a/src/modules/system/System.cpp +++ b/src/modules/system/System.cpp @@ -28,6 +28,7 @@ #include //#include //#include +#include #include #elif defined(LOVE_WINDOWS) #include "common/utf8.h" @@ -41,6 +42,20 @@ namespace love namespace system { +System::System() +{ +#if defined(LOVE_LINUX) + // Enable automatic cleanup of zombie processes + struct sigaction act = {0}; + sigemptyset(&act.sa_mask); + act.sa_handler = SIG_DFL; + act.sa_flags = SA_NOCLDWAIT; + + // Requires linux 2.6 or higher, so anything remotely modern + sigaction(SIGCHLD, &act, nullptr); +#endif +} + std::string System::getOS() const { #if defined(LOVE_MACOSX) @@ -86,12 +101,14 @@ bool System::openURL(const std::string &url) const if (posix_spawnp(&pid, "xdg-open", nullptr, nullptr, const_cast(argv), environ) != 0) return false; - // Wait for xdg-open to complete (or fail.) + // Check if xdg-open already completed (or failed.) int status = 0; - if (waitpid(pid, &status, 0) == pid) + if (waitpid(pid, &status, WNOHANG) > 0) return (status == 0); else - return false; + // We can't tell what actually happens without waiting for + // the process to finish, which could take forever (literally). + return true; #elif defined(LOVE_WINDOWS) diff --git a/src/modules/system/System.h b/src/modules/system/System.h index 58eff3356..fb12b22fc 100644 --- a/src/modules/system/System.h +++ b/src/modules/system/System.h @@ -48,6 +48,7 @@ public: POWER_MAX_ENUM }; + System(); virtual ~System() {} // Implements Module.