Browse Source

Reduced the number of explicit retain/release method calls on love objects. Less chance of bugs!

Alex Szpakowski 11 years ago
parent
commit
d59c76a55f
38 changed files with 194 additions and 247 deletions
  1. 2 0
      src/common/Object.cpp
  2. 62 0
      src/common/Object.h
  3. 8 13
      src/modules/audio/openal/Source.cpp
  4. 2 2
      src/modules/audio/openal/Source.h
  5. 0 2
      src/modules/font/ImageRasterizer.cpp
  6. 1 1
      src/modules/font/ImageRasterizer.h
  7. 0 3
      src/modules/font/freetype/TrueTypeRasterizer.cpp
  8. 1 1
      src/modules/font/freetype/TrueTypeRasterizer.h
  9. 0 3
      src/modules/graphics/opengl/Font.cpp
  10. 1 1
      src/modules/graphics/opengl/Font.h
  11. 39 80
      src/modules/graphics/opengl/Graphics.cpp
  12. 5 3
      src/modules/graphics/opengl/Graphics.h
  13. 13 21
      src/modules/graphics/opengl/Image.cpp
  14. 2 2
      src/modules/graphics/opengl/Image.h
  15. 5 16
      src/modules/graphics/opengl/Mesh.cpp
  16. 1 1
      src/modules/graphics/opengl/Mesh.h
  17. 17 32
      src/modules/graphics/opengl/ParticleSystem.cpp
  18. 3 3
      src/modules/graphics/opengl/ParticleSystem.h
  19. 2 9
      src/modules/graphics/opengl/SpriteBatch.cpp
  20. 1 1
      src/modules/graphics/opengl/SpriteBatch.h
  21. 7 13
      src/modules/mouse/sdl/Mouse.cpp
  22. 1 1
      src/modules/mouse/sdl/Mouse.h
  23. 2 5
      src/modules/physics/box2d/Body.cpp
  24. 1 1
      src/modules/physics/box2d/Body.h
  25. 2 2
      src/modules/physics/box2d/Joint.cpp
  26. 3 6
      src/modules/physics/box2d/World.cpp
  27. 0 3
      src/modules/sound/lullaby/Decoder.cpp
  28. 1 1
      src/modules/sound/lullaby/Decoder.h
  29. 1 1
      src/modules/sound/lullaby/FLACDecoder.cpp
  30. 1 1
      src/modules/sound/lullaby/GmeDecoder.cpp
  31. 1 1
      src/modules/sound/lullaby/ModPlugDecoder.cpp
  32. 1 1
      src/modules/sound/lullaby/Mpg123Decoder.cpp
  33. 1 1
      src/modules/sound/lullaby/VorbisDecoder.cpp
  34. 1 1
      src/modules/sound/lullaby/WaveDecoder.cpp
  35. 0 3
      src/modules/thread/LuaThread.cpp
  36. 1 1
      src/modules/thread/LuaThread.h
  37. 4 10
      src/modules/window/sdl/Window.cpp
  38. 1 1
      src/modules/window/sdl/Window.h

+ 2 - 0
src/common/Object.cpp

@@ -21,6 +21,8 @@
 // LOVE
 #include "Object.h"
 
+#include <stdio.h>
+
 namespace love
 {
 

+ 62 - 0
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 <typename T>
+	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

+ 8 - 13
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;

+ 2 - 2
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<StaticDataBuffer> staticBuffer;
 
 	float pitch;
 	float volume;
@@ -182,7 +182,7 @@ private:
 
 	int channels;
 
-	love::sound::Decoder *decoder;
+	Object::StrongRef<love::sound::Decoder> decoder;
 
 	unsigned int toLoop;
 

+ 0 - 2
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

+ 1 - 1
src/modules/font/ImageRasterizer.h

@@ -53,7 +53,7 @@ private:
 	void load();
 
 	// The image data
-	love::image::ImageData *imageData;
+	Object::StrongRef<love::image::ImageData> imageData;
 
 	// The glyphs in the font
 	uint32 *glyphs;

+ 0 - 3
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

+ 1 - 1
src/modules/font/freetype/TrueTypeRasterizer.h

@@ -58,7 +58,7 @@ private:
 	FT_Face face;
 
 	// File data
-	Data *data;
+	Object::StrongRef<Data> data;
 }; // FreetypeRasterizer
 
 } // freetype

+ 0 - 3
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();
 }
 

+ 1 - 1
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<love::font::Rasterizer> rasterizer;
 
 	int height;
 	float lineHeight;

+ 39 - 80
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<Object::StrongRef<Canvas>> 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<Canvas *> &canvases)
@@ -686,13 +667,24 @@ void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
 	auto attachments = std::vector<Canvas *>(canvases.begin() + 1, canvases.end());
 	canvases[0]->startGrab(attachments);
 
+	std::vector<Object::StrongRef<Canvas>> canvasrefs;
+	canvasrefs.reserve(canvases.size());
+
 	for (Canvas *c : canvases)
