Browse Source

Merged default into minor

--HG--
branch : minor
Alex Szpakowski 11 years ago
parent
commit
aa05664d4c
42 changed files with 640 additions and 356 deletions
  1. 19 13
      src/common/Module.cpp
  2. 38 9
      src/common/Module.h
  3. 3 3
      src/modules/audio/Audio.h
  4. 29 27
      src/modules/audio/wrap_Audio.cpp
  5. 3 0
      src/modules/event/Event.h
  6. 5 5
      src/modules/event/sdl/Event.cpp
  7. 9 8
      src/modules/event/sdl/wrap_Event.cpp
  8. 41 15
      src/modules/filesystem/physfs/Filesystem.cpp
  9. 18 0
      src/modules/filesystem/physfs/Filesystem.h
  10. 65 42
      src/modules/filesystem/wrap_Filesystem.cpp
  11. 3 0
      src/modules/filesystem/wrap_Filesystem.h
  12. 5 0
      src/modules/font/Font.h
  13. 7 6
      src/modules/font/freetype/wrap_Font.cpp
  14. 3 0
      src/modules/graphics/Graphics.h
  15. 8 5
      src/modules/graphics/opengl/Graphics.cpp
  16. 76 75
      src/modules/graphics/opengl/wrap_Graphics.cpp
  17. 3 3
      src/modules/image/Image.h
  18. 6 5
      src/modules/image/wrap_Image.cpp
  19. 3 0
      src/modules/joystick/JoystickModule.h
  20. 10 9
      src/modules/joystick/wrap_JoystickModule.cpp
  21. 3 0
      src/modules/keyboard/Keyboard.h
  22. 7 6
      src/modules/keyboard/wrap_Keyboard.cpp
  23. 6 0
      src/modules/math/MathModule.h
  24. 3 0
      src/modules/mouse/Mouse.h
  25. 18 17
      src/modules/mouse/wrap_Mouse.cpp
  26. 1 0
      src/modules/physics/box2d/Physics.h
  27. 26 25
      src/modules/physics/box2d/wrap_Physics.cpp
  28. 3 3
      src/modules/sound/Sound.h
  29. 6 5
      src/modules/sound/wrap_Sound.cpp
  30. 3 0
      src/modules/system/System.h
  31. 8 7
      src/modules/system/wrap_System.cpp
  32. 1 1
      src/modules/thread/LuaThread.cpp
  33. 1 0
      src/modules/thread/ThreadModule.h
  34. 6 5
      src/modules/thread/wrap_ThreadModule.cpp
  35. 3 3
      src/modules/timer/Timer.h
  36. 9 8
      src/modules/timer/wrap_Timer.cpp
  37. 5 5
      src/modules/window/Window.cpp
  38. 27 9
      src/modules/window/Window.h
  39. 62 15
      src/modules/window/sdl/Window.cpp
  40. 4 1
      src/modules/window/sdl/Window.h
  41. 83 21
      src/modules/window/wrap_Window.cpp
  42. 1 0
      src/modules/window/wrap_Window.h

+ 19 - 13
src/common/Module.cpp

@@ -58,6 +58,8 @@ namespace
 namespace love
 namespace love
 {
 {
 
 
+Module *Module::instances[] = {};
+
 Module::~Module()
 Module::~Module()
 {
 {
 	ModuleRegistry &registry = registryInstance();
 	ModuleRegistry &registry = registryInstance();
@@ -72,6 +74,13 @@ Module::~Module()
 		}
 		}
 	}
 	}
 
 
+	// Same deal with Module::getModuleType().
+	for (int i = 0; i < (int) M_MAX_ENUM; i++)
+	{
+		if (instances[i] == this)
+			instances[i] = nullptr;
+	}
+
 	freeEmptyRegistry();
 	freeEmptyRegistry();
 }
 }
 
 
@@ -94,6 +103,16 @@ void Module::registerInstance(Module *instance)
 	}
 	}
 
 
 	registry.insert(make_pair(name, instance));
 	registry.insert(make_pair(name, instance));
+
+	ModuleType moduletype = instance->getModuleType();
+
+	if (instances[moduletype] != nullptr)
+	{
+		printf("Warning: overwriting module instance %s with new instance %s\n",
+			   instances[moduletype]->getName(), instance->getName());
+	}
+
+	instances[moduletype] = instance;
 }
 }
 
 
 Module *Module::getInstance(const std::string &name)
 Module *Module::getInstance(const std::string &name)
@@ -108,17 +127,4 @@ Module *Module::getInstance(const std::string &name)
 	return it->second;
 	return it->second;
 }
 }
 
 
-Module *Module::findInstance(const std::string &name)
-{
-	ModuleRegistry &registry = registryInstance();
-
-	for (auto it = registry.begin(); it != registry.end(); ++it)
-	{
-		if (it->first.find(name) == 0)
-			return it->second;
-	}
-
-	return nullptr;
-}
-
 } // love
 } // love

+ 38 - 9
src/common/Module.h

@@ -34,11 +34,34 @@ class Module : public Object
 {
 {
 public:
 public:
 
 
-	/**
-	 * Destructor.
-	 **/
+	enum ModuleType
+	{
+		M_AUDIO,
+		M_EVENT,
+		M_FILESYSTEM,
+		M_FONT,
+		M_GRAPHICS,
+		M_IMAGE,
+		M_JOYSTICK,
+		M_KEYBOARD,
+		M_MATH,
+		M_MOUSE,
+		M_PHYSICS,
+		M_SOUND,
+		M_SYSTEM,
+		M_THREAD,
+		M_TIMER,
+		M_WINDOW,
+		M_MAX_ENUM
+	};
+
 	virtual ~Module();
 	virtual ~Module();
 
 
+    /**
+     * Gets the base type of the module.
+     **/
+	virtual ModuleType getModuleType() const = 0;
+
 	/**
 	/**
 	 * Gets the name of the module. This is used in case of errors
 	 * Gets the name of the module. This is used in case of errors
 	 * and other messages.
 	 * and other messages.
@@ -63,13 +86,19 @@ public:
 	static Module *getInstance(const std::string &name);
 	static Module *getInstance(const std::string &name);
 
 
 	/**
 	/**
-	 * Find the first module instance from the internal registry whose name
-	 * starts with the supplied name. May return NULL if module is not
-	 * registered or the supplied name is not part of any module name.
-	 * @param name The partial name of the module.
-	 * @return Module instance or NULL if the module is not registered.
+	 * Retrieve module instance from the internal registry using the base
+	 * module type. May return null if the module is not registered.
+	 * @param type The base type of the module.
 	 **/
 	 **/
-	static Module *findInstance(const std::string &name);
+	template <typename T>
+	static T *getInstance(ModuleType type)
+	{
+		return (T *) instances[type];
+	}
+
+private:
+
+	static Module *instances[M_MAX_ENUM];
 
 
 }; // Module
 }; // Module
 
 

+ 3 - 3
src/modules/audio/Audio.h

@@ -64,11 +64,11 @@ public:
 	static bool getConstant(const char *in, DistanceModel &out);
 	static bool getConstant(const char *in, DistanceModel &out);
 	static bool getConstant(DistanceModel in, const char  *&out);
 	static bool getConstant(DistanceModel in, const char  *&out);
 
 
-	/**
-	 * Destructor.
-	 **/
 	virtual ~Audio() {}
 	virtual ~Audio() {}
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_AUDIO; }
+
 	virtual Source *newSource(love::sound::Decoder *decoder) = 0;
 	virtual Source *newSource(love::sound::Decoder *decoder) = 0;
 	virtual Source *newSource(love::sound::SoundData *soundData) = 0;
 	virtual Source *newSource(love::sound::SoundData *soundData) = 0;
 
 

+ 29 - 27
src/modules/audio/wrap_Audio.cpp

@@ -31,11 +31,11 @@ namespace love
 namespace audio
 namespace audio
 {
 {
 
 
-static Audio *instance = 0;
+#define instance() (Module::getInstance<Audio>(Module::M_AUDIO))
 
 
 int w_getSourceCount(lua_State *L)
 int w_getSourceCount(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getSourceCount());
+	lua_pushinteger(L, instance()->getSourceCount());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -56,9 +56,9 @@ int w_newSource(lua_State *L)
 	Source *t = 0;
 	Source *t = 0;
 
 
 	if (luax_istype(L, 1, SOUND_SOUND_DATA_T))
 	if (luax_istype(L, 1, SOUND_SOUND_DATA_T))
-		t = instance->newSource(luax_totype<love::sound::SoundData>(L, 1, "SoundData", SOUND_SOUND_DATA_T));
+		t = instance()->newSource(luax_totype<love::sound::SoundData>(L, 1, "SoundData", SOUND_SOUND_DATA_T));
 	else if (luax_istype(L, 1, SOUND_DECODER_T))
 	else if (luax_istype(L, 1, SOUND_DECODER_T))
-		t = instance->newSource(luax_totype<love::sound::Decoder>(L, 1, "Decoder", SOUND_DECODER_T));
+		t = instance()->newSource(luax_totype<love::sound::Decoder>(L, 1, "Decoder", SOUND_DECODER_T));
 
 
 	if (t)
 	if (t)
 	{
 	{
@@ -72,7 +72,7 @@ int w_newSource(lua_State *L)
 int w_play(lua_State *L)
 int w_play(lua_State *L)
 {
 {
 	Source *s = luax_checksource(L, 1);
 	Source *s = luax_checksource(L, 1);
-	luax_pushboolean(L, instance->play(s));
+	luax_pushboolean(L, instance()->play(s));
 	return 1;
 	return 1;
 }
 }
 
 
@@ -80,7 +80,7 @@ int w_stop(lua_State *L)
 {
 {
 	if (lua_gettop(L) == 0)
 	if (lua_gettop(L) == 0)
 	{
 	{
-		instance->stop();
+		instance()->stop();
 	}
 	}
 	else
 	else
 	{
 	{
@@ -94,7 +94,7 @@ int w_pause(lua_State *L)
 {
 {
 	if (lua_gettop(L) == 0)
 	if (lua_gettop(L) == 0)
 	{
 	{
-		instance->pause();
+		instance()->pause();
 	}
 	}
 	else
 	else
 	{
 	{
@@ -109,7 +109,7 @@ int w_resume(lua_State *L)
 {
 {
 	if (lua_gettop(L) == 0)
 	if (lua_gettop(L) == 0)
 	{
 	{
-		instance->resume();
+		instance()->resume();
 	}
 	}
 	else
 	else
 	{
 	{
@@ -123,7 +123,7 @@ int w_rewind(lua_State *L)
 {
 {
 	if (lua_gettop(L) == 0)
 	if (lua_gettop(L) == 0)
 	{
 	{
-		instance->rewind();
+		instance()->rewind();
 	}
 	}
 	else
 	else
 	{
 	{
@@ -136,13 +136,13 @@ int w_rewind(lua_State *L)
 int w_setVolume(lua_State *L)
 int w_setVolume(lua_State *L)
 {
 {
 	float v = (float)luaL_checknumber(L, 1);
 	float v = (float)luaL_checknumber(L, 1);
-	instance->setVolume(v);
+	instance()->setVolume(v);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getVolume(lua_State *L)
 int w_getVolume(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getVolume());
+	lua_pushnumber(L, instance()->getVolume());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -152,14 +152,14 @@ int w_setPosition(lua_State *L)
 	v[0] = (float)luaL_checknumber(L, 1);
 	v[0] = (float)luaL_checknumber(L, 1);
 	v[1] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 2);
 	v[2] = (float)luaL_optnumber(L, 3, 0);
 	v[2] = (float)luaL_optnumber(L, 3, 0);
-	instance->setPosition(v);
+	instance()->setPosition(v);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getPosition(lua_State *L)
 int w_getPosition(lua_State *L)
 {
 {
 	float v[3];
 	float v[3];
-	instance->getPosition(v);
+	instance()->getPosition(v);
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
 	lua_pushnumber(L, v[2]);
@@ -175,14 +175,14 @@ int w_setOrientation(lua_State *L)
 	v[3] = (float)luaL_checknumber(L, 4);
 	v[3] = (float)luaL_checknumber(L, 4);
 	v[4] = (float)luaL_checknumber(L, 5);
 	v[4] = (float)luaL_checknumber(L, 5);
 	v[5] = (float)luaL_checknumber(L, 6);
 	v[5] = (float)luaL_checknumber(L, 6);
-	instance->setOrientation(v);
+	instance()->setOrientation(v);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getOrientation(lua_State *L)
 int w_getOrientation(lua_State *L)
 {
 {
 	float v[6];
 	float v[6];
-	instance->getOrientation(v);
+	instance()->getOrientation(v);
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
 	lua_pushnumber(L, v[2]);
@@ -198,14 +198,14 @@ int w_setVelocity(lua_State *L)
 	v[0] = (float)luaL_checknumber(L, 1);
 	v[0] = (float)luaL_checknumber(L, 1);
 	v[1] = (float)luaL_checknumber(L, 2);
 	v[1] = (float)luaL_checknumber(L, 2);
 	v[2] = (float)luaL_optnumber(L, 3, 0);
 	v[2] = (float)luaL_optnumber(L, 3, 0);
-	instance->setVelocity(v);
+	instance()->setVelocity(v);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getVelocity(lua_State *L)
 int w_getVelocity(lua_State *L)
 {
 {
 	float v[3];
 	float v[3];
-	instance->getVelocity(v);
+	instance()->getVelocity(v);
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[0]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[1]);
 	lua_pushnumber(L, v[2]);
 	lua_pushnumber(L, v[2]);
@@ -214,13 +214,13 @@ int w_getVelocity(lua_State *L)
 
 
 int w_record(lua_State *)
 int w_record(lua_State *)
 {
 {
-	instance->record();
+	instance()->record();
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getRecordedData(lua_State *L)
 int w_getRecordedData(lua_State *L)
 {
 {
-	love::sound::SoundData *sd = instance->getRecordedData();
+	love::sound::SoundData *sd = instance()->getRecordedData();
 	if (!sd)
 	if (!sd)
 		lua_pushnil(L);
 		lua_pushnil(L);
 	else
 	else
@@ -232,18 +232,18 @@ int w_stopRecording(lua_State *L)
 {
 {
 	if (luax_optboolean(L, 1, true))
 	if (luax_optboolean(L, 1, true))
 	{
 	{
-		love::sound::SoundData *sd = instance->stopRecording(true);
+		love::sound::SoundData *sd = instance()->stopRecording(true);
 		if (!sd) lua_pushnil(L);
 		if (!sd) lua_pushnil(L);
 		else luax_pushtype(L, "SoundData", SOUND_SOUND_DATA_T, sd);
 		else luax_pushtype(L, "SoundData", SOUND_SOUND_DATA_T, sd);
 		return 1;
 		return 1;
 	}
 	}
-	instance->stopRecording(false);
+	instance()->stopRecording(false);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_canRecord(lua_State *L)
 int w_canRecord(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->canRecord());
+	luax_pushboolean(L, instance()->canRecord());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -253,13 +253,13 @@ int w_setDistanceModel(lua_State *L)
 	Audio::DistanceModel distanceModel;
 	Audio::DistanceModel distanceModel;
 	if (!Audio::getConstant(modelStr, distanceModel))
 	if (!Audio::getConstant(modelStr, distanceModel))
 		return luaL_error(L, "Invalid distance model: %s", modelStr);
 		return luaL_error(L, "Invalid distance model: %s", modelStr);
-	instance->setDistanceModel(distanceModel);
+	instance()->setDistanceModel(distanceModel);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getDistanceModel(lua_State *L)
 int w_getDistanceModel(lua_State *L)
 {
 {
-	Audio::DistanceModel distanceModel = instance->getDistanceModel();
+	Audio::DistanceModel distanceModel = instance()->getDistanceModel();
 	const char *modelStr;
 	const char *modelStr;
 	if (!Audio::getConstant(distanceModel, modelStr))
 	if (!Audio::getConstant(distanceModel, modelStr))
 		return 0;
 		return 0;
@@ -301,8 +301,10 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_audio(lua_State *L)
 extern "C" int luaopen_love_audio(lua_State *L)
 {
 {
+	Audio *instance = instance();
+
 #ifdef LOVE_ENABLE_AUDIO_OPENAL
 #ifdef LOVE_ENABLE_AUDIO_OPENAL
-	if (instance == 0)
+	if (instance == nullptr)
 	{
 	{
 		// Try OpenAL first.
 		// Try OpenAL first.
 		try
 		try
@@ -319,7 +321,7 @@ extern "C" int luaopen_love_audio(lua_State *L)
 #endif
 #endif
 
 
 #ifdef LOVE_ENABLE_AUDIO_NULL
 #ifdef LOVE_ENABLE_AUDIO_NULL
-	if (instance == 0)
+	if (instance == nullptr)
 	{
 	{
 		// Fall back to nullaudio.
 		// Fall back to nullaudio.
 		try
 		try
@@ -333,7 +335,7 @@ extern "C" int luaopen_love_audio(lua_State *L)
 	}
 	}
 #endif
 #endif
 
 
-	if (instance == 0)
+	if (instance == nullptr)
 		return luaL_error(L, "Could not open any audio module.");
 		return luaL_error(L, "Could not open any audio module.");
 
 
 	WrappedModule w;
 	WrappedModule w;

+ 3 - 0
src/modules/event/Event.h

@@ -58,6 +58,9 @@ public:
 	Event();
 	Event();
 	virtual ~Event();
 	virtual ~Event();
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_EVENT; }
+
 	void push(Message *msg);
 	void push(Message *msg);
 	bool poll(Message *&msg);
 	bool poll(Message *&msg);
 	virtual void clear();
 	virtual void clear();

+ 5 - 5
src/modules/event/sdl/Event.cpp

@@ -44,7 +44,7 @@ static void windowToPixelCoords(int *x, int *y)
 {
 {
 	double scale = 1.0;
 	double scale = 1.0;
 
 
-	window::Window *window = (window::Window *) Module::findInstance("love.window.");
+	window::Window *window = Module::getInstance<window::Window>(Module::M_WINDOW);
 	if (window != nullptr)
 	if (window != nullptr)
 		scale = window->getPixelScale();
 		scale = window->getPixelScale();
 
 
@@ -129,7 +129,7 @@ Message *Event::convert(const SDL_Event &e) const
 	case SDL_KEYDOWN:
 	case SDL_KEYDOWN:
 		if (e.key.repeat)
 		if (e.key.repeat)
 		{
 		{
-			kb = (love::keyboard::Keyboard *) Module::findInstance("love.keyboard.");
+			kb = Module::getInstance<love::keyboard::Keyboard>(Module::M_KEYBOARD);
 			if (kb && !kb->hasKeyRepeat())
 			if (kb && !kb->hasKeyRepeat())
 				break;
 				break;
 		}
 		}
@@ -232,7 +232,7 @@ Message *Event::convert(const SDL_Event &e) const
 
 
 Message *Event::convertJoystickEvent(const SDL_Event &e) const
 Message *Event::convertJoystickEvent(const SDL_Event &e) const
 {
 {
-	joystick::JoystickModule *joymodule = (joystick::JoystickModule *) Module::findInstance("love.joystick.");
+	joystick::JoystickModule *joymodule = Module::getInstance<joystick::JoystickModule>(Module::M_JOYSTICK);
 	if (!joymodule)
 	if (!joymodule)
 		return 0;
 		return 0;
 
 
@@ -403,7 +403,7 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const
 		arg1->release();
 		arg1->release();
 		break;
 		break;
 	case SDL_WINDOWEVENT_RESIZED:
 	case SDL_WINDOWEVENT_RESIZED:
-		win = (window::Window *) Module::findInstance("love.window.");
+		win = Module::getInstance<window::Window>(Module::M_WINDOW);
 		if (win)
 		if (win)
 		{
 		{
 			int px_w = e.window.data1;
 			int px_w = e.window.data1;
@@ -418,7 +418,7 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const
 
 
 			win->onWindowResize(e.window.data1, e.window.data2);
 			win->onWindowResize(e.window.data1, e.window.data2);
 
 
-			graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
+			graphics::Graphics *gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
 			if (gfx)
 			if (gfx)
 				gfx->setViewportSize(px_w, px_h);
 				gfx->setViewportSize(px_w, px_h);
 
 

+ 9 - 8
src/modules/event/sdl/wrap_Event.cpp

@@ -33,13 +33,13 @@ namespace event
 namespace sdl
 namespace sdl
 {
 {
 
 
-static Event *instance = 0;
+#define instance() (Module::getInstance<Event>(Module::M_EVENT))
 
 
 static int poll_i(lua_State *L)
 static int poll_i(lua_State *L)
 {
 {
 	Message *m;
 	Message *m;
 
 
-	while (instance->poll(m))
+	while (instance()->poll(m))
 	{
 	{
 		int args = m->toLua(L);
 		int args = m->toLua(L);
 		m->release();
 		m->release();
@@ -52,7 +52,7 @@ static int poll_i(lua_State *L)
 
 
 int w_pump(lua_State *)
 int w_pump(lua_State *)
 {
 {
-	instance->pump();
+	instance()->pump();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -66,7 +66,7 @@ int w_wait(lua_State *L)
 {
 {
 	Message *m;
 	Message *m;
 
 
-	if ((m = instance->wait()))
+	if ((m = instance()->wait()))
 	{
 	{
 		int args = m->toLua(L);
 		int args = m->toLua(L);
 		m->release();
 		m->release();
@@ -86,7 +86,7 @@ int w_push(lua_State *L)
 	if (!success)
 	if (!success)
 		return 1;
 		return 1;
 
 
-	instance->push(m);
+	instance()->push(m);
 	m->release();
 	m->release();
 
 
 	return 1;
 	return 1;
@@ -94,14 +94,14 @@ int w_push(lua_State *L)
 
 
 int w_clear(lua_State *)
 int w_clear(lua_State *)
 {
 {
-	instance->clear();
+	instance()->clear();
 	return 0;
 	return 0;
 }
 }
 
 
 int w_quit(lua_State *L)
 int w_quit(lua_State *L)
 {
 {
 	Message *m = new Message("quit");
 	Message *m = new Message("quit");
-	instance->push(m);
+	instance()->push(m);
 	m->release();
 	m->release();
 	luax_pushboolean(L, true);
 	luax_pushboolean(L, true);
 	return 1;
 	return 1;
@@ -121,7 +121,8 @@ static const luaL_Reg functions[] =
 
 
 extern "C" int luaopen_love_event(lua_State *L)
 extern "C" int luaopen_love_event(lua_State *L)
 {
 {
-	if (instance == 0)
+	Event *instance = instance();
+	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new Event(); });
 		luax_catchexcept(L, [&](){ instance = new Event(); });
 	}
 	}

+ 41 - 15
src/modules/filesystem/physfs/Filesystem.cpp

@@ -21,6 +21,7 @@
 #include "common/config.h"
 #include "common/config.h"
 
 
 #include <iostream>
 #include <iostream>
+#include <sstream>
 
 
 #include "common/utf8.h"
 #include "common/utf8.h"
 #include "common/b64.h"
 #include "common/b64.h"
@@ -47,6 +48,21 @@ namespace
 	{
 	{
 		return input.substr(getDriveDelim(input)+1);
 		return input.substr(getDriveDelim(input)+1);
 	}
 	}
+
+	std::string normalize(const std::string &input)
+	{
+		std::stringstream out;
+		bool seenSep = false, isSep = false;
+		for (size_t i = 0; i < input.size(); ++i)
+		{
+			isSep = (input[i] == LOVE_PATH_SEPARATOR[0]);
+			if (!isSep || !seenSep)
+				out << input[i];
+			seenSep = isSep;
+		}
+
+		return out.str();
+	}
 }
 }
 
 
 namespace love
 namespace love
@@ -116,6 +132,8 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath)
 	else
 	else
 		save_path_full += save_path_relative;
 		save_path_full += save_path_relative;
 
 
+	save_path_full = normalize(save_path_full);
+
 	// We now have something like:
 	// We now have something like:
 	// save_identity: game
 	// save_identity: game
 	// save_path_relative: ./LOVE/game
 	// save_path_relative: ./LOVE/game
@@ -354,40 +372,33 @@ const char *Filesystem::getWorkingDirectory()
 
 
 std::string Filesystem::getUserDirectory()
 std::string Filesystem::getUserDirectory()
 {
 {
-	return std::string(PHYSFS_getUserDir());
+	static std::string userDir = normalize(PHYSFS_getUserDir());
+	return userDir;
 }
 }
 
 
 std::string Filesystem::getAppdataDirectory()
 std::string Filesystem::getAppdataDirectory()
 {
 {
-#ifdef LOVE_WINDOWS
 	if (appdata.empty())
 	if (appdata.empty())
 	{
 	{
+#ifdef LOVE_WINDOWS
 		wchar_t *w_appdata = _wgetenv(L"APPDATA");
 		wchar_t *w_appdata = _wgetenv(L"APPDATA");
 		appdata = to_utf8(w_appdata);
 		appdata = to_utf8(w_appdata);
 		replace_char(appdata, '\\', '/');
 		replace_char(appdata, '\\', '/');
-	}
-	return appdata;
 #elif defined(LOVE_MACOSX)
 #elif defined(LOVE_MACOSX)
-	if (appdata.empty())
-	{
 		std::string udir = getUserDirectory();
 		std::string udir = getUserDirectory();
 		udir.append("/Library/Application Support");
 		udir.append("/Library/Application Support");
-		appdata = udir;
-	}
-	return appdata;
+		appdata = normalize(udir);
 #elif defined(LOVE_LINUX)
 #elif defined(LOVE_LINUX)
-	if (appdata.empty())
-	{
 		char *xdgdatahome = getenv("XDG_DATA_HOME");
 		char *xdgdatahome = getenv("XDG_DATA_HOME");
 		if (!xdgdatahome)
 		if (!xdgdatahome)
-			appdata = std::string(getUserDirectory()) + "/.local/share/";
+			appdata = normalize(std::string(getUserDirectory()) + "/.local/share/");
 		else
 		else
 			appdata = xdgdatahome;
 			appdata = xdgdatahome;
-	}
-	return appdata;
 #else
 #else
-	return getUserDirectory();
+		appdata = getUserDirectory();
 #endif
 #endif
+	}
+	return appdata;
 }
 }
 
 
 
 
@@ -645,6 +656,21 @@ int64 Filesystem::getSize(const char *filename) const
 	return size;
 	return size;
 }
 }
 
 
+void Filesystem::setSymlinksEnabled(bool enable)
+{
+	PHYSFS_permitSymbolicLinks(enable ? 1 : 0);
+}
+
+bool Filesystem::areSymlinksEnabled() const
+{
+	return PHYSFS_symbolicLinksPermitted() != 0;
+}
+
+bool Filesystem::isSymlink(const char *filename) const
+{
+	return PHYSFS_isSymbolicLink(filename) != 0;
+}
+
 } // physfs
 } // physfs
 } // filesystem
 } // filesystem
 } // love
 } // love

+ 18 - 0
src/modules/filesystem/physfs/Filesystem.h

@@ -80,6 +80,8 @@ public:
 	Filesystem();
 	Filesystem();
 	virtual ~Filesystem();
 	virtual ~Filesystem();
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_FILESYSTEM; }
 	const char *getName() const;
 	const char *getName() const;
 
 
 	void init(const char *arg0);
 	void init(const char *arg0);
@@ -237,6 +239,22 @@ public:
 	 **/
 	 **/
 	int64 getSize(const char *filename) const;
 	int64 getSize(const char *filename) const;
 
 
+	/**
+	 * Enable or disable symbolic link support in love.filesystem.
+	 **/
+	void setSymlinksEnabled(bool enable);
+
+	/**
+	 * Gets whether symbolic link support is enabled.
+	 **/
+	bool areSymlinksEnabled() const;
+
+	/**
+	 * Gets whether a filepath is actually a symlink.
+	 * Always returns false if symlinks are not enabled.
+	 **/
+	bool isSymlink(const char *filename) const;
+
 	/**
 	/**
 	 * Text file line-reading iterator function used and
 	 * Text file line-reading iterator function used and
 	 * pushed on the Lua stack by love.filesystem.lines
 	 * pushed on the Lua stack by love.filesystem.lines

+ 65 - 42
src/modules/filesystem/wrap_Filesystem.cpp

@@ -32,20 +32,20 @@ namespace love
 {
 {
 namespace filesystem
 namespace filesystem
 {
 {
-
-static physfs::Filesystem *instance = 0;
+	
+#define instance() (Module::getInstance<physfs::Filesystem>(Module::M_FILESYSTEM))
 
 
 bool hack_setupWriteDirectory()
 bool hack_setupWriteDirectory()
 {
 {
-	if (instance != 0)
-		return instance->setupWriteDirectory();
+	if (instance() != 0)
+		return instance()->setupWriteDirectory();
 	return false;
 	return false;
 }
 }
 
 
 int w_init(lua_State *L)
 int w_init(lua_State *L)
 {
 {
 	const char *arg0 = luaL_checkstring(L, 1);
 	const char *arg0 = luaL_checkstring(L, 1);
-	luax_catchexcept(L, [&](){ instance->init(arg0); });
+	luax_catchexcept(L, [&](){ instance()->init(arg0); });
 	return 0;
 	return 0;
 }
 }
 
 
@@ -53,13 +53,13 @@ int w_setFused(lua_State *L)
 {
 {
 	// no error checking needed, everything, even nothing
 	// no error checking needed, everything, even nothing
 	// can be converted to a boolean
 	// can be converted to a boolean
-	instance->setFused(luax_toboolean(L, 1));
+	instance()->setFused(luax_toboolean(L, 1));
 	return 0;
 	return 0;
 }
 }
 
 
 int w_isFused(lua_State *L)
 int w_isFused(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->isFused());
+	luax_pushboolean(L, instance()->isFused());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -68,7 +68,7 @@ int w_setIdentity(lua_State *L)
 	const char *arg = luaL_checkstring(L, 1);
 	const char *arg = luaL_checkstring(L, 1);
 	bool append = luax_optboolean(L, 2, false);
 	bool append = luax_optboolean(L, 2, false);
 
 
-	if (!instance->setIdentity(arg, append))
+	if (!instance()->setIdentity(arg, append))
 		return luaL_error(L, "Could not set write directory.");
 		return luaL_error(L, "Could not set write directory.");
 
 
 	return 0;
 	return 0;
@@ -76,7 +76,7 @@ int w_setIdentity(lua_State *L)
 
 
 int w_getIdentity(lua_State *L)
 int w_getIdentity(lua_State *L)
 {
 {
-	lua_pushstring(L, instance->getIdentity());
+	lua_pushstring(L, instance()->getIdentity());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -84,7 +84,7 @@ int w_setSource(lua_State *L)
 {
 {
 	const char *arg = luaL_checkstring(L, 1);
 	const char *arg = luaL_checkstring(L, 1);
 
 
-	if (!instance->setSource(arg))
+	if (!instance()->setSource(arg))
 		return luaL_error(L, "Could not set source.");
 		return luaL_error(L, "Could not set source.");
 
 
 	return 0;
 	return 0;
@@ -92,7 +92,7 @@ int w_setSource(lua_State *L)
 
 
 int w_getSource(lua_State *L)
 int w_getSource(lua_State *L)
 {
 {
-	lua_pushstring(L, instance->getSource());
+	lua_pushstring(L, instance()->getSource());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -102,7 +102,7 @@ int w_mount(lua_State *L)
 	const char *mountpoint = luaL_checkstring(L, 2);
 	const char *mountpoint = luaL_checkstring(L, 2);
 	bool append = luax_optboolean(L, 3, false);
 	bool append = luax_optboolean(L, 3, false);
 
 
-	luax_pushboolean(L, instance->mount(archive, mountpoint, append));
+	luax_pushboolean(L, instance()->mount(archive, mountpoint, append));
 	return 1;
 	return 1;
 }
 }
 
 
@@ -110,7 +110,7 @@ int w_unmount(lua_State *L)
 {
 {
 	const char *archive = luaL_checkstring(L, 1);
 	const char *archive = luaL_checkstring(L, 1);
 
 
-	luax_pushboolean(L, instance->unmount(archive));
+	luax_pushboolean(L, instance()->unmount(archive));
 	return 1;
 	return 1;
 }
 }
 
 
@@ -128,7 +128,7 @@ int w_newFile(lua_State *L)
 			return luaL_error(L, "Incorrect file open mode: %s", str);
 			return luaL_error(L, "Incorrect file open mode: %s", str);
 	}
 	}
 
 
-	File *t = instance->newFile(filename);
+	File *t = instance()->newFile(filename);
 
 
 	if (mode != File::CLOSED)
 	if (mode != File::CLOSED)
 	{
 	{
@@ -156,7 +156,7 @@ FileData *luax_getfiledata(lua_State *L, int idx)
 	if (lua_isstring(L, idx))
 	if (lua_isstring(L, idx))
 	{
 	{
 		const char *filename = luaL_checkstring(L, idx);
 		const char *filename = luaL_checkstring(L, idx);
-		file = instance->newFile(filename);
+		file = instance()->newFile(filename);
 	}
 	}
 	else if (luax_istype(L, idx, FILESYSTEM_FILE_T))
 	else if (luax_istype(L, idx, FILESYSTEM_FILE_T))
 	{
 	{
@@ -231,10 +231,10 @@ int w_newFileData(lua_State *L)
 	switch (decoder)
 	switch (decoder)
 	{
 	{
 	case FileData::FILE:
 	case FileData::FILE:
-		t = instance->newFileData((void *)str, (int)length, filename);
+		t = instance()->newFileData((void *)str, (int)length, filename);
 		break;
 		break;
 	case FileData::BASE64:
 	case FileData::BASE64:
-		t = instance->newFileData(str, filename);
+		t = instance()->newFileData(str, filename);
 		break;
 		break;
 	default:
 	default:
 		return luaL_error(L, "Invalid FileData decoder: %s", decstr);
 		return luaL_error(L, "Invalid FileData decoder: %s", decstr);
@@ -246,59 +246,59 @@ int w_newFileData(lua_State *L)
 
 
 int w_getWorkingDirectory(lua_State *L)
 int w_getWorkingDirectory(lua_State *L)
 {
 {
-	lua_pushstring(L, instance->getWorkingDirectory());
+	lua_pushstring(L, instance()->getWorkingDirectory());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getUserDirectory(lua_State *L)
 int w_getUserDirectory(lua_State *L)
 {
 {
-	luax_pushstring(L, instance->getUserDirectory());
+	luax_pushstring(L, instance()->getUserDirectory());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getAppdataDirectory(lua_State *L)
 int w_getAppdataDirectory(lua_State *L)
 {
 {
-	luax_pushstring(L, instance->getAppdataDirectory());
+	luax_pushstring(L, instance()->getAppdataDirectory());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getSaveDirectory(lua_State *L)
 int w_getSaveDirectory(lua_State *L)
 {
 {
-	lua_pushstring(L, instance->getSaveDirectory());
+	lua_pushstring(L, instance()->getSaveDirectory());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getSourceBaseDirectory(lua_State *L)
 int w_getSourceBaseDirectory(lua_State *L)
 {
 {
-	luax_pushstring(L, instance->getSourceBaseDirectory());
+	luax_pushstring(L, instance()->getSourceBaseDirectory());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_isDirectory(lua_State *L)
 int w_isDirectory(lua_State *L)
 {
 {
 	const char *arg = luaL_checkstring(L, 1);
 	const char *arg = luaL_checkstring(L, 1);
-	luax_pushboolean(L, instance->isDirectory(arg));
+	luax_pushboolean(L, instance()->isDirectory(arg));
 	return 1;
 	return 1;
 }
 }
 
 
 int w_isFile(lua_State *L)
 int w_isFile(lua_State *L)
 {
 {
 	const char *arg = luaL_checkstring(L, 1);
 	const char *arg = luaL_checkstring(L, 1);
-	luax_pushboolean(L, instance->isFile(arg));
+	luax_pushboolean(L, instance()->isFile(arg));
 	return 1;
 	return 1;
 }
 }
 
 
 int w_createDirectory(lua_State *L)
 int w_createDirectory(lua_State *L)
 {
 {
 	const char *arg = luaL_checkstring(L, 1);
 	const char *arg = luaL_checkstring(L, 1);
-	luax_pushboolean(L, instance->createDirectory(arg));
+	luax_pushboolean(L, instance()->createDirectory(arg));
 	return 1;
 	return 1;
 }
 }
 
 
 int w_remove(lua_State *L)
 int w_remove(lua_State *L)
 {
 {
 	const char *arg = luaL_checkstring(L, 1);
 	const char *arg = luaL_checkstring(L, 1);
-	luax_pushboolean(L, instance->remove(arg));
+	luax_pushboolean(L, instance()->remove(arg));
 	return 1;
 	return 1;
 }
 }
 
 
@@ -310,7 +310,7 @@ int w_read(lua_State *L)
 	Data *data = 0;
 	Data *data = 0;
 	try
 	try
 	{
 	{
-		data = instance->read(filename, len);
+		data = instance()->read(filename, len);
 	}
 	}
 	catch (love::Exception &e)
 	catch (love::Exception &e)
 	{
 	{
@@ -356,9 +356,9 @@ static int w_write_or_append(lua_State *L, File::Mode mode)
 	try
 	try
 	{
 	{
 		if (mode == File::APPEND)
 		if (mode == File::APPEND)
-			instance->append(filename, (const void *) input, len);
+			instance()->append(filename, (const void *) input, len);
 		else
 		else
-			instance->write(filename, (const void *) input, len);
+			instance()->write(filename, (const void *) input, len);
 	}
 	}
 	catch (love::Exception &e)
 	catch (love::Exception &e)
 	{
 	{
@@ -381,7 +381,7 @@ int w_append(lua_State *L)
 
 
 int w_getDirectoryItems(lua_State *L)
 int w_getDirectoryItems(lua_State *L)
 {
 {
-	return instance->getDirectoryItems(L);
+	return instance()->getDirectoryItems(L);
 }
 }
 
 
 int w_lines(lua_State *L)
 int w_lines(lua_State *L)
@@ -390,7 +390,7 @@ int w_lines(lua_State *L)
 
 
 	if (lua_isstring(L, 1))
 	if (lua_isstring(L, 1))
 	{
 	{
-		file = instance->newFile(lua_tostring(L, 1));
+		file = instance()->newFile(lua_tostring(L, 1));
 		bool success = false;
 		bool success = false;
 
 
 		luax_catchexcept(L, [&](){ success = file->open(File::READ); });
 		luax_catchexcept(L, [&](){ success = file->open(File::READ); });
@@ -414,7 +414,7 @@ int w_load(lua_State *L)
 	Data *data = 0;
 	Data *data = 0;
 	try
 	try
 	{
 	{
-		data = instance->read(filename.c_str());
+		data = instance()->read(filename.c_str());
 	}
 	}
 	catch (love::Exception &e)
 	catch (love::Exception &e)
 	{
 	{
@@ -444,7 +444,7 @@ int w_getLastModified(lua_State *L)
 	int64 time = 0;
 	int64 time = 0;
 	try
 	try
 	{
 	{
-		time = instance->getLastModified(filename);
+		time = instance()->getLastModified(filename);
 	}
 	}
 	catch (love::Exception &e)
 	catch (love::Exception &e)
 	{
 	{
@@ -462,7 +462,7 @@ int w_getSize(lua_State *L)
 	int64 size = -1;
 	int64 size = -1;
 	try
 	try
 	{
 	{
-		size = instance->getSize(filename);
+		size = instance()->getSize(filename);
 	}
 	}
 	catch (love::Exception &e)
 	catch (love::Exception &e)
 	{
 	{
@@ -479,6 +479,25 @@ int w_getSize(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
+int w_setSymlinksEnabled(lua_State *L)
+{
+	instance()->setSymlinksEnabled(luax_toboolean(L, 1));
+	return 0;
+}
+
+int w_areSymlinksEnabled(lua_State *L)
+{
+	luax_pushboolean(L, instance()->areSymlinksEnabled());
+	return 1;
+}
+
+int w_isSymlink(lua_State *L)
+{
+	const char *filename = luaL_checkstring(L, 1);
+	luax_pushboolean(L, instance()->isSymlink(filename));
+	return 1;
+}
+
 int loader(lua_State *L)
 int loader(lua_State *L)
 {
 {
 	const char *filename = lua_tostring(L, -1);
 	const char *filename = lua_tostring(L, -1);
@@ -497,7 +516,7 @@ int loader(lua_State *L)
 	}
 	}
 
 
 	// Check whether file exists.
 	// Check whether file exists.
-	if (instance->isFile(tmp.c_str()))
+	if (instance()->isFile(tmp.c_str()))
 	{
 	{
 		lua_pop(L, 1);
 		lua_pop(L, 1);
 		lua_pushstring(L, tmp.c_str());
 		lua_pushstring(L, tmp.c_str());
@@ -515,10 +534,10 @@ int loader(lua_State *L)
 		}
 		}
 	}
 	}
 
 
-	if (instance->isDirectory(tmp.c_str()))
+	if (instance()->isDirectory(tmp.c_str()))
 	{
 	{
 		tmp += "/init.lua";
 		tmp += "/init.lua";
-		if (instance->isFile(tmp.c_str()))
+		if (instance()->isFile(tmp.c_str()))
 		{
 		{
 			lua_pop(L, 1);
 			lua_pop(L, 1);
 			lua_pushstring(L, tmp.c_str());
 			lua_pushstring(L, tmp.c_str());
@@ -563,15 +582,15 @@ int extloader(lua_State *L)
 	void *handle = nullptr;
 	void *handle = nullptr;
 
 
 	// If the game is fused, try looking for the DLL in the game's read paths.
 	// If the game is fused, try looking for the DLL in the game's read paths.
-	if (instance->isFused())
+	if (instance()->isFused())
 	{
 	{
 		try
 		try
 		{
 		{
-			std::string dir = instance->getRealDirectory(tokenized_name.c_str());
+			std::string dir = instance()->getRealDirectory(tokenized_name.c_str());
 
 
 			// We don't want to look in the game's source, because it can be a
 			// We don't want to look in the game's source, because it can be a
 			// zip sometimes and a folder other times.
 			// zip sometimes and a folder other times.
-			if (dir.find(instance->getSource()) == std::string::npos)
+			if (dir.find(instance()->getSource()) == std::string::npos)
 				handle = SDL_LoadObject((dir + LOVE_PATH_SEPARATOR + tokenized_name).c_str());
 				handle = SDL_LoadObject((dir + LOVE_PATH_SEPARATOR + tokenized_name).c_str());
 		}
 		}
 		catch (love::Exception &)
 		catch (love::Exception &)
@@ -582,7 +601,7 @@ int extloader(lua_State *L)
 
 
 	if (!handle)
 	if (!handle)
 	{
 	{
-		std::string path = std::string(instance->getAppdataDirectory()) + LOVE_PATH_SEPARATOR LOVE_APPDATA_FOLDER LOVE_PATH_SEPARATOR + tokenized_name;
+		std::string path = std::string(instance()->getAppdataDirectory()) + LOVE_PATH_SEPARATOR LOVE_APPDATA_FOLDER LOVE_PATH_SEPARATOR + tokenized_name;
 		handle = SDL_LoadObject(path.c_str());
 		handle = SDL_LoadObject(path.c_str());
 	}
 	}
 
 
@@ -637,6 +656,9 @@ static const luaL_Reg functions[] =
 	{ "load", w_load },
 	{ "load", w_load },
 	{ "getLastModified", w_getLastModified },
 	{ "getLastModified", w_getLastModified },
 	{ "getSize", w_getSize },
 	{ "getSize", w_getSize },
+	{ "setSymlinksEnabled", w_setSymlinksEnabled },
+	{ "areSymlinksEnabled", w_areSymlinksEnabled },
+	{ "isSymlink", w_isSymlink },
 	{ "newFileData", w_newFileData },
 	{ "newFileData", w_newFileData },
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
@@ -650,7 +672,8 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_filesystem(lua_State *L)
 extern "C" int luaopen_love_filesystem(lua_State *L)
 {
 {
-	if (instance == 0)
+	physfs::Filesystem *instance = instance();
+	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new physfs::Filesystem(); });
 		luax_catchexcept(L, [&](){ instance = new physfs::Filesystem(); });
 	}
 	}

+ 3 - 0
src/modules/filesystem/wrap_Filesystem.h

@@ -70,6 +70,9 @@ int w_lines(lua_State *L);
 int w_load(lua_State *L);
 int w_load(lua_State *L);
 int w_getLastModified(lua_State *L);
 int w_getLastModified(lua_State *L);
 int w_getSize(lua_State *L);
 int w_getSize(lua_State *L);
+int w_setSymlinksEnabled(lua_State *L);
+int w_areSymlinksEnabled(lua_State *L);
+int w_isSymlink(lua_State *L);
 int loader(lua_State *L);
 int loader(lua_State *L);
 int extloader(lua_State *L);
 int extloader(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_filesystem(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_filesystem(lua_State *L);

+ 5 - 0
src/modules/font/Font.h

@@ -40,6 +40,11 @@ class Font : public Module
 
 
 public:
 public:
 
 
+	virtual ~Font() {}
+
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_FONT; }
+
 	virtual Rasterizer *newRasterizer(Data *data, int size) = 0;
 	virtual Rasterizer *newRasterizer(Data *data, int size) = 0;
 	virtual Rasterizer *newRasterizer(love::image::ImageData *data, const std::string &glyphs) = 0;
 	virtual Rasterizer *newRasterizer(love::image::ImageData *data, const std::string &glyphs) = 0;
 	virtual Rasterizer *newRasterizer(love::image::ImageData *data, uint32 *glyphs, int length) = 0;
 	virtual Rasterizer *newRasterizer(love::image::ImageData *data, uint32 *glyphs, int length) = 0;

+ 7 - 6
src/modules/font/freetype/wrap_Font.cpp

@@ -36,7 +36,7 @@ namespace font
 namespace freetype
 namespace freetype
 {
 {
 
 
-static Font *instance = nullptr;
+#define instance() (Module::getInstance<Font>(Module::M_FONT))
 
 
 int w_newRasterizer(lua_State *L)
 int w_newRasterizer(lua_State *L)
 {
 {
@@ -47,14 +47,14 @@ int w_newRasterizer(lua_State *L)
 		love::image::ImageData *d = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
 		love::image::ImageData *d = luax_checktype<love::image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
 		const char *g = luaL_checkstring(L, 2);
 		const char *g = luaL_checkstring(L, 2);
 		std::string glyphs(g);
 		std::string glyphs(g);
-		luax_catchexcept(L, [&](){ t = instance->newRasterizer(d, glyphs); });
+		luax_catchexcept(L, [&](){ t = instance()->newRasterizer(d, glyphs); });
 	}
 	}
 	else if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 	else if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 	{
 	{
 		love::filesystem::FileData *d = love::filesystem::luax_getfiledata(L, 1);
 		love::filesystem::FileData *d = love::filesystem::luax_getfiledata(L, 1);
 		int size = luaL_checkint(L, 2);
 		int size = luaL_checkint(L, 2);
 		luax_catchexcept(L,
 		luax_catchexcept(L,
-			[&]() { t = instance->newRasterizer(d, size); },
+			[&]() { t = instance()->newRasterizer(d, size); },
 			[&]() { d->release(); }
 			[&]() { d->release(); }
 		);
 		);
 	}
 	}
@@ -72,12 +72,12 @@ int w_newGlyphData(lua_State *L)
 	if (lua_type(L, 2) == LUA_TSTRING)
 	if (lua_type(L, 2) == LUA_TSTRING)
 	{
 	{
 		std::string glyph = luax_checkstring(L, 2);
 		std::string glyph = luax_checkstring(L, 2);
-		luax_catchexcept(L, [&](){ t = instance->newGlyphData(r, glyph); });
+		luax_catchexcept(L, [&](){ t = instance()->newGlyphData(r, glyph); });
 	}
 	}
 	else
 	else
 	{
 	{
 		uint32 g = (uint32) luaL_checknumber(L, 2);
 		uint32 g = (uint32) luaL_checknumber(L, 2);
-		t = instance->newGlyphData(r, g);
+		t = instance()->newGlyphData(r, g);
 	}
 	}
 
 
 	luax_pushtype(L, "GlyphData", FONT_GLYPH_DATA_T, t);
 	luax_pushtype(L, "GlyphData", FONT_GLYPH_DATA_T, t);
@@ -101,9 +101,10 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_font(lua_State *L)
 extern "C" int luaopen_love_font(lua_State *L)
 {
 {
+	Font *instance = instance();
 	if (instance == nullptr)
 	if (instance == nullptr)
 	{
 	{
-		luax_catchexcept(L, [](){ instance = new Font(); });
+		luax_catchexcept(L, [&](){ instance = new Font(); });
 	}
 	}
 	else
 	else
 		instance->retain();
 		instance->retain();

+ 3 - 0
src/modules/graphics/Graphics.h

@@ -106,6 +106,9 @@ public:
 
 
 	virtual ~Graphics();
 	virtual ~Graphics();
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_GRAPHICS; }
+
 	/**
 	/**
 	 * Sets the current graphics display viewport dimensions.
 	 * Sets the current graphics display viewport dimensions.
 	 **/
 	 **/

+ 8 - 5
src/modules/graphics/opengl/Graphics.cpp

@@ -46,6 +46,7 @@ namespace opengl
 Graphics::Graphics()
 Graphics::Graphics()
 	: currentFont(0)
 	: currentFont(0)
 	, lineStyle(LINE_SMOOTH)
 	, lineStyle(LINE_SMOOTH)
+	, lineJoin(LINE_JOIN_MITER)
 	, lineWidth(1)
 	, lineWidth(1)
 	, matrixLimit(0)
 	, matrixLimit(0)
 	, userMatrices(0)
 	, userMatrices(0)
@@ -90,7 +91,8 @@ DisplayState Graphics::saveState()
 
 
 	s.blendMode = getBlendMode();
 	s.blendMode = getBlendMode();
 	//get line style
 	//get line style
-	s.lineStyle = lineStyle;
+	s.lineStyle = getLineStyle();
+	s.lineJoin = getLineJoin();
 	//get the point size
 	//get the point size
 	glGetFloatv(GL_POINT_SIZE, &s.pointSize);
 	glGetFloatv(GL_POINT_SIZE, &s.pointSize);
 	//get scissor status
 	//get scissor status
@@ -114,6 +116,7 @@ void Graphics::restoreState(const DisplayState &s)
 	setBlendMode(s.blendMode);
 	setBlendMode(s.blendMode);
 	setLineWidth(lineWidth);
 	setLineWidth(lineWidth);
 	setLineStyle(s.lineStyle);
 	setLineStyle(s.lineStyle);
+	setLineJoin(s.lineJoin);
 	setPointSize(s.pointSize);
 	setPointSize(s.pointSize);
 	if (s.scissor)
 	if (s.scissor)
 		setScissor(s.scissorBox.x, s.scissorBox.y, s.scissorBox.w, s.scissorBox.h);
 		setScissor(s.scissorBox.x, s.scissorBox.y, s.scissorBox.w, s.scissorBox.h);
@@ -168,9 +171,9 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
 	if (!(GLEE_VERSION_2_0 && Shader::isSupported() && Canvas::isSupported())
 	if (!(GLEE_VERSION_2_0 && Shader::isSupported() && Canvas::isSupported())
 		&& !displayedMinReqWarning)
 		&& !displayedMinReqWarning)
 	{
 	{
-		love::window::MessageBoxType type = love::window::MESSAGEBOX_ERROR;
+		love::window::Window::MessageBoxType type = love::window::Window::MESSAGEBOX_ERROR;
 
 
-		const char *title = "Minimum system requirements not met!";
+		std::string title = "Minimum system requirements not met!";
 
 
 		std::string message;
 		std::string message;
 		message += "Detected OpenGL version: ";
 		message += "Detected OpenGL version: ";
@@ -178,8 +181,8 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
 		message += "\nRequired OpenGL version: 2.1."; // -ish
 		message += "\nRequired OpenGL version: 2.1."; // -ish
 		message += "\nThe program may crash or have graphical issues.";
 		message += "\nThe program may crash or have graphical issues.";
 
 
-		::printf("%s\n%s\n", title, message.c_str());
-		currentWindow->showMessageBox(type, title, message.c_str());
+		::printf("%s\n%s\n", title.c_str(), message.c_str());
+		currentWindow->showMessageBox(type, title, message, true);
 
 
 		// We should only show the message once, instead of after every setMode.
 		// We should only show the message once, instead of after every setMode.
 		displayedMinReqWarning = true;
 		displayedMinReqWarning = true;

+ 76 - 75
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -36,48 +36,48 @@ namespace graphics
 namespace opengl
 namespace opengl
 {
 {
 
 
-static Graphics *instance = nullptr;
+#define instance() (Module::getInstance<Graphics>(Module::M_GRAPHICS))
 
 
 int w_reset(lua_State *)
 int w_reset(lua_State *)
 {
 {
-	instance->reset();
+	instance()->reset();
 	return 0;
 	return 0;
 }
 }
 
 
 int w_clear(lua_State *)
 int w_clear(lua_State *)
 {
 {
-	instance->clear();
+	instance()->clear();
 	return 0;
 	return 0;
 }
 }
 
 
 int w_present(lua_State *)
 int w_present(lua_State *)
 {
 {
-	instance->present();
+	instance()->present();
 	return 0;
 	return 0;
 }
 }
 
 
 int w_isCreated(lua_State *L)
 int w_isCreated(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->isCreated());
+	luax_pushboolean(L, instance()->isCreated());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getWidth(lua_State *L)
 int w_getWidth(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getWidth());
+	lua_pushinteger(L, instance()->getWidth());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getHeight(lua_State *L)
 int w_getHeight(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getHeight());
+	lua_pushinteger(L, instance()->getHeight());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getDimensions(lua_State *L)
 int w_getDimensions(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getWidth());
-	lua_pushinteger(L, instance->getHeight());
+	lua_pushinteger(L, instance()->getWidth());
+	lua_pushinteger(L, instance()->getHeight());
 	return 2;
 	return 2;
 }
 }
 
 
@@ -88,7 +88,7 @@ int w_setScissor(lua_State *L)
 	if (nargs == 0 || (nargs == 4 && lua_isnil(L, 1) && lua_isnil(L, 2)
 	if (nargs == 0 || (nargs == 4 && lua_isnil(L, 1) && lua_isnil(L, 2)
 		&& lua_isnil(L, 3) && lua_isnil(L, 4)))
 		&& lua_isnil(L, 3) && lua_isnil(L, 4)))
 	{
 	{
-		instance->setScissor();
+		instance()->setScissor();
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -100,14 +100,14 @@ int w_setScissor(lua_State *L)
 	if (w < 0 || h < 0)
 	if (w < 0 || h < 0)
 		return luaL_error(L, "Can't set scissor with negative width and/or height.");
 		return luaL_error(L, "Can't set scissor with negative width and/or height.");
 
 
-	instance->setScissor(x, y, w, h);
+	instance()->setScissor(x, y, w, h);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getScissor(lua_State *L)
 int w_getScissor(lua_State *L)
 {
 {
 	int x, y, w, h;
 	int x, y, w, h;
-	if (!instance->getScissor(x, y, w, h))
+	if (!instance()->getScissor(x, y, w, h))
 		return 0;
 		return 0;
 
 
 	lua_pushinteger(L, x);
 	lua_pushinteger(L, x);
@@ -123,15 +123,15 @@ static int setStencil(lua_State *L, bool invert)
 	// no argument -> clear stencil
 	// no argument -> clear stencil
 	if (lua_isnoneornil(L, 1))
 	if (lua_isnoneornil(L, 1))
 	{
 	{
-		instance->discardStencil();
+		instance()->discardStencil();
 		return 0;
 		return 0;
 	}
 	}
 
 
 	luaL_checktype(L, 1, LUA_TFUNCTION);
 	luaL_checktype(L, 1, LUA_TFUNCTION);
 
 
-	instance->defineStencil();
+	instance()->defineStencil();
 	lua_call(L, lua_gettop(L) - 1, 0); // call stencil(...)
 	lua_call(L, lua_gettop(L) - 1, 0); // call stencil(...)
-	instance->useStencil(invert);
+	instance()->useStencil(invert);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -171,7 +171,7 @@ int w_newImage(lua_State *L)
 	// Convert to ImageData / CompressedData, if necessary.
 	// Convert to ImageData / CompressedData, if necessary.
 	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 	{
 	{
-		love::image::Image *image = (love::image::Image *) Module::findInstance("love.image.");
+		love::image::Image *image = Module::getInstance<love::image::Image>(Module::M_IMAGE);
 		if (image == nullptr)
 		if (image == nullptr)
 			return luaL_error(L, "Cannot load images without the love.image module.");
 			return luaL_error(L, "Cannot load images without the love.image module.");
 
 
@@ -208,9 +208,9 @@ int w_newImage(lua_State *L)
 	luax_catchexcept(L,
 	luax_catchexcept(L,
 		[&]() {
 		[&]() {
 			if (cdata)
 			if (cdata)
-				image = instance->newImage(cdata, flags);
+				image = instance()->newImage(cdata, flags);
 			else if (data)
 			else if (data)
-				image = instance->newImage(data, flags);
+				image = instance()->newImage(data, flags);
 		},
 		},
 		[&]() {
 		[&]() {
 			if (releasedata && data)
 			if (releasedata && data)
@@ -239,7 +239,7 @@ int w_newQuad(lua_State *L)
 	float sw = (float) luaL_checknumber(L, 5);
 	float sw = (float) luaL_checknumber(L, 5);
 	float sh = (float) luaL_checknumber(L, 6);
 	float sh = (float) luaL_checknumber(L, 6);
 
 
-	Quad *quad = instance->newQuad(v, sw, sh);
+	Quad *quad = instance()->newQuad(v, sw, sh);
 	luax_pushtype(L, "Quad", GRAPHICS_QUAD_T, quad);
 	luax_pushtype(L, "Quad", GRAPHICS_QUAD_T, quad);
 	return 1;
 	return 1;
 }
 }
@@ -257,7 +257,7 @@ int w_newFont(lua_State *L)
 
 
 	Font *font = 0;
 	Font *font = 0;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		font = instance->newFont(rasterizer, instance->getDefaultFilter()); }
+		font = instance()->newFont(rasterizer, instance()->getDefaultFilter()); }
 	);
 	);
 
 
 	if (font == 0)
 	if (font == 0)
@@ -271,7 +271,7 @@ int w_newFont(lua_State *L)
 int w_newImageFont(lua_State *L)
 int w_newImageFont(lua_State *L)
 {
 {
 	// filter for glyphs
 	// filter for glyphs
-	Texture::Filter filter = instance->getDefaultFilter();
+	Texture::Filter filter = instance()->getDefaultFilter();
 
 
 	// Convert to ImageData if necessary.
 	// Convert to ImageData if necessary.
 	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
 	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_T))
@@ -298,7 +298,7 @@ int w_newImageFont(lua_State *L)
 	love::font::Rasterizer *rasterizer = luax_checktype<love::font::Rasterizer>(L, 1, "Rasterizer", FONT_RASTERIZER_T);
 	love::font::Rasterizer *rasterizer = luax_checktype<love::font::Rasterizer>(L, 1, "Rasterizer", FONT_RASTERIZER_T);
 
 
 	// Create the font.
 	// Create the font.
-	Font *font = instance->newFont(rasterizer, filter);
+	Font *font = instance()->newFont(rasterizer, filter);
 
 
 	if (font == 0)
 	if (font == 0)
 		return luaL_error(L, "Could not load font.");
 		return luaL_error(L, "Could not load font.");
@@ -323,7 +323,7 @@ int w_newSpriteBatch(lua_State *L)
 
 
 	SpriteBatch *t = nullptr;
 	SpriteBatch *t = nullptr;
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&](){ t = instance->newSpriteBatch(texture, size, usage); }
+		[&](){ t = instance()->newSpriteBatch(texture, size, usage); }
 	);
 	);
 
 
 	luax_pushtype(L, "SpriteBatch", GRAPHICS_SPRITE_BATCH_T, t);
 	luax_pushtype(L, "SpriteBatch", GRAPHICS_SPRITE_BATCH_T, t);
@@ -339,7 +339,7 @@ int w_newParticleSystem(lua_State *L)
 		return luaL_error(L, "Invalid ParticleSystem size");	
 		return luaL_error(L, "Invalid ParticleSystem size");	
 
 
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&](){ t = instance->newParticleSystem(texture, int(size)); }
+		[&](){ t = instance()->newParticleSystem(texture, int(size)); }
 	);
 	);
 
 
 	luax_pushtype(L, "ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_T, t);
 	luax_pushtype(L, "ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_T, t);
@@ -349,8 +349,8 @@ int w_newParticleSystem(lua_State *L)
 int w_newCanvas(lua_State *L)
 int w_newCanvas(lua_State *L)
 {
 {
 	// check if width and height are given. else default to screen dimensions.
 	// check if width and height are given. else default to screen dimensions.
-	int width       = luaL_optint(L, 1, instance->getWidth());
-	int height      = luaL_optint(L, 2, instance->getHeight());
+	int width       = luaL_optint(L, 1, instance()->getWidth());
+	int height      = luaL_optint(L, 2, instance()->getHeight());
 	const char *str = luaL_optstring(L, 3, "normal");
 	const char *str = luaL_optstring(L, 3, "normal");
 	int msaa        = luaL_optint(L, 4, 0);
 	int msaa        = luaL_optint(L, 4, 0);
 
 
@@ -360,7 +360,7 @@ int w_newCanvas(lua_State *L)
 
 
 	Canvas *canvas = nullptr;
 	Canvas *canvas = nullptr;
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&](){ canvas = instance->newCanvas(width, height, format, msaa); }
+		[&](){ canvas = instance()->newCanvas(width, height, format, msaa); }
 	);
 	);
 
 
 	if (canvas == nullptr)
 	if (canvas == nullptr)
@@ -448,7 +448,7 @@ int w_newShader(lua_State *L)
 	bool should_error = false;
 	bool should_error = false;
 	try
 	try
 	{
 	{
-		Shader *shader = instance->newShader(sources);
+		Shader *shader = instance()->newShader(sources);
 		luax_pushtype(L, "Shader", GRAPHICS_SHADER_T, shader);
 		luax_pushtype(L, "Shader", GRAPHICS_SHADER_T, shader);
 	}
 	}
 	catch (love::Exception &e)
 	catch (love::Exception &e)
@@ -529,13 +529,13 @@ int w_newMesh(lua_State *L)
 			vertices.push_back(v);
 			vertices.push_back(v);
 		}
 		}
 
 
-		luax_catchexcept(L, [&](){ t = instance->newMesh(vertices, mode); });
+		luax_catchexcept(L, [&](){ t = instance()->newMesh(vertices, mode); });
 		t->setVertexColors(use_colors);
 		t->setVertexColors(use_colors);
 	}
 	}
 	else
 	else
 	{
 	{
 		int count = luaL_checkint(L, 1);
 		int count = luaL_checkint(L, 1);
-		luax_catchexcept(L, [&](){ t = instance->newMesh(count, mode); });
+		luax_catchexcept(L, [&](){ t = instance()->newMesh(count, mode); });
 	}
 	}
 
 
 	if (tex)
 	if (tex)
@@ -567,13 +567,13 @@ int w_setColor(lua_State *L)
 		c.b = (unsigned char)luaL_checkint(L, 3);
 		c.b = (unsigned char)luaL_checkint(L, 3);
 		c.a = (unsigned char)luaL_optint(L, 4, 255);
 		c.a = (unsigned char)luaL_optint(L, 4, 255);
 	}
 	}
-	instance->setColor(c);
+	instance()->setColor(c);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getColor(lua_State *L)
 int w_getColor(lua_State *L)
 {
 {
-	Color c = instance->getColor();
+	Color c = instance()->getColor();
 	lua_pushinteger(L, c.r);
 	lua_pushinteger(L, c.r);
 	lua_pushinteger(L, c.g);
 	lua_pushinteger(L, c.g);
 	lua_pushinteger(L, c.b);
 	lua_pushinteger(L, c.b);
@@ -603,13 +603,13 @@ int w_setBackgroundColor(lua_State *L)
 		c.b = (unsigned char)luaL_checkint(L, 3);
 		c.b = (unsigned char)luaL_checkint(L, 3);
 		c.a = (unsigned char)luaL_optint(L, 4, 255);
 		c.a = (unsigned char)luaL_optint(L, 4, 255);
 	}
 	}
-	instance->setBackgroundColor(c);
+	instance()->setBackgroundColor(c);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getBackgroundColor(lua_State *L)
 int w_getBackgroundColor(lua_State *L)
 {
 {
-	Color c = instance->getBackgroundColor();
+	Color c = instance()->getBackgroundColor();
 	lua_pushinteger(L, c.r);
 	lua_pushinteger(L, c.r);
 	lua_pushinteger(L, c.g);
 	lua_pushinteger(L, c.g);
 	lua_pushinteger(L, c.b);
 	lua_pushinteger(L, c.b);
@@ -620,13 +620,13 @@ int w_getBackgroundColor(lua_State *L)
 int w_setFont(lua_State *L)
 int w_setFont(lua_State *L)
 {
 {
 	Font *font = luax_checktype<Font>(L, 1, "Font", GRAPHICS_FONT_T);
 	Font *font = luax_checktype<Font>(L, 1, "Font", GRAPHICS_FONT_T);
-	instance->setFont(font);
+	instance()->setFont(font);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getFont(lua_State *L)
 int w_getFont(lua_State *L)
 {
 {
-	Font *f = instance->getFont();
+	Font *f = instance()->getFont();
 
 
 	if (f == 0)
 	if (f == 0)
 		return 0;
 		return 0;
@@ -652,14 +652,14 @@ int w_setColorMask(lua_State *L)
 	}
 	}
 
 
 	// r, g, b, a
 	// r, g, b, a
-	instance->setColorMask(mask[0], mask[1], mask[2], mask[3]);
+	instance()->setColorMask(mask[0], mask[1], mask[2], mask[3]);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getColorMask(lua_State *L)
 int w_getColorMask(lua_State *L)
 {
 {
-	const bool *mask = instance->getColorMask();
+	const bool *mask = instance()->getColorMask();
 
 
 	for (int i = 0; i < 4; i++)
 	for (int i = 0; i < 4; i++)
 		luax_pushboolean(L, mask[i]);
 		luax_pushboolean(L, mask[i]);
@@ -674,7 +674,7 @@ int w_setBlendMode(lua_State *L)
 	if (!Graphics::getConstant(str, mode))
 	if (!Graphics::getConstant(str, mode))
 		return luaL_error(L, "Invalid blend mode: %s", str);
 		return luaL_error(L, "Invalid blend mode: %s", str);
 
 
-	luax_catchexcept(L, [&](){ instance->setBlendMode(mode); });
+	luax_catchexcept(L, [&](){ instance()->setBlendMode(mode); });
 	return 0;
 	return 0;
 }
 }
 
 
@@ -683,7 +683,7 @@ int w_getBlendMode(lua_State *L)
 	const char *str;
 	const char *str;
 	Graphics::BlendMode mode;
 	Graphics::BlendMode mode;
 
 
-	luax_catchexcept(L, [&](){ mode = instance->getBlendMode(); });
+	luax_catchexcept(L, [&](){ mode = instance()->getBlendMode(); });
 
 
 	if (!Graphics::getConstant(mode, str))
 	if (!Graphics::getConstant(mode, str))
 		return luaL_error(L, "Unknown blend mode");
 		return luaL_error(L, "Unknown blend mode");
@@ -712,14 +712,14 @@ int w_setDefaultFilter(lua_State *L)
 	f.mag = mag;
 	f.mag = mag;
 	f.anisotropy = anisotropy;
 	f.anisotropy = anisotropy;
 
 
-	instance->setDefaultFilter(f);
+	instance()->setDefaultFilter(f);
 	
 	
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getDefaultFilter(lua_State *L)
 int w_getDefaultFilter(lua_State *L)
 {
 {
-	const Texture::Filter &f = instance->getDefaultFilter();
+	const Texture::Filter &f = instance()->getDefaultFilter();
 	const char *minstr;
 	const char *minstr;
 	const char *magstr;
 	const char *magstr;
 	if (!Texture::getConstant(f.min, minstr))
 	if (!Texture::getConstant(f.min, minstr))
@@ -744,7 +744,7 @@ int w_setDefaultMipmapFilter(lua_State *L)
 
 
 	float sharpness = (float) luaL_optnumber(L, 2, 0);
 	float sharpness = (float) luaL_optnumber(L, 2, 0);
 
 
-	instance->setDefaultMipmapFilter(filter, sharpness);
+	instance()->setDefaultMipmapFilter(filter, sharpness);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -754,7 +754,7 @@ int w_getDefaultMipmapFilter(lua_State *L)
 	Texture::FilterMode filter;
 	Texture::FilterMode filter;
 	float sharpness;
 	float sharpness;
 
 
-	instance->getDefaultMipmapFilter(&filter, &sharpness);
+	instance()->getDefaultMipmapFilter(&filter, &sharpness);
 
 
 	const char *str;
 	const char *str;
 	if (Texture::getConstant(filter, str))
 	if (Texture::getConstant(filter, str))
@@ -770,7 +770,7 @@ int w_getDefaultMipmapFilter(lua_State *L)
 int w_setLineWidth(lua_State *L)
 int w_setLineWidth(lua_State *L)
 {
 {
 	float width = (float)luaL_checknumber(L, 1);
 	float width = (float)luaL_checknumber(L, 1);
-	instance->setLineWidth(width);
+	instance()->setLineWidth(width);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -781,7 +781,7 @@ int w_setLineStyle(lua_State *L)
 	if (!Graphics::getConstant(str, style))
 	if (!Graphics::getConstant(str, style))
 		return luaL_error(L, "Invalid line style: %s", str);
 		return luaL_error(L, "Invalid line style: %s", str);
 
 
-	instance->setLineStyle(style);
+	instance()->setLineStyle(style);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -792,19 +792,19 @@ int w_setLineJoin(lua_State *L)
 	if (!Graphics::getConstant(str, join))
 	if (!Graphics::getConstant(str, join))
 		return luaL_error(L, "Invalid line join mode: %s", str);
 		return luaL_error(L, "Invalid line join mode: %s", str);
 
 
-	instance->setLineJoin(join);
+	instance()->setLineJoin(join);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getLineWidth(lua_State *L)
 int w_getLineWidth(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getLineWidth());
+	lua_pushnumber(L, instance()->getLineWidth());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getLineStyle(lua_State *L)
 int w_getLineStyle(lua_State *L)
 {
 {
-	Graphics::LineStyle style = instance->getLineStyle();
+	Graphics::LineStyle style = instance()->getLineStyle();
 	const char *str;
 	const char *str;
 	if (!Graphics::getConstant(style, str))
 	if (!Graphics::getConstant(style, str))
 		return luaL_error(L, "Unknown line style");
 		return luaL_error(L, "Unknown line style");
@@ -814,7 +814,7 @@ int w_getLineStyle(lua_State *L)
 
 
 int w_getLineJoin(lua_State *L)
 int w_getLineJoin(lua_State *L)
 {
 {
-	Graphics::LineJoin join = instance->getLineJoin();
+	Graphics::LineJoin join = instance()->getLineJoin();
 	const char *str;
 	const char *str;
 	if (!Graphics::getConstant(join, str))
 	if (!Graphics::getConstant(join, str))
 		return luaL_error(L, "Unknown line join");
 		return luaL_error(L, "Unknown line join");
@@ -825,25 +825,25 @@ int w_getLineJoin(lua_State *L)
 int w_setPointSize(lua_State *L)
 int w_setPointSize(lua_State *L)
 {
 {
 	float size = (float)luaL_checknumber(L, 1);
 	float size = (float)luaL_checknumber(L, 1);
-	instance->setPointSize(size);
+	instance()->setPointSize(size);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getPointSize(lua_State *L)
 int w_getPointSize(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getPointSize());
+	lua_pushnumber(L, instance()->getPointSize());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_setWireframe(lua_State *L)
 int w_setWireframe(lua_State *L)
 {
 {
-	instance->setWireframe(luax_toboolean(L, 1));
+	instance()->setWireframe(luax_toboolean(L, 1));
 	return 0;
 	return 0;
 }
 }
 
 
 int w_isWireframe(lua_State *L)
 int w_isWireframe(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->isWireframe());
+	luax_pushboolean(L, instance()->isWireframe());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -853,7 +853,7 @@ int w_newScreenshot(lua_State *L)
 	bool copyAlpha = luax_optboolean(L, 1, false);
 	bool copyAlpha = luax_optboolean(L, 1, false);
 	love::image::ImageData *i = 0;
 	love::image::ImageData *i = 0;
 
 
-	luax_catchexcept(L, [&](){ i = instance->newScreenshot(image, copyAlpha); });
+	luax_catchexcept(L, [&](){ i = instance()->newScreenshot(image, copyAlpha); });
 
 
 	luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, i);
 	luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, i);
 	return 1;
 	return 1;
@@ -862,7 +862,7 @@ int w_newScreenshot(lua_State *L)
 int w_setCanvas(lua_State *L)
 int w_setCanvas(lua_State *L)
 {
 {
 	// discard stencil testing
 	// discard stencil testing
-	instance->discardStencil();
+	instance()->discardStencil();
 
 
 	// called with none -> reset to default buffer
 	// called with none -> reset to default buffer
 	if (lua_isnoneornil(L,1))
 	if (lua_isnoneornil(L,1))
@@ -970,7 +970,7 @@ int w_getSupported(lua_State *L)
 		if (!Graphics::getConstant(feature, name))
 		if (!Graphics::getConstant(feature, name))
 			continue;
 			continue;
 
 
-		luax_pushboolean(L, instance->isSupported(feature));
+		luax_pushboolean(L, instance()->isSupported(feature));
 		lua_setfield(L, -2, name);
 		lua_setfield(L, -2, name);
 	}
 	}
 
 
@@ -1021,7 +1021,7 @@ int w_getCompressedImageFormats(lua_State *L)
 int w_getRendererInfo(lua_State *L)
 int w_getRendererInfo(lua_State *L)
 {
 {
 	Graphics::RendererInfo info;
 	Graphics::RendererInfo info;
-	luax_catchexcept(L, [&](){ info = instance->getRendererInfo(); });
+	luax_catchexcept(L, [&](){ info = instance()->getRendererInfo(); });
 
 
 	luax_pushstring(L, info.name);
 	luax_pushstring(L, info.name);
 	luax_pushstring(L, info.version);
 	luax_pushstring(L, info.version);
@@ -1042,7 +1042,7 @@ int w_getSystemLimits(lua_State *L)
 		if (!Graphics::getConstant(limittype, name))
 		if (!Graphics::getConstant(limittype, name))
 			continue;
 			continue;
 
 
-		lua_pushnumber(L, instance->getSystemLimit(limittype));
+		lua_pushnumber(L, instance()->getSystemLimit(limittype));
 		lua_setfield(L, -2, name);
 		lua_setfield(L, -2, name);
 	}
 	}
 
 
@@ -1104,7 +1104,7 @@ int w_print(lua_State *L)
 	float ky = (float)luaL_optnumber(L, 10, 0.0f);
 	float ky = (float)luaL_optnumber(L, 10, 0.0f);
 
 
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&](){ instance->print(str, x, y, angle, sx, sy, ox, oy, kx,ky); }
+		[&](){ instance()->print(str, x, y, angle, sx, sy, ox, oy, kx,ky); }
 	);
 	);
 	return 0;
 	return 0;
 }
 }
@@ -1142,7 +1142,7 @@ int w_printf(lua_State *L)
 	}
 	}
 
 
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&](){ instance->printf(str, x, y, wrap, align, angle, sx, sy, ox, oy, kx, ky); }
+		[&](){ instance()->printf(str, x, y, wrap, align, angle, sx, sy, ox, oy, kx, ky); }
 	);
 	);
 	return 0;
 	return 0;
 }
 }
@@ -1151,7 +1151,7 @@ int w_point(lua_State *L)
 {
 {
 	float x = (float)luaL_checknumber(L, 1);
 	float x = (float)luaL_checknumber(L, 1);
 	float y = (float)luaL_checknumber(L, 2);
 	float y = (float)luaL_checknumber(L, 2);
-	instance->point(x, y);
+	instance()->point(x, y);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1186,7 +1186,7 @@ int w_line(lua_State *L)
 			coords[i] = luax_tofloat(L, i + 1);
 			coords[i] = luax_tofloat(L, i + 1);
 	}
 	}
 
 
-	instance->polyline(coords, args);
+	instance()->polyline(coords, args);
 
 
 	delete[] coords;
 	delete[] coords;
 	return 0;
 	return 0;
@@ -1203,7 +1203,7 @@ int w_rectangle(lua_State *L)
 	float y = (float)luaL_checknumber(L, 3);
 	float y = (float)luaL_checknumber(L, 3);
 	float w = (float)luaL_checknumber(L, 4);
 	float w = (float)luaL_checknumber(L, 4);
 	float h = (float)luaL_checknumber(L, 5);
 	float h = (float)luaL_checknumber(L, 5);
-	instance->rectangle(mode, x, y, w, h);
+	instance()->rectangle(mode, x, y, w, h);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1223,7 +1223,7 @@ int w_circle(lua_State *L)
 	else
 	else
 		points = luaL_checkint(L, 5);
 		points = luaL_checkint(L, 5);
 
 
-	instance->circle(mode, x, y, radius, points);
+	instance()->circle(mode, x, y, radius, points);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1245,7 +1245,7 @@ int w_arc(lua_State *L)
 	else
 	else
 		points = luaL_checkint(L, 7);
 		points = luaL_checkint(L, 7);
 
 
-	instance->arc(mode, x, y, radius, angle1, angle2, points);
+	instance()->arc(mode, x, y, radius, angle1, angle2, points);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1291,7 +1291,7 @@ int w_polygon(lua_State *L)
 	// make a closed loop
 	// make a closed loop
 	coords[args]   = coords[0];
 	coords[args]   = coords[0];
 	coords[args+1] = coords[1];
 	coords[args+1] = coords[1];
-	instance->polygon(mode, coords, args+2);
+	instance()->polygon(mode, coords, args+2);
 	delete[] coords;
 	delete[] coords;
 
 
 	return 0;
 	return 0;
@@ -1299,20 +1299,20 @@ int w_polygon(lua_State *L)
 
 
 int w_push(lua_State *L)
 int w_push(lua_State *L)
 {
 {
-	luax_catchexcept(L, [&](){ instance->push(); });
+	luax_catchexcept(L, [&](){ instance()->push(); });
 	return 0;
 	return 0;
 }
 }
 
 
 int w_pop(lua_State *L)
 int w_pop(lua_State *L)
 {
 {
-	luax_catchexcept(L, [&](){ instance->pop(); });
+	luax_catchexcept(L, [&](){ instance()->pop(); });
 	return 0;
 	return 0;
 }
 }
 
 
 int w_rotate(lua_State *L)
 int w_rotate(lua_State *L)
 {
 {
 	float angle = (float)luaL_checknumber(L, 1);
 	float angle = (float)luaL_checknumber(L, 1);
-	instance->rotate(angle);
+	instance()->rotate(angle);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1320,7 +1320,7 @@ int w_scale(lua_State *L)
 {
 {
 	float sx = (float)luaL_optnumber(L, 1, 1.0f);
 	float sx = (float)luaL_optnumber(L, 1, 1.0f);
 	float sy = (float)luaL_optnumber(L, 2, sx);
 	float sy = (float)luaL_optnumber(L, 2, sx);
-	instance->scale(sx, sy);
+	instance()->scale(sx, sy);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1328,7 +1328,7 @@ int w_translate(lua_State *L)
 {
 {
 	float x = (float)luaL_checknumber(L, 1);
 	float x = (float)luaL_checknumber(L, 1);
 	float y = (float)luaL_checknumber(L, 2);
 	float y = (float)luaL_checknumber(L, 2);
-	instance->translate(x, y);
+	instance()->translate(x, y);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1336,13 +1336,13 @@ int w_shear(lua_State *L)
 {
 {
 	float kx = (float)luaL_checknumber(L, 1);
 	float kx = (float)luaL_checknumber(L, 1);
 	float ky = (float)luaL_checknumber(L, 2);
 	float ky = (float)luaL_checknumber(L, 2);
-	instance->shear(kx, ky);
+	instance()->shear(kx, ky);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_origin(lua_State * /*L*/)
 int w_origin(lua_State * /*L*/)
 {
 {
-	instance->origin();
+	instance()->origin();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1454,7 +1454,8 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_graphics(lua_State *L)
 extern "C" int luaopen_love_graphics(lua_State *L)
 {
 {
-	if (instance == 0)
+	Graphics *instance = instance();
+	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new Graphics(); });
 		luax_catchexcept(L, [&](){ instance = new Graphics(); });
 	}
 	}

+ 3 - 3
src/modules/image/Image.h

@@ -44,11 +44,11 @@ class Image : public Module
 {
 {
 public:
 public:
 
 
-	/**
-	 * Destructor.
-	 **/
 	virtual ~Image() {}
 	virtual ~Image() {}
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_IMAGE; }
+
 	/**
 	/**
 	 * Creates new ImageData from FileData.
 	 * Creates new ImageData from FileData.
 	 * @param data The FileData containing the encoded image data.
 	 * @param data The FileData containing the encoded image data.

+ 6 - 5
src/modules/image/wrap_Image.cpp

@@ -32,7 +32,7 @@ namespace love
 namespace image
 namespace image
 {
 {
 
 
-static Image *instance = nullptr;
+#define instance() (Module::getInstance<Image>(Module::M_IMAGE))
 
 
 int w_newImageData(lua_State *L)
 int w_newImageData(lua_State *L)
 {
 {
@@ -45,7 +45,7 @@ int w_newImageData(lua_State *L)
 			return luaL_error(L, "Invalid image size.");
 			return luaL_error(L, "Invalid image size.");
 
 
 		ImageData *t = nullptr;
 		ImageData *t = nullptr;
-		luax_catchexcept(L, [&](){ t = instance->newImageData(w, h); });
+		luax_catchexcept(L, [&](){ t = instance()->newImageData(w, h); });
 
 
 		luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, t);
 		luax_pushtype(L, "ImageData", IMAGE_IMAGE_DATA_T, t);
 		return 1;
 		return 1;
@@ -56,7 +56,7 @@ int w_newImageData(lua_State *L)
 
 
 	ImageData *t = nullptr;
 	ImageData *t = nullptr;
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&]() { t = instance->newImageData(data); },
+		[&]() { t = instance()->newImageData(data); },
 		[&]() { data->release(); }
 		[&]() { data->release(); }
 	);
 	);
 
 
@@ -70,7 +70,7 @@ int w_newCompressedData(lua_State *L)
 
 
 	CompressedData *t = nullptr;
 	CompressedData *t = nullptr;
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&]() { t = instance->newCompressedData(data); },
+		[&]() { t = instance()->newCompressedData(data); },
 		[&]() { data->release(); }
 		[&]() { data->release(); }
 	);
 	);
 
 
@@ -81,7 +81,7 @@ int w_newCompressedData(lua_State *L)
 int w_isCompressed(lua_State *L)
 int w_isCompressed(lua_State *L)
 {
 {
 	love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1);
 	love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1);
-	bool compressed = instance->isCompressed(data);
+	bool compressed = instance()->isCompressed(data);
 	data->release();
 	data->release();
 
 
 	luax_pushboolean(L, compressed);
 	luax_pushboolean(L, compressed);
@@ -106,6 +106,7 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_image(lua_State *L)
 extern "C" int luaopen_love_image(lua_State *L)
 {
 {
+	Image *instance = instance();
 	if (instance == nullptr)
 	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new love::image::magpie::Image(); });
 		luax_catchexcept(L, [&](){ instance = new love::image::magpie::Image(); });

+ 3 - 0
src/modules/joystick/JoystickModule.h

@@ -36,6 +36,9 @@ public:
 
 
 	virtual ~JoystickModule() {}
 	virtual ~JoystickModule() {}
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_JOYSTICK; }
+
 	/**
 	/**
 	 * Adds a connected Joystick device and opens it for use.
 	 * Adds a connected Joystick device and opens it for use.
 	 * Returns NULL if the Joystick could not be added.
 	 * Returns NULL if the Joystick could not be added.

+ 10 - 9
src/modules/joystick/wrap_JoystickModule.cpp

@@ -30,16 +30,16 @@ namespace love
 namespace joystick
 namespace joystick
 {
 {
 
 
-static JoystickModule *instance = nullptr;
+#define instance() (Module::getInstance<JoystickModule>(Module::M_JOYSTICK))
 
 
 int w_getJoysticks(lua_State *L)
 int w_getJoysticks(lua_State *L)
 {
 {
-	int stickcount = instance->getJoystickCount();
+	int stickcount = instance()->getJoystickCount();
 	lua_createtable(L, stickcount, 0);
 	lua_createtable(L, stickcount, 0);
 
 
 	for (int i = 0; i < stickcount; i++)
 	for (int i = 0; i < stickcount; i++)
 	{
 	{
-		Joystick *stick = instance->getJoystick(i);
+		Joystick *stick = instance()->getJoystick(i);
 		stick->retain();
 		stick->retain();
 		luax_pushtype(L, "Joystick", JOYSTICK_JOYSTICK_T, stick);
 		luax_pushtype(L, "Joystick", JOYSTICK_JOYSTICK_T, stick);
 		lua_rawseti(L, -2, i + 1);
 		lua_rawseti(L, -2, i + 1);
@@ -51,7 +51,7 @@ int w_getJoysticks(lua_State *L)
 int w_getIndex(lua_State *L)
 int w_getIndex(lua_State *L)
 {
 {
 	Joystick *j = luax_checkjoystick(L, 1);
 	Joystick *j = luax_checkjoystick(L, 1);
-	int index = instance->getIndex(j);
+	int index = instance()->getIndex(j);
 	if (index >= 0)
 	if (index >= 0)
 		lua_pushinteger(L, index + 1);
 		lua_pushinteger(L, index + 1);
 	else
 	else
@@ -61,7 +61,7 @@ int w_getIndex(lua_State *L)
 
 
 int w_getJoystickCount(lua_State *L)
 int w_getJoystickCount(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getJoystickCount());
+	lua_pushinteger(L, instance()->getJoystickCount());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -109,7 +109,7 @@ int w_setGamepadMapping(lua_State *L)
 	}
 	}
 
 
 	bool success = false;
 	bool success = false;
-	luax_catchexcept(L, [&](){ success = instance->setGamepadMapping(guid, gpinput, jinput); });
+	luax_catchexcept(L, [&](){ success = instance()->setGamepadMapping(guid, gpinput, jinput); });
 
 
 	luax_pushboolean(L, success);
 	luax_pushboolean(L, success);
 	return 1;
 	return 1;
@@ -142,7 +142,7 @@ int w_getGamepadMapping(lua_State *L)
 	Joystick::JoystickInput jinput;
 	Joystick::JoystickInput jinput;
 	jinput.type = Joystick::INPUT_TYPE_MAX_ENUM;
 	jinput.type = Joystick::INPUT_TYPE_MAX_ENUM;
 
 
-	luax_catchexcept(L, [&](){ jinput = instance->getGamepadMapping(guid, gpinput); });
+	luax_catchexcept(L, [&](){ jinput = instance()->getGamepadMapping(guid, gpinput); });
 
 
 	if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM)
 	if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM)
 		return 0;
 		return 0;
@@ -197,14 +197,14 @@ int w_loadGamepadMappings(lua_State *L)
 	else
 	else
 		mappings = luax_checkstring(L, 1);
 		mappings = luax_checkstring(L, 1);
 
 
-	luax_catchexcept(L, [&](){ instance->loadGamepadMappings(mappings); });
+	luax_catchexcept(L, [&](){ instance()->loadGamepadMappings(mappings); });
 	return 0;
 	return 0;
 }
 }
 
 
 int w_saveGamepadMappings(lua_State *L)
 int w_saveGamepadMappings(lua_State *L)
 {
 {
 	lua_settop(L, 1);
 	lua_settop(L, 1);
-	std::string mappings = instance->saveGamepadMappings();
+	std::string mappings = instance()->saveGamepadMappings();
 
 
 	// Optionally write the mappings string to a file.
 	// Optionally write the mappings string to a file.
 	if (!lua_isnoneornil(L, 1))
 	if (!lua_isnoneornil(L, 1))
@@ -240,6 +240,7 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_joystick(lua_State *L)
 extern "C" int luaopen_love_joystick(lua_State *L)
 {
 {
+	JoystickModule *instance = instance();
 	if (instance == nullptr)
 	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new sdl::JoystickModule(); });
 		luax_catchexcept(L, [&](){ instance = new sdl::JoystickModule(); });

+ 3 - 0
src/modules/keyboard/Keyboard.h

@@ -246,6 +246,9 @@ public:
 
 
 	virtual ~Keyboard() {}
 	virtual ~Keyboard() {}
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_KEYBOARD; }
+
 	/**
 	/**
 	 * Sets whether repeat keypress events should be sent if a key is held down.
 	 * Sets whether repeat keypress events should be sent if a key is held down.
 	 * Does not affect text input events.
 	 * Does not affect text input events.

+ 7 - 6
src/modules/keyboard/wrap_Keyboard.cpp

@@ -29,17 +29,17 @@ namespace love
 namespace keyboard
 namespace keyboard
 {
 {
 
 
-static Keyboard *instance = nullptr;
+#define instance() (Module::getInstance<Keyboard>(Module::M_KEYBOARD))
 
 
 int w_setKeyRepeat(lua_State *L)
 int w_setKeyRepeat(lua_State *L)
 {
 {
-	instance->setKeyRepeat(luax_toboolean(L, 1));
+	instance()->setKeyRepeat(luax_toboolean(L, 1));
 	return 0;
 	return 0;
 }
 }
 
 
 int w_hasKeyRepeat(lua_State *L)
 int w_hasKeyRepeat(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->hasKeyRepeat());
+	luax_pushboolean(L, instance()->hasKeyRepeat());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -57,20 +57,20 @@ int w_isDown(lua_State *L)
 	}
 	}
 	keylist[counter] = Keyboard::KEY_MAX_ENUM;
 	keylist[counter] = Keyboard::KEY_MAX_ENUM;
 
 
-	luax_pushboolean(L, instance->isDown(keylist));
+	luax_pushboolean(L, instance()->isDown(keylist));
 	delete[] keylist;
 	delete[] keylist;
 	return 1;
 	return 1;
 }
 }
 
 
 int w_setTextInput(lua_State *L)
 int w_setTextInput(lua_State *L)
 {
 {
-	instance->setTextInput(luax_toboolean(L, 1));
+	instance()->setTextInput(luax_toboolean(L, 1));
 	return 0;
 	return 0;
 }
 }
 
 
 int w_hasTextInput(lua_State *L)
 int w_hasTextInput(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->hasTextInput());
+	luax_pushboolean(L, instance()->hasTextInput());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -87,6 +87,7 @@ static const luaL_Reg functions[] =
 
 
 extern "C" int luaopen_love_keyboard(lua_State *L)
 extern "C" int luaopen_love_keyboard(lua_State *L)
 {
 {
+	Keyboard *instance = instance();
 	if (instance == nullptr)
 	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new love::keyboard::sdl::Keyboard(); });
 		luax_catchexcept(L, [&](){ instance = new love::keyboard::sdl::Keyboard(); });

+ 6 - 0
src/modules/math/MathModule.h

@@ -115,6 +115,12 @@ public:
 	 **/
 	 **/
 	BezierCurve *newBezierCurve(const std::vector<Vector> &points);
 	BezierCurve *newBezierCurve(const std::vector<Vector> &points);
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const
+	{
+		return M_MATH;
+	}
+
 	virtual const char *getName() const
 	virtual const char *getName() const
 	{
 	{
 		return "love.math";
 		return "love.math";

+ 3 - 0
src/modules/mouse/Mouse.h

@@ -49,6 +49,9 @@ public:
 
 
 	virtual ~Mouse() {}
 	virtual ~Mouse() {}
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_MOUSE; }
+
 	virtual Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty) = 0;
 	virtual Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty) = 0;
 	virtual Cursor *getSystemCursor(Cursor::SystemCursor cursortype) = 0;
 	virtual Cursor *getSystemCursor(Cursor::SystemCursor cursortype) = 0;
 
 

+ 18 - 17
src/modules/mouse/wrap_Mouse.cpp

@@ -30,7 +30,7 @@ namespace love
 namespace mouse
 namespace mouse
 {
 {
 
 
-static Mouse *instance = nullptr;
+#define instance() (Module::getInstance<Mouse>(Module::M_MOUSE))
 
 
 int w_newCursor(lua_State *L)
 int w_newCursor(lua_State *L)
 {
 {
@@ -43,7 +43,7 @@ int w_newCursor(lua_State *L)
 	int hotx = luaL_optint(L, 2, 0);
 	int hotx = luaL_optint(L, 2, 0);
 	int hoty = luaL_optint(L, 3, 0);
 	int hoty = luaL_optint(L, 3, 0);
 
 
-	luax_catchexcept(L, [&](){ cursor = instance->newCursor(data, hotx, hoty); });
+	luax_catchexcept(L, [&](){ cursor = instance()->newCursor(data, hotx, hoty); });
 
 
 	luax_pushtype(L, "Cursor", MOUSE_CURSOR_T, cursor);
 	luax_pushtype(L, "Cursor", MOUSE_CURSOR_T, cursor);
 	return 1;
 	return 1;
@@ -58,7 +58,7 @@ int w_getSystemCursor(lua_State *L)
 		return luaL_error(L, "Invalid system cursor type: %s", str);
 		return luaL_error(L, "Invalid system cursor type: %s", str);
 
 
 	Cursor *cursor = 0;
 	Cursor *cursor = 0;
-	luax_catchexcept(L, [&](){ cursor = instance->getSystemCursor(systemCursor); });
+	luax_catchexcept(L, [&](){ cursor = instance()->getSystemCursor(systemCursor); });
 
 
 	cursor->retain();
 	cursor->retain();
 	luax_pushtype(L, "Cursor", MOUSE_CURSOR_T, cursor);
 	luax_pushtype(L, "Cursor", MOUSE_CURSOR_T, cursor);
@@ -70,18 +70,18 @@ int w_setCursor(lua_State *L)
 	// Revert to the default system cursor if no argument is given.
 	// Revert to the default system cursor if no argument is given.
 	if (lua_isnoneornil(L, 1))
 	if (lua_isnoneornil(L, 1))
 	{
 	{
-		instance->setCursor();
+		instance()->setCursor();
 		return 0;
 		return 0;
 	}
 	}
 
 
 	Cursor *cursor = luax_checkcursor(L, 1);
 	Cursor *cursor = luax_checkcursor(L, 1);
-	instance->setCursor(cursor);
+	instance()->setCursor(cursor);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getCursor(lua_State *L)
 int w_getCursor(lua_State *L)
 {
 {
-	Cursor *cursor = instance->getCursor();
+	Cursor *cursor = instance()->getCursor();
 
 
 	if (cursor)
 	if (cursor)
 	{
 	{
@@ -96,20 +96,20 @@ int w_getCursor(lua_State *L)
 
 
 int w_getX(lua_State *L)
 int w_getX(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getX());
+	lua_pushnumber(L, instance()->getX());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getY(lua_State *L)
 int w_getY(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getY());
+	lua_pushnumber(L, instance()->getY());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getPosition(lua_State *L)
 int w_getPosition(lua_State *L)
 {
 {
 	int x, y;
 	int x, y;
-	instance->getPosition(x, y);
+	instance()->getPosition(x, y);
 	lua_pushinteger(L, x);
 	lua_pushinteger(L, x);
 	lua_pushinteger(L, y);
 	lua_pushinteger(L, y);
 	return 2;
 	return 2;
@@ -118,14 +118,14 @@ int w_getPosition(lua_State *L)
 int w_setX(lua_State *L)
 int w_setX(lua_State *L)
 {
 {
 	int x = luaL_checkint(L, 1);
 	int x = luaL_checkint(L, 1);
-	instance->setX(x);
+	instance()->setX(x);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_setY(lua_State *L)
 int w_setY(lua_State *L)
 {
 {
 	int y = luaL_checkint(L, 1);
 	int y = luaL_checkint(L, 1);
-	instance->setY(y);
+	instance()->setY(y);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -133,7 +133,7 @@ int w_setPosition(lua_State *L)
 {
 {
 	int x = luaL_checkint(L, 1);
 	int x = luaL_checkint(L, 1);
 	int y = luaL_checkint(L, 2);
 	int y = luaL_checkint(L, 2);
-	instance->setPosition(x, y);
+	instance()->setPosition(x, y);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -151,7 +151,7 @@ int w_isDown(lua_State *L)
 	}
 	}
 	buttonlist[counter] = Mouse::BUTTON_MAX_ENUM;
 	buttonlist[counter] = Mouse::BUTTON_MAX_ENUM;
 
 
-	luax_pushboolean(L, instance->isDown(buttonlist));
+	luax_pushboolean(L, instance()->isDown(buttonlist));
 	delete[] buttonlist;
 	delete[] buttonlist;
 	return 1;
 	return 1;
 }
 }
@@ -159,26 +159,26 @@ int w_isDown(lua_State *L)
 int w_setVisible(lua_State *L)
 int w_setVisible(lua_State *L)
 {
 {
 	bool b = luax_toboolean(L, 1);
 	bool b = luax_toboolean(L, 1);
-	instance->setVisible(b);
+	instance()->setVisible(b);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_isVisible(lua_State *L)
 int w_isVisible(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->isVisible());
+	luax_pushboolean(L, instance()->isVisible());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_setGrabbed(lua_State *L)
 int w_setGrabbed(lua_State *L)
 {
 {
 	bool b = luax_toboolean(L, 1);
 	bool b = luax_toboolean(L, 1);
-	instance->setGrabbed(b);
+	instance()->setGrabbed(b);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_isGrabbed(lua_State *L)
 int w_isGrabbed(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->isGrabbed());
+	luax_pushboolean(L, instance()->isGrabbed());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -212,6 +212,7 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_mouse(lua_State *L)
 extern "C" int luaopen_love_mouse(lua_State *L)
 {
 {
+	Mouse *instance = instance();
 	if (instance == nullptr)
 	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new love::mouse::sdl::Mouse(); });
 		luax_catchexcept(L, [&](){ instance = new love::mouse::sdl::Mouse(); });

+ 1 - 0
src/modules/physics/box2d/Physics.h

@@ -63,6 +63,7 @@ public:
 
 
 	// Implements Module.
 	// Implements Module.
 	const char *getName() const;
 	const char *getName() const;
+	virtual ModuleType getModuleType() const { return M_PHYSICS; }
 
 
 	/**
 	/**
 	 * Creates a new World.
 	 * Creates a new World.

+ 26 - 25
src/modules/physics/box2d/wrap_Physics.cpp

@@ -49,7 +49,7 @@ namespace physics
 namespace box2d
 namespace box2d
 {
 {
 
 
-static Physics *instance = 0;
+#define instance() (Module::getInstance<Physics>(Module::M_PHYSICS))
 
 
 int w_newWorld(lua_State *L)
 int w_newWorld(lua_State *L)
 {
 {
@@ -58,7 +58,7 @@ int w_newWorld(lua_State *L)
 	bool sleep = luax_optboolean(L, 3, true);
 	bool sleep = luax_optboolean(L, 3, true);
 
 
 	World *w;
 	World *w;
-	luax_catchexcept(L, [&](){ w = instance->newWorld(gx, gy, sleep); });
+	luax_catchexcept(L, [&](){ w = instance()->newWorld(gx, gy, sleep); });
 	luax_pushtype(L, "World", PHYSICS_WORLD_T, w);
 	luax_pushtype(L, "World", PHYSICS_WORLD_T, w);
 
 
 	return 1;
 	return 1;
@@ -76,7 +76,7 @@ int w_newBody(lua_State *L)
 		return luaL_error(L, "Invalid Body type: %s", typestr);
 		return luaL_error(L, "Invalid Body type: %s", typestr);
 
 
 	Body *body;
 	Body *body;
-	luax_catchexcept(L, [&](){ body = instance->newBody(world, x, y, btype); });
+	luax_catchexcept(L, [&](){ body = instance()->newBody(world, x, y, btype); });
 	luax_pushtype(L, "Body", PHYSICS_BODY_T, body);
 	luax_pushtype(L, "Body", PHYSICS_BODY_T, body);
 	return 1;
 	return 1;
 }
 }
@@ -87,7 +87,7 @@ int w_newFixture(lua_State *L)
 	Shape *shape = luax_checkshape(L, 2);
 	Shape *shape = luax_checkshape(L, 2);
 	float density = (float)luaL_optnumber(L, 3, 1.0f);
 	float density = (float)luaL_optnumber(L, 3, 1.0f);
 	Fixture *fixture;
 	Fixture *fixture;
-	luax_catchexcept(L, [&](){ fixture = instance->newFixture(body, shape, density); });
+	luax_catchexcept(L, [&](){ fixture = instance()->newFixture(body, shape, density); });
 	luax_pushtype(L, "Fixture", PHYSICS_FIXTURE_T, fixture);
 	luax_pushtype(L, "Fixture", PHYSICS_FIXTURE_T, fixture);
 	return 1;
 	return 1;
 }
 }
@@ -100,7 +100,7 @@ int w_newCircleShape(lua_State *L)
 	{
 	{
 		float radius = (float)luaL_checknumber(L, 1);
 		float radius = (float)luaL_checknumber(L, 1);
 		CircleShape *shape;
 		CircleShape *shape;
-		luax_catchexcept(L, [&](){ shape = instance->newCircleShape(radius); });
+		luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(radius); });
 		luax_pushtype(L, "CircleShape", PHYSICS_CIRCLE_SHAPE_T, shape);
 		luax_pushtype(L, "CircleShape", PHYSICS_CIRCLE_SHAPE_T, shape);
 		return 1;
 		return 1;
 	}
 	}
@@ -110,7 +110,7 @@ int w_newCircleShape(lua_State *L)
 		float y = (float)luaL_checknumber(L, 2);
 		float y = (float)luaL_checknumber(L, 2);
 		float radius = (float)luaL_checknumber(L, 3);
 		float radius = (float)luaL_checknumber(L, 3);
 		CircleShape *shape;
 		CircleShape *shape;
-		luax_catchexcept(L, [&](){ shape = instance->newCircleShape(x, y, radius); });
+		luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(x, y, radius); });
 		luax_pushtype(L, "CircleShape", PHYSICS_CIRCLE_SHAPE_T, shape);
 		luax_pushtype(L, "CircleShape", PHYSICS_CIRCLE_SHAPE_T, shape);
 		return 1;
 		return 1;
 	}
 	}
@@ -127,7 +127,7 @@ int w_newRectangleShape(lua_State *L)
 		float w = (float)luaL_checknumber(L, 1);
 		float w = (float)luaL_checknumber(L, 1);
 		float h = (float)luaL_checknumber(L, 2);
 		float h = (float)luaL_checknumber(L, 2);
 		PolygonShape *shape;
 		PolygonShape *shape;
-		luax_catchexcept(L, [&](){ shape = instance->newRectangleShape(w, h); });
+		luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(w, h); });
 		luax_pushtype(L, "PolygonShape", PHYSICS_POLYGON_SHAPE_T, shape);
 		luax_pushtype(L, "PolygonShape", PHYSICS_POLYGON_SHAPE_T, shape);
 		return 1;
 		return 1;
 	}
 	}
@@ -139,7 +139,7 @@ int w_newRectangleShape(lua_State *L)
 		float h = (float)luaL_checknumber(L, 4);
 		float h = (float)luaL_checknumber(L, 4);
 		float angle = (float)luaL_optnumber(L, 5, 0);
 		float angle = (float)luaL_optnumber(L, 5, 0);
 		PolygonShape *shape;
 		PolygonShape *shape;
-		luax_catchexcept(L, [&](){ shape = instance->newRectangleShape(x, y, w, h, angle); });
+		luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(x, y, w, h, angle); });
 		luax_pushtype(L, "PolygonShape", PHYSICS_POLYGON_SHAPE_T, shape);
 		luax_pushtype(L, "PolygonShape", PHYSICS_POLYGON_SHAPE_T, shape);
 		return 1;
 		return 1;
 	}
 	}
@@ -154,7 +154,7 @@ int w_newEdgeShape(lua_State *L)
 	float x2 = (float)luaL_checknumber(L, 3);
 	float x2 = (float)luaL_checknumber(L, 3);
 	float y2 = (float)luaL_checknumber(L, 4);
 	float y2 = (float)luaL_checknumber(L, 4);
 	EdgeShape *shape;
 	EdgeShape *shape;
-	luax_catchexcept(L, [&](){ shape = instance->newEdgeShape(x1, y1, x2, y2); });
+	luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(x1, y1, x2, y2); });
 	luax_pushtype(L, "EdgeShape", PHYSICS_EDGE_SHAPE_T, shape);
 	luax_pushtype(L, "EdgeShape", PHYSICS_EDGE_SHAPE_T, shape);
 	return 1;
 	return 1;
 }
 }
@@ -162,14 +162,14 @@ int w_newEdgeShape(lua_State *L)
 int w_newPolygonShape(lua_State *L)
 int w_newPolygonShape(lua_State *L)
 {
 {
 	int ret = 0;
 	int ret = 0;
-	luax_catchexcept(L, [&](){ ret = instance->newPolygonShape(L); });
+	luax_catchexcept(L, [&](){ ret = instance()->newPolygonShape(L); });
 	return ret;
 	return ret;
 }
 }
 
 
 int w_newChainShape(lua_State *L)
 int w_newChainShape(lua_State *L)
 {
 {
 	int ret = 0;
 	int ret = 0;
-	luax_catchexcept(L, [&](){ ret = instance->newChainShape(L); });
+	luax_catchexcept(L, [&](){ ret = instance()->newChainShape(L); });
 	return ret;
 	return ret;
 }
 }
 
 
@@ -184,7 +184,7 @@ int w_newDistanceJoint(lua_State *L)
 	bool collideConnected = luax_optboolean(L, 7, false);
 	bool collideConnected = luax_optboolean(L, 7, false);
 	DistanceJoint *j;
 	DistanceJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newDistanceJoint(body1, body2, x1, y1, x2, y2, collideConnected);
+		j = instance()->newDistanceJoint(body1, body2, x1, y1, x2, y2, collideConnected);
 	});
 	});
 	luax_pushtype(L, "DistanceJoint", PHYSICS_DISTANCE_JOINT_T, j);
 	luax_pushtype(L, "DistanceJoint", PHYSICS_DISTANCE_JOINT_T, j);
 	return 1;
 	return 1;
@@ -196,7 +196,7 @@ int w_newMouseJoint(lua_State *L)
 	float x = (float)luaL_checknumber(L, 2);
 	float x = (float)luaL_checknumber(L, 2);
 	float y = (float)luaL_checknumber(L, 3);
 	float y = (float)luaL_checknumber(L, 3);
 	MouseJoint *j;
 	MouseJoint *j;
-	luax_catchexcept(L, [&](){ j = instance->newMouseJoint(body, x, y); });
+	luax_catchexcept(L, [&](){ j = instance()->newMouseJoint(body, x, y); });
 	luax_pushtype(L, "MouseJoint", PHYSICS_MOUSE_JOINT_T, j);
 	luax_pushtype(L, "MouseJoint", PHYSICS_MOUSE_JOINT_T, j);
 	return 1;
 	return 1;
 }
 }
@@ -210,7 +210,7 @@ int w_newRevoluteJoint(lua_State *L)
 	bool collideConnected = luax_optboolean(L, 5, false);
 	bool collideConnected = luax_optboolean(L, 5, false);
 	RevoluteJoint *j;
 	RevoluteJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newRevoluteJoint(body1, body2, x, y, collideConnected);
+		j = instance()->newRevoluteJoint(body1, body2, x, y, collideConnected);
 	});
 	});
 	luax_pushtype(L, "RevoluteJoint", PHYSICS_REVOLUTE_JOINT_T, j);
 	luax_pushtype(L, "RevoluteJoint", PHYSICS_REVOLUTE_JOINT_T, j);
 	return 1;
 	return 1;
@@ -242,7 +242,7 @@ int w_newPrismaticJoint(lua_State *L)
 	}
 	}
 	PrismaticJoint *j;
 	PrismaticJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newPrismaticJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected);
+		j = instance()->newPrismaticJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected);
 	});
 	});
 	luax_pushtype(L, "PrismaticJoint", PHYSICS_PRISMATIC_JOINT_T, j);
 	luax_pushtype(L, "PrismaticJoint", PHYSICS_PRISMATIC_JOINT_T, j);
 	return 1;
 	return 1;
@@ -265,7 +265,7 @@ int w_newPulleyJoint(lua_State *L)
 
 
 	PulleyJoint *j;
 	PulleyJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newPulleyJoint(body1, body2, b2Vec2(gx1,gy1), b2Vec2(gx2,gy2), b2Vec2(x1,y1), b2Vec2(x2,y2), ratio, collideConnected);
+		j = instance()->newPulleyJoint(body1, body2, b2Vec2(gx1,gy1), b2Vec2(gx2,gy2), b2Vec2(x1,y1), b2Vec2(x2,y2), ratio, collideConnected);
 	});
 	});
 	luax_pushtype(L, "PulleyJoint", PHYSICS_PULLEY_JOINT_T, j);
 	luax_pushtype(L, "PulleyJoint", PHYSICS_PULLEY_JOINT_T, j);
 	return 1;
 	return 1;
@@ -280,7 +280,7 @@ int w_newGearJoint(lua_State *L)
 
 
 	GearJoint *j;
 	GearJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newGearJoint(joint1, joint2, ratio, collideConnected);
+		j = instance()->newGearJoint(joint1, joint2, ratio, collideConnected);
 	});
 	});
 	luax_pushtype(L, "GearJoint", PHYSICS_GEAR_JOINT_T, j);
 	luax_pushtype(L, "GearJoint", PHYSICS_GEAR_JOINT_T, j);
 	return 1;
 	return 1;
@@ -308,7 +308,7 @@ int w_newFrictionJoint(lua_State *L)
 	}
 	}
 	FrictionJoint *j;
 	FrictionJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newFrictionJoint(body1, body2, xA, yA, xB, yB, collideConnected);
+		j = instance()->newFrictionJoint(body1, body2, xA, yA, xB, yB, collideConnected);
 	});
 	});
 	luax_pushtype(L, "FrictionJoint", PHYSICS_FRICTION_JOINT_T, j);
 	luax_pushtype(L, "FrictionJoint", PHYSICS_FRICTION_JOINT_T, j);
 	return 1;
 	return 1;
@@ -336,7 +336,7 @@ int w_newWeldJoint(lua_State *L)
 	}
 	}
 	WeldJoint *j;
 	WeldJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newWeldJoint(body1, body2, xA, yA, xB, yB, collideConnected);
+		j = instance()->newWeldJoint(body1, body2, xA, yA, xB, yB, collideConnected);
 	});
 	});
 	luax_pushtype(L, "WeldJoint", PHYSICS_WELD_JOINT_T, j);
 	luax_pushtype(L, "WeldJoint", PHYSICS_WELD_JOINT_T, j);
 	return 1;
 	return 1;
@@ -369,7 +369,7 @@ int w_newWheelJoint(lua_State *L)
 
 
 	WheelJoint *j;
 	WheelJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newWheelJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected);
+		j = instance()->newWheelJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected);
 	});
 	});
 	luax_pushtype(L, "WheelJoint", PHYSICS_WHEEL_JOINT_T, j);
 	luax_pushtype(L, "WheelJoint", PHYSICS_WHEEL_JOINT_T, j);
 	return 1;
 	return 1;
@@ -387,7 +387,7 @@ int w_newRopeJoint(lua_State *L)
 	bool collideConnected = luax_optboolean(L, 8, false);
 	bool collideConnected = luax_optboolean(L, 8, false);
 	RopeJoint *j;
 	RopeJoint *j;
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
-		j = instance->newRopeJoint(body1, body2, x1, y1, x2, y2, maxLength, collideConnected);
+		j = instance()->newRopeJoint(body1, body2, x1, y1, x2, y2, maxLength, collideConnected);
 	});
 	});
 	luax_pushtype(L, "RopeJoint", PHYSICS_ROPE_JOINT_T, j);
 	luax_pushtype(L, "RopeJoint", PHYSICS_ROPE_JOINT_T, j);
 	return 1;
 	return 1;
@@ -402,12 +402,12 @@ int w_newMotorJoint(lua_State *L)
 	{
 	{
 		float correctionFactor = (float)luaL_checknumber(L, 3);
 		float correctionFactor = (float)luaL_checknumber(L, 3);
 		luax_catchexcept(L, [&]() {
 		luax_catchexcept(L, [&]() {
-			j = instance->newMotorJoint(body1, body2, correctionFactor);
+			j = instance()->newMotorJoint(body1, body2, correctionFactor);
 		});
 		});
 	}
 	}
 	else
 	else
 	{
 	{
-		luax_catchexcept(L, [&](){ j = instance->newMotorJoint(body1, body2); });
+		luax_catchexcept(L, [&](){ j = instance()->newMotorJoint(body1, body2); });
 	}
 	}
 	luax_pushtype(L, "MotorJoint", PHYSICS_MOTOR_JOINT_T, j);
 	luax_pushtype(L, "MotorJoint", PHYSICS_MOTOR_JOINT_T, j);
 	return 1;
 	return 1;
@@ -415,7 +415,7 @@ int w_newMotorJoint(lua_State *L)
 
 
 int w_getDistance(lua_State *L)
 int w_getDistance(lua_State *L)
 {
 {
-	return instance->getDistance(L);
+	return instance()->getDistance(L);
 }
 }
 
 
 int w_setMeter(lua_State *L)
 int w_setMeter(lua_State *L)
@@ -487,7 +487,8 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_physics(lua_State *L)
 extern "C" int luaopen_love_physics(lua_State *L)
 {
 {
-	if (instance == 0)
+	Physics *instance = instance();
+	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new Physics(); });
 		luax_catchexcept(L, [&](){ instance = new Physics(); });
 	}
 	}

+ 3 - 3
src/modules/sound/Sound.h

@@ -42,11 +42,11 @@ class Sound : public Module
 
 
 public:
 public:
 
 
-	/**
-	 * Destructor.
-	 **/
 	virtual ~Sound();
 	virtual ~Sound();
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_SOUND; }
+
 	/**
 	/**
 	 * Creates new SoundData from a decoder. Fully expands the
 	 * Creates new SoundData from a decoder. Fully expands the
 	 * encoded sound data into raw sound data. Not recommended
 	 * encoded sound data into raw sound data. Not recommended

+ 6 - 5
src/modules/sound/wrap_Sound.cpp

@@ -30,7 +30,7 @@ namespace love
 namespace sound
 namespace sound
 {
 {
 
 
-static Sound *instance = 0;
+#define instance() (Module::getInstance<Sound>(Module::M_SOUND))
 
 
 int w_newSoundData(lua_State *L)
 int w_newSoundData(lua_State *L)
 {
 {
@@ -43,7 +43,7 @@ int w_newSoundData(lua_State *L)
 		int bitDepth = luaL_optint(L, 3, Decoder::DEFAULT_BIT_DEPTH);
 		int bitDepth = luaL_optint(L, 3, Decoder::DEFAULT_BIT_DEPTH);
 		int channels = luaL_optint(L, 4, Decoder::DEFAULT_CHANNELS);
 		int channels = luaL_optint(L, 4, Decoder::DEFAULT_CHANNELS);
 
 
-		luax_catchexcept(L, [&](){ t = instance->newSoundData(samples, sampleRate, bitDepth, channels); });
+		luax_catchexcept(L, [&](){ t = instance()->newSoundData(samples, sampleRate, bitDepth, channels); });
 	}
 	}
 	// Must be string or decoder.
 	// Must be string or decoder.
 	else
 	else
@@ -55,7 +55,7 @@ int w_newSoundData(lua_State *L)
 			lua_replace(L, 1);
 			lua_replace(L, 1);
 		}
 		}
 
 
-		luax_catchexcept(L, [&](){ t = instance->newSoundData(luax_checkdecoder(L, 1)); });
+		luax_catchexcept(L, [&](){ t = instance()->newSoundData(luax_checkdecoder(L, 1)); });
 	}
 	}
 
 
 	luax_pushtype(L, "SoundData", SOUND_SOUND_DATA_T, t);
 	luax_pushtype(L, "SoundData", SOUND_SOUND_DATA_T, t);
@@ -69,7 +69,7 @@ int w_newDecoder(lua_State *L)
 
 
 	Decoder *t = nullptr;
 	Decoder *t = nullptr;
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&]() { t = instance->newDecoder(data, bufferSize); },
+		[&]() { t = instance()->newDecoder(data, bufferSize); },
 		[&]() { data->release(); }
 		[&]() { data->release(); }
 	);
 	);
 
 
@@ -97,7 +97,8 @@ static const lua_CFunction types[] =
 
 
 extern "C" int luaopen_love_sound(lua_State *L)
 extern "C" int luaopen_love_sound(lua_State *L)
 {
 {
-	if (instance == 0)
+	Sound *instance = instance();
+	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new lullaby::Sound(); });
 		luax_catchexcept(L, [&](){ instance = new lullaby::Sound(); });
 	}
 	}

+ 3 - 0
src/modules/system/System.h

@@ -50,6 +50,9 @@ public:
 
 
 	virtual ~System() {}
 	virtual ~System() {}
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_SYSTEM; }
+
 	/**
 	/**
 	 * Gets the current operating system.
 	 * Gets the current operating system.
 	 **/
 	 **/

+ 8 - 7
src/modules/system/wrap_System.cpp

@@ -27,30 +27,30 @@ namespace love
 namespace system
 namespace system
 {
 {
 
 
-static System *instance = nullptr;
+#define instance() (Module::getInstance<System>(Module::M_SYSTEM))
 
 
 int w_getOS(lua_State *L)
 int w_getOS(lua_State *L)
 {
 {
-	luax_pushstring(L, instance->getOS());
+	luax_pushstring(L, instance()->getOS());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getProcessorCount(lua_State *L)
 int w_getProcessorCount(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getProcessorCount());
+	lua_pushinteger(L, instance()->getProcessorCount());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_setClipboardText(lua_State *L)
 int w_setClipboardText(lua_State *L)
 {
 {
 	const char *text = luaL_checkstring(L, 1);
 	const char *text = luaL_checkstring(L, 1);
-	instance->setClipboardText(text);
+	instance()->setClipboardText(text);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getClipboardText(lua_State *L)
 int w_getClipboardText(lua_State *L)
 {
 {
-	luax_pushstring(L, instance->getClipboardText());
+	luax_pushstring(L, instance()->getClipboardText());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -59,7 +59,7 @@ int w_getPowerInfo(lua_State *L)
 	int seconds = -1, percent = -1;
 	int seconds = -1, percent = -1;
 	const char *str;
 	const char *str;
 
 
-	System::PowerState state = instance->getPowerInfo(seconds, percent);
+	System::PowerState state = instance()->getPowerInfo(seconds, percent);
 
 
 	if (!System::getConstant(state, str))
 	if (!System::getConstant(state, str))
 		str = "unknown";
 		str = "unknown";
@@ -82,7 +82,7 @@ int w_getPowerInfo(lua_State *L)
 int w_openURL(lua_State *L)
 int w_openURL(lua_State *L)
 {
 {
 	std::string url = luax_checkstring(L, 1);
 	std::string url = luax_checkstring(L, 1);
-	luax_pushboolean(L, instance->openURL(url));
+	luax_pushboolean(L, instance()->openURL(url));
 	return 1;
 	return 1;
 }
 }
 
 
@@ -99,6 +99,7 @@ static const luaL_Reg functions[] =
 
 
 extern "C" int luaopen_love_system(lua_State *L)
 extern "C" int luaopen_love_system(lua_State *L)
 {
 {
+	System *instance = instance();
 	if (instance == nullptr)
 	if (instance == nullptr)
 	{
 	{
 		instance = new love::system::sdl::System();
 		instance = new love::system::sdl::System();

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

@@ -107,7 +107,7 @@ void LuaThread::onError()
 	if (error.empty())
 	if (error.empty())
 		return;
 		return;
 
 
-	event::Event *event = (event::Event *) Module::findInstance("love.event.");
+	event::Event *event = Module::getInstance<event::Event>(Module::M_EVENT);
 	if (!event)
 	if (!event)
 		return;
 		return;
 
 

+ 1 - 0
src/modules/thread/ThreadModule.h

@@ -49,6 +49,7 @@ public:
 
 
 	// Implements Module.
 	// Implements Module.
 	virtual const char *getName() const;
 	virtual const char *getName() const;
+	virtual ModuleType getModuleType() const { return M_THREAD; }
 
 
 }; // ThreadModule
 }; // ThreadModule
 
 

+ 6 - 5
src/modules/thread/wrap_ThreadModule.cpp

@@ -32,7 +32,7 @@ namespace love
 namespace thread
 namespace thread
 {
 {
 
 
-static ThreadModule *instance = 0;
+#define instance() (Module::getInstance<ThreadModule>(Module::M_THREAD))
 
 
 int w_newThread(lua_State *L)
 int w_newThread(lua_State *L)
 {
 {
@@ -53,14 +53,14 @@ int w_newThread(lua_State *L)
 		data = luax_checktype<love::Data>(L, 1, "Data", DATA_T);
 		data = luax_checktype<love::Data>(L, 1, "Data", DATA_T);
 	}
 	}
 
 
-	LuaThread *t = instance->newThread(name, data);
+	LuaThread *t = instance()->newThread(name, data);
 	luax_pushtype(L, "Thread", THREAD_THREAD_T, t);
 	luax_pushtype(L, "Thread", THREAD_THREAD_T, t);
 	return 1;
 	return 1;
 }
 }
 
 
 int w_newChannel(lua_State *L)
 int w_newChannel(lua_State *L)
 {
 {
-	Channel *c = instance->newChannel();
+	Channel *c = instance()->newChannel();
 	luax_pushtype(L, "Channel", THREAD_CHANNEL_T, c);
 	luax_pushtype(L, "Channel", THREAD_CHANNEL_T, c);
 	return 1;
 	return 1;
 }
 }
@@ -68,7 +68,7 @@ int w_newChannel(lua_State *L)
 int w_getChannel(lua_State *L)
 int w_getChannel(lua_State *L)
 {
 {
 	std::string name = luax_checkstring(L, 1);
 	std::string name = luax_checkstring(L, 1);
-	Channel *c = instance->getChannel(name);
+	Channel *c = instance()->getChannel(name);
 	luax_pushtype(L, "Channel", THREAD_CHANNEL_T, c);
 	luax_pushtype(L, "Channel", THREAD_CHANNEL_T, c);
 	return 1;
 	return 1;
 }
 }
@@ -89,7 +89,8 @@ static const lua_CFunction types[] = {
 
 
 extern "C" int luaopen_love_thread(lua_State *L)
 extern "C" int luaopen_love_thread(lua_State *L)
 {
 {
-	if (instance == 0)
+	ThreadModule *instance = instance();
+	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new love::thread::ThreadModule(); });
 		luax_catchexcept(L, [&](){ instance = new love::thread::ThreadModule(); });
 	}
 	}

+ 3 - 3
src/modules/timer/Timer.h

@@ -33,11 +33,11 @@ class Timer : public Module
 {
 {
 public:
 public:
 
 
-	/**
-	 * Destructor.
-	 **/
 	virtual ~Timer() {}
 	virtual ~Timer() {}
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_TIMER; }
+
 	/**
 	/**
 	 * Measures the time between this call and the previous call,
 	 * Measures the time between this call and the previous call,
 	 * and updates internal values accordinly.
 	 * and updates internal values accordinly.

+ 9 - 8
src/modules/timer/wrap_Timer.cpp

@@ -30,41 +30,41 @@ namespace love
 namespace timer
 namespace timer
 {
 {
 
 
-static Timer *instance = 0;
+#define instance() (Module::getInstance<Timer>(Module::M_TIMER))
 
 
 int w_step(lua_State *)
 int w_step(lua_State *)
 {
 {
-	instance->step();
+	instance()->step();
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getDelta(lua_State *L)
 int w_getDelta(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getDelta());
+	lua_pushnumber(L, instance()->getDelta());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getFPS(lua_State *L)
 int w_getFPS(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getFPS());
+	lua_pushinteger(L, instance()->getFPS());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getAverageDelta(lua_State *L)
 int w_getAverageDelta(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getAverageDelta());
+	lua_pushnumber(L, instance()->getAverageDelta());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_sleep(lua_State *L)
 int w_sleep(lua_State *L)
 {
 {
-	instance->sleep(luaL_checknumber(L, 1));
+	instance()->sleep(luaL_checknumber(L, 1));
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getTime(lua_State *L)
 int w_getTime(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getTime());
+	lua_pushnumber(L, instance()->getTime());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -83,7 +83,8 @@ static const luaL_Reg functions[] =
 
 
 extern "C" int luaopen_love_timer(lua_State *L)
 extern "C" int luaopen_love_timer(lua_State *L)
 {
 {
-	if (instance == 0)
+	Timer *instance = instance();
+	if (instance == nullptr)
 	{
 	{
 		luax_catchexcept(L, [&](){ instance = new love::timer::sdl::Timer(); });
 		luax_catchexcept(L, [&](){ instance = new love::timer::sdl::Timer(); });
 	}
 	}

+ 5 - 5
src/modules/window/Window.cpp

@@ -110,14 +110,14 @@ StringMap<Window::FullscreenType, Window::FULLSCREEN_TYPE_MAX_ENUM>::Entry Windo
 
 
 StringMap<Window::FullscreenType, Window::FULLSCREEN_TYPE_MAX_ENUM> Window::fullscreenTypes(Window::fullscreenTypeEntries, sizeof(Window::fullscreenTypeEntries));
 StringMap<Window::FullscreenType, Window::FULLSCREEN_TYPE_MAX_ENUM> Window::fullscreenTypes(Window::fullscreenTypeEntries, sizeof(Window::fullscreenTypeEntries));
 
 
-StringMap<MessageBoxType, MESSAGEBOX_MAX_ENUM>::Entry Window::messageBoxTypeEntries[] =
+StringMap<Window::MessageBoxType, Window::MESSAGEBOX_MAX_ENUM>::Entry Window::messageBoxTypeEntries[] =
 {
 {
-	{"error", MESSAGEBOX_ERROR},
-	{"warning", MESSAGEBOX_WARNING},
-	{"info", MESSAGEBOX_INFO},
+	{"error", Window::MESSAGEBOX_ERROR},
+	{"warning", Window::MESSAGEBOX_WARNING},
+	{"info", Window::MESSAGEBOX_INFO},
 };
 };
 
 
-StringMap<MessageBoxType, MESSAGEBOX_MAX_ENUM> Window::messageBoxTypes(Window::messageBoxTypeEntries, sizeof(Window::messageBoxTypeEntries));
+StringMap<Window::MessageBoxType, Window::MESSAGEBOX_MAX_ENUM> Window::messageBoxTypes(Window::messageBoxTypeEntries, sizeof(Window::messageBoxTypeEntries));
 
 
 } // window
 } // window
 } // love
 } // love

+ 27 - 9
src/modules/window/Window.h

@@ -39,14 +39,6 @@ namespace window
 // whole thing here because it uses the Window::Type enum.
 // whole thing here because it uses the Window::Type enum.
 struct WindowSettings;
 struct WindowSettings;
 
 
-enum MessageBoxType
-{
-	MESSAGEBOX_ERROR,
-	MESSAGEBOX_WARNING,
-	MESSAGEBOX_INFO,
-	MESSAGEBOX_MAX_ENUM
-};
-
 class Window : public Module
 class Window : public Module
 {
 {
 public:
 public:
@@ -76,14 +68,39 @@ public:
 		FULLSCREEN_TYPE_MAX_ENUM
 		FULLSCREEN_TYPE_MAX_ENUM
 	};
 	};
 
 
+	enum MessageBoxType
+	{
+		MESSAGEBOX_ERROR,
+		MESSAGEBOX_WARNING,
+		MESSAGEBOX_INFO,
+		MESSAGEBOX_MAX_ENUM
+	};
+
 	struct WindowSize
 	struct WindowSize
 	{
 	{
 		int width;
 		int width;
 		int height;
 		int height;
 	};
 	};
 
 
+	struct MessageBoxData
+	{
+		MessageBoxType type;
+
+		std::string title;
+		std::string message;
+
+		std::vector<std::string> buttons;
+		int enterButtonIndex;
+		int escapeButtonIndex;
+
+		bool attachToWindow;
+	};
+
 	virtual ~Window();
 	virtual ~Window();
 
 
+	// Implements Module.
+	virtual ModuleType getModuleType() const { return M_WINDOW; }
+
 	virtual bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr) = 0;
 	virtual bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr) = 0;
 	virtual void getWindow(int &width, int &height, WindowSettings &settings) = 0;
 	virtual void getWindow(int &width, int &height, WindowSettings &settings) = 0;
 
 
@@ -128,7 +145,8 @@ public:
 
 
 	virtual const void *getHandle() const = 0;
 	virtual const void *getHandle() const = 0;
 
 
-	virtual void showMessageBox(MessageBoxType type, const char *title, const char *message) = 0;
+	virtual bool showMessageBox(MessageBoxType type, const std::string &title, const std::string &message, bool attachtowindow) = 0;
+	virtual int showMessageBox(const MessageBoxData &data) = 0;
 
 
 	//virtual static Window *createSingleton() = 0;
 	//virtual static Window *createSingleton() = 0;
 	//virtual static Window *getSingleton() = 0;
 	//virtual static Window *getSingleton() = 0;

+ 62 - 15
src/modules/window/sdl/Window.cpp

@@ -98,11 +98,20 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 		else
 		else
 		{
 		{
 			sdlflags |= SDL_WINDOW_FULLSCREEN;
 			sdlflags |= SDL_WINDOW_FULLSCREEN;
+			SDL_DisplayMode mode = {0, width, height, 0, 0};
 
 
 			// Fullscreen window creation will bug out if no mode can be used.
 			// Fullscreen window creation will bug out if no mode can be used.
-			SDL_DisplayMode mode = {0, width, height, 0, 0};
-			if (SDL_GetClosestDisplayMode(f.display, &mode, &mode) == 0)
-				return false;
+			if (SDL_GetClosestDisplayMode(f.display, &mode, &mode) == nullptr)
+			{
+				// GetClosestDisplayMode will fail if we request a size larger
+				// than the largest available display mode, so we'll try to use
+				// the largest (first) mode in that case.
+				if (SDL_GetDisplayMode(f.display, 0, &mode) < 0)
+					return false;
+			}
+
+			width = mode.w;
+			height = mode.h;
 		}
 		}
 	}
 	}
 
 
@@ -118,7 +127,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 		sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI;
 		sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI;
 #endif
 #endif
 
 
-	graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
+	graphics::Graphics *gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
 	if (gfx != nullptr)
 	if (gfx != nullptr)
 		gfx->unSetMode();
 		gfx->unSetMode();
 
 
@@ -431,7 +440,7 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
 		updateSettings(newsettings);
 		updateSettings(newsettings);
 
 
 		// Update the viewport size now instead of waiting for event polling.
 		// Update the viewport size now instead of waiting for event polling.
-		graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
+		graphics::Graphics *gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
 		if (gfx != nullptr)
 		if (gfx != nullptr)
 		{
 		{
 			int width = curMode.width;
 			int width = curMode.width;
@@ -668,25 +677,63 @@ const void *Window::getHandle() const
 	return window;
 	return window;
 }
 }
 
 
-void Window::showMessageBox(MessageBoxType type, const char *title, const char *message)
+SDL_MessageBoxFlags Window::convertMessageBoxType(MessageBoxType type) const
 {
 {
-	SDL_MessageBoxFlags sdlflags;
-
 	switch (type)
 	switch (type)
 	{
 	{
 	case MESSAGEBOX_ERROR:
 	case MESSAGEBOX_ERROR:
-		sdlflags = SDL_MESSAGEBOX_ERROR;
-		break;
+		return SDL_MESSAGEBOX_ERROR;
 	case MESSAGEBOX_WARNING:
 	case MESSAGEBOX_WARNING:
-		sdlflags = SDL_MESSAGEBOX_WARNING;
-		break;
+		return SDL_MESSAGEBOX_WARNING;
 	case MESSAGEBOX_INFO:
 	case MESSAGEBOX_INFO:
 	default:
 	default:
-		sdlflags = SDL_MESSAGEBOX_INFORMATION;
-		break;
+		return SDL_MESSAGEBOX_INFORMATION;
 	}
 	}
+}
+
+bool Window::showMessageBox(MessageBoxType type, const std::string &title, const std::string &message, bool attachtowindow)
+{
+	SDL_MessageBoxFlags flags = convertMessageBoxType(type);
+	SDL_Window *sdlwindow = attachtowindow ? window : nullptr;
+
+	return SDL_ShowSimpleMessageBox(flags, title.c_str(), message.c_str(), sdlwindow) >= 0;
+}
+
+int Window::showMessageBox(const MessageBoxData &data)
+{
+	SDL_MessageBoxData sdldata = {};
+
+	sdldata.flags = convertMessageBoxType(data.type);
+	sdldata.title = data.title.c_str();
+	sdldata.message = data.message.c_str();
+	sdldata.window = data.attachToWindow ? window : nullptr;
+
+	sdldata.numbuttons = (int) data.buttons.size();
+
+	std::vector<SDL_MessageBoxButtonData> sdlbuttons;
+
+	for (size_t i = 0; i < data.buttons.size(); i++)
+	{
+		SDL_MessageBoxButtonData sdlbutton = {};
+
+		sdlbutton.buttonid = (int) i;
+		sdlbutton.text = data.buttons[i].c_str();
+
+		if ((int) i == data.enterButtonIndex)
+			sdlbutton.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
+
+		if ((int) i == data.escapeButtonIndex)
+			sdlbutton.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
+
+		sdlbuttons.push_back(sdlbutton);
+	}
+
+	sdldata.buttons = &sdlbuttons[0];
+
+	int pressedbutton = -2;
+	SDL_ShowMessageBox(&sdldata, &pressedbutton);
 
 
-	SDL_ShowSimpleMessageBox(sdlflags, title, message, window);
+	return pressedbutton;
 }
 }
 
 
 love::window::Window *Window::createSingleton()
 love::window::Window *Window::createSingleton()

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

@@ -84,7 +84,8 @@ public:
 
 
 	const void *getHandle() const;
 	const void *getHandle() const;
 
 
-	void showMessageBox(MessageBoxType type, const char *title, const char *message);
+	bool showMessageBox(MessageBoxType type, const std::string &title, const std::string &message, bool attachtowindow);
+	int showMessageBox(const MessageBoxData &data);
 
 
 	static love::window::Window *createSingleton();
 	static love::window::Window *createSingleton();
 	static love::window::Window *getSingleton();
 	static love::window::Window *getSingleton();
@@ -99,6 +100,8 @@ private:
 	// Update the saved window settings based on the window's actual state.
 	// Update the saved window settings based on the window's actual state.
 	void updateSettings(const WindowSettings &newsettings);
 	void updateSettings(const WindowSettings &newsettings);
 
 
+	SDL_MessageBoxFlags convertMessageBoxType(MessageBoxType type) const;
+
 	std::string windowTitle;
 	std::string windowTitle;
 
 
 	struct _currentMode
 	struct _currentMode

+ 83 - 21
src/modules/window/wrap_Window.cpp

@@ -26,11 +26,11 @@ namespace love
 namespace window
 namespace window
 {
 {
 
 
-static Window *instance = nullptr;
+#define instance() (Module::getInstance<Window>(Module::M_WINDOW))
 
 
 int w_getDisplayCount(lua_State *L)
 int w_getDisplayCount(lua_State *L)
 {
 {
-	lua_pushinteger(L, instance->getDisplayCount());
+	lua_pushinteger(L, instance()->getDisplayCount());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -39,7 +39,7 @@ int w_getDisplayName(lua_State *L)
 	int index = luaL_checkint(L, 1) - 1;
 	int index = luaL_checkint(L, 1) - 1;
 
 
 	const char *name = nullptr;
 	const char *name = nullptr;
-	luax_catchexcept(L, [&](){ name = instance->getDisplayName(index); });
+	luax_catchexcept(L, [&](){ name = instance()->getDisplayName(index); });
 
 
 	lua_pushstring(L, name);
 	lua_pushstring(L, name);
 	return 1;
 	return 1;
@@ -59,7 +59,7 @@ int w_setMode(lua_State *L)
 
 
 	if (lua_isnoneornil(L, 3))
 	if (lua_isnoneornil(L, 3))
 	{
 	{
-		luax_pushboolean(L, instance->setWindow(w, h, 0));
+		luax_pushboolean(L, instance()->setWindow(w, h, 0));
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -113,7 +113,7 @@ int w_setMode(lua_State *L)
 	settings.display--;
 	settings.display--;
 
 
 	luax_catchexcept(L,
 	luax_catchexcept(L,
-		[&](){ luax_pushboolean(L, instance->setWindow(w, h, &settings)); }
+		[&](){ luax_pushboolean(L, instance()->setWindow(w, h, &settings)); }
 	);
 	);
 
 
 	return 1;
 	return 1;
@@ -123,7 +123,7 @@ int w_getMode(lua_State *L)
 {
 {
 	int w, h;
 	int w, h;
 	WindowSettings settings;
 	WindowSettings settings;
-	instance->getWindow(w, h, settings);
+	instance()->getWindow(w, h, settings);
 	lua_pushnumber(L, w);
 	lua_pushnumber(L, w);
 	lua_pushnumber(L, h);
 	lua_pushnumber(L, h);
 
 
@@ -176,7 +176,7 @@ int w_getFullscreenModes(lua_State *L)
 {
 {
 	int displayindex = luaL_optint(L, 1, 1) - 1;
 	int displayindex = luaL_optint(L, 1, 1) - 1;
 
 
-	std::vector<Window::WindowSize> modes = instance->getFullscreenSizes(displayindex);
+	std::vector<Window::WindowSize> modes = instance()->getFullscreenSizes(displayindex);
 
 
 	lua_createtable(L, modes.size(), 0);
 	lua_createtable(L, modes.size(), 0);
 
 
@@ -212,9 +212,9 @@ int w_setFullscreen(lua_State *L)
 
 
 	bool success = false;
 	bool success = false;
 	if (fstype == Window::FULLSCREEN_TYPE_MAX_ENUM)
 	if (fstype == Window::FULLSCREEN_TYPE_MAX_ENUM)
-		success = instance->setFullscreen(fullscreen);
+		success = instance()->setFullscreen(fullscreen);
 	else
 	else
-		success = instance->setFullscreen(fullscreen, fstype);
+		success = instance()->setFullscreen(fullscreen, fstype);
 
 
 	luax_pushboolean(L, success);
 	luax_pushboolean(L, success);
 	return 1;
 	return 1;
@@ -224,7 +224,7 @@ int w_getFullscreen(lua_State *L)
 {
 {
 	int w, h;
 	int w, h;
 	WindowSettings settings;
 	WindowSettings settings;
-	instance->getWindow(w, h, settings);
+	instance()->getWindow(w, h, settings);
 
 
 	const char *typestr;
 	const char *typestr;
 	if (!Window::getConstant(settings.fstype, typestr))
 	if (!Window::getConstant(settings.fstype, typestr))
@@ -237,7 +237,7 @@ int w_getFullscreen(lua_State *L)
 
 
 int w_isCreated(lua_State *L)
 int w_isCreated(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->isCreated());
+	luax_pushboolean(L, instance()->isCreated());
 	return 1;
 	return 1;
 }
 }
 
 
@@ -245,7 +245,7 @@ int w_getDesktopDimensions(lua_State *L)
 {
 {
 	int width = 0, height = 0;
 	int width = 0, height = 0;
 	int displayindex = luaL_optint(L, 1, 1) - 1;
 	int displayindex = luaL_optint(L, 1, 1) - 1;
-	instance->getDesktopDimensions(displayindex, width, height);
+	instance()->getDesktopDimensions(displayindex, width, height);
 	lua_pushinteger(L, width);
 	lua_pushinteger(L, width);
 	lua_pushinteger(L, height);
 	lua_pushinteger(L, height);
 	return 2;
 	return 2;
@@ -254,13 +254,13 @@ int w_getDesktopDimensions(lua_State *L)
 int w_setIcon(lua_State *L)
 int w_setIcon(lua_State *L)
 {
 {
 	image::ImageData *i = luax_checktype<image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
 	image::ImageData *i = luax_checktype<image::ImageData>(L, 1, "ImageData", IMAGE_IMAGE_DATA_T);
-	luax_pushboolean(L, instance->setIcon(i));
+	luax_pushboolean(L, instance()->setIcon(i));
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getIcon(lua_State *L)
 int w_getIcon(lua_State *L)
 {
 {
-	image::ImageData *i = instance->getIcon();
+	image::ImageData *i = instance()->getIcon();
 	if (i)
 	if (i)
 	{
 	{
 		i->retain();
 		i->retain();
@@ -274,46 +274,106 @@ int w_getIcon(lua_State *L)
 int w_setTitle(lua_State *L)
 int w_setTitle(lua_State *L)
 {
 {
 	std::string title = luax_checkstring(L, 1);
 	std::string title = luax_checkstring(L, 1);
-	instance->setWindowTitle(title);
+	instance()->setWindowTitle(title);
 	return 0;
 	return 0;
 }
 }
 
 
 int w_getTitle(lua_State *L)
 int w_getTitle(lua_State *L)
 {
 {
-	luax_pushstring(L, instance->getWindowTitle());
+	luax_pushstring(L, instance()->getWindowTitle());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_hasFocus(lua_State *L)
 int w_hasFocus(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->hasFocus());
+	luax_pushboolean(L, instance()->hasFocus());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_hasMouseFocus(lua_State *L)
 int w_hasMouseFocus(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->hasMouseFocus());
+	luax_pushboolean(L, instance()->hasMouseFocus());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_isVisible(lua_State *L)
 int w_isVisible(lua_State *L)
 {
 {
-	luax_pushboolean(L, instance->isVisible());
+	luax_pushboolean(L, instance()->isVisible());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_getPixelScale(lua_State *L)
 int w_getPixelScale(lua_State *L)
 {
 {
-	lua_pushnumber(L, instance->getPixelScale());
+	lua_pushnumber(L, instance()->getPixelScale());
 	return 1;
 	return 1;
 }
 }
 
 
 int w_minimize(lua_State* /*L*/)
 int w_minimize(lua_State* /*L*/)
 {
 {
-	instance->minimize();
+	instance()->minimize();
 	return 0;
 	return 0;
 }
 }
 
 
+int w_showMessageBox(lua_State *L)
+{
+	Window::MessageBoxData data = {};
+
+	const char *typestr = luaL_checkstring(L, 1);
+	if (!Window::getConstant(typestr, data.type))
+		return luaL_error(L, "Invalid messagebox type: %s", typestr);
+
+	data.title = luaL_checkstring(L, 2);
+	data.message = luaL_checkstring(L, 3);
+
+	// If we have a table argument, we assume a list of button names, which
+	// means we should use the more complex message box API.
+	if (lua_istable(L, 4))
+	{
+		size_t numbuttons = lua_objlen(L, 4);
+		if (numbuttons == 0)
+			return luaL_error(L, "Must have at least one messagebox button.");
+
+		// Array of button names.
+		for (size_t i = 0; i < numbuttons; i++)
+		{
+			lua_rawgeti(L, 4, i + 1);
+			data.buttons.push_back(luax_checkstring(L, -1));
+			lua_pop(L, 1);
+		}
+
+		// Optional table entry specifying the button to use when enter is pressed.
+		lua_getfield(L, 4, "enterbutton");
+		if (!lua_isnoneornil(L, -1))
+			data.enterButtonIndex = luaL_checkint(L, -1) - 1;
+		else
+			data.enterButtonIndex = 0;
+		lua_pop(L, 1);
+
+		// Optional table entry specifying the button to use when esc is pressed.
+		lua_getfield(L, 4, "escapebutton");
+		if (!lua_isnoneornil(L, -1))
+			data.escapeButtonIndex = luaL_checkint(L, -1) - 1;
+		else
+			data.escapeButtonIndex = (int) data.buttons.size() - 1;
+		lua_pop(L, 1);
+
+		data.attachToWindow = luax_optboolean(L, 5, true);
+
+		int pressedbutton = instance()->showMessageBox(data);
+		lua_pushinteger(L, pressedbutton + 1);
+	}
+	else
+	{
+		data.attachToWindow = luax_optboolean(L, 4, true);
+
+		// Display a simple message box.
+		bool success = instance()->showMessageBox(data.type, data.title, data.message, data.attachToWindow);
+		luax_pushboolean(L, success);
+	}
+
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 static const luaL_Reg functions[] =
 {
 {
 	{ "getDisplayCount", w_getDisplayCount },
 	{ "getDisplayCount", w_getDisplayCount },
@@ -334,11 +394,13 @@ static const luaL_Reg functions[] =
 	{ "isVisible", w_isVisible },
 	{ "isVisible", w_isVisible },
 	{ "getPixelScale", w_getPixelScale },
 	{ "getPixelScale", w_getPixelScale },
 	{ "minimize", w_minimize },
 	{ "minimize", w_minimize },
+	{ "showMessageBox", w_showMessageBox },
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 
 extern "C" int luaopen_love_window(lua_State *L)
 extern "C" int luaopen_love_window(lua_State *L)
 {
 {
+	Window *instance = nullptr;
 	luax_catchexcept(L, [&](){ instance = sdl::Window::createSingleton(); });
 	luax_catchexcept(L, [&](){ instance = sdl::Window::createSingleton(); });
 
 
 	WrappedModule w;
 	WrappedModule w;

+ 1 - 0
src/modules/window/wrap_Window.h

@@ -47,6 +47,7 @@ int w_hasMouseFocus(lua_State *L);
 int w_isVisible(lua_State *L);
 int w_isVisible(lua_State *L);
 int w_getPixelScale(lua_State *L);
 int w_getPixelScale(lua_State *L);
 int w_minimize(lua_State *L);
 int w_minimize(lua_State *L);
+int w_showMessageBox(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_window(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_window(lua_State *L);
 
 
 } // window
 } // window