-		c->retain();
+		canvasrefs.push_back(c);
+
+	std::swap(state.canvases, canvasrefs);
+}
+
+void Graphics::setCanvas(const std::vector<Object::StrongRef<Canvas>> &canvases)
+{
+	std::vector<Canvas *> canvaslist;
+	canvaslist.reserve(canvases.size());
 
-	for (Canvas *c : state.canvases)
-		c->release();
+	for (const Object::StrongRef<Canvas> &c : canvases)
+		canvaslist.push_back(c.get());
 
-	state.canvases = canvases;
+	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<Canvas *> Graphics::getCanvas() const
 {
-	return states.back().canvases;
+	std::vector<Canvas *> canvases;
+	canvases.reserve(states.back().canvases.size());
+
+	for (const Object::StrongRef<Canvas> &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++)

+ 5 - 3
src/modules/graphics/opengl/Graphics.h

@@ -208,6 +208,7 @@ public:
 
 	void setCanvas(Canvas *canvas);
 	void setCanvas(const std::vector<Canvas *> &canvases);
+	void setCanvas(const std::vector<Object::StrongRef<Canvas>> &canvases);
 	void setCanvas();
 
 	std::vector<Canvas *> getCanvas() const;
@@ -459,9 +460,10 @@ private:
 		bool scissor;
 		OpenGL::Viewport scissorBox;
 
-		Font *font;
-		Shader *shader;
-		std::vector<Canvas *> canvases;
+		Object::StrongRef<Font> font;
+		Object::StrongRef<Shader> shader;
+
+		std::vector<Object::StrongRef<Canvas>> canvases;
 
 		// Color mask.
 		bool colorMask[4];

+ 13 - 21
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.

+ 2 - 2
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<love::image::ImageData> data;
 
 	// Or the Compressed Image Data from which the texture is created. May be
 	// null if raw ImageData was used to create the texture.
-	love::image::CompressedData *cdata;
+	Object::StrongRef<love::image::CompressedData> cdata;
 
 	// Real dimensions of the texture, if it was auto-padded to POT size.
 	int paddedWidth, paddedHeight;

+ 5 - 16
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();
 }
 

+ 1 - 1
src/modules/graphics/opengl/Mesh.h

@@ -178,7 +178,7 @@ private:
 	int range_min;
 	int range_max;
 
-	Texture *texture;
+	Object::StrongRef<Texture> texture;
 
 	// Whether the per-vertex colors are used when drawing.
 	bool colors_enabled;

+ 17 - 32
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<Color> ParticleSystem::getColor() const
 
 void ParticleSystem::setQuads(const std::vector<Quad *> &newQuads)
 {
-	for (Quad *quad : newQuads)
-		quad->retain();
+	std::vector<StrongRef<Quad>> 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<Quad *> &ParticleSystem::getQuads() const
+std::vector<Quad *> ParticleSystem::getQuads() const
 {
-	return quads;
+	std::vector<Quad *> quadlist;
+	quadlist.reserve(quads.size());
+
+	for (const Object::StrongRef<Quad> &q : quads)
+		quadlist.push_back(q.get());
+
+	return quadlist;
 }
 
 void ParticleSystem::setRelativeRotation(bool enable)
@@ -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();

+ 3 - 3
src/modules/graphics/opengl/ParticleSystem.h

@@ -431,7 +431,7 @@ public:
 	/**
 	 * Gets the Quads used when drawing the particles.
 	 **/
-	const std::vector<Quad *> &getQuads() const;
+	std::vector<Quad *> 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> texture;
 
 	// Whether the particle emitter is active.
 	bool active;
@@ -640,7 +640,7 @@ protected:
 	std::vector<Colorf> colors;
 
 	// Quads.
-	std::vector<Quad *> quads;
+	std::vector<Object::StrongRef<Quad>> quads;
 
 	bool relativeRotation;
 

+ 2 - 9
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)

+ 1 - 1
src/modules/graphics/opengl/SpriteBatch.h

@@ -126,7 +126,7 @@ private:
 	 */
 	void setColorv(Vertex *v, const Color &color);
 
-	Texture *texture;
+	Object::StrongRef<Texture> texture;
 
 	// Max number of sprites in the batch.
 	int size;

+ 7 - 13
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

+ 1 - 1
src/modules/mouse/sdl/Mouse.h

@@ -67,7 +67,7 @@ public:
 
 private:
 
-	love::mouse::Cursor *curCursor;
+	Object::StrongRef<love::mouse::Cursor> curCursor;
 
 	std::map<Cursor::SystemCursor, Cursor *> systemCursors;
 

+ 2 - 5
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

+ 1 - 1
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> world;
 
 	bodyudata *udata;
 

+ 2 - 2
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)

+ 3 - 6
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();

+ 0 - 3
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

+ 1 - 1
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> data;
 
 	// File extension.
 	std::string ext;

+ 1 - 1
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()

+ 1 - 1
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()

+ 1 - 1
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()

+ 1 - 1
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()

+ 1 - 1
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()

+ 1 - 1
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()

+ 0 - 3
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)

+ 1 - 1
src/modules/thread/LuaThread.h

@@ -50,7 +50,7 @@ private:
 
 	void onError();
 
-	love::Data *code;
+	Object::StrongRef<love::Data> code;
 	std::string name;
 	std::string error;
 

+ 4 - 10
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()

+ 1 - 1
src/modules/window/sdl/Window.h

@@ -114,7 +114,7 @@ private:
 		int width;
 		int height;
 		WindowSettings settings;
-		love::image::ImageData *icon;
+		Object::StrongRef<love::image::ImageData> icon;
 
 	} curMode;