diff --git a/platform/macosx/love.xcodeproj/project.pbxproj b/platform/macosx/love.xcodeproj/project.pbxproj index 329bc2c87..9f5618c67 100644 --- a/platform/macosx/love.xcodeproj/project.pbxproj +++ b/platform/macosx/love.xcodeproj/project.pbxproj @@ -8,8 +8,12 @@ /* Begin PBXBuildFile section */ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + A5474CEF1624903B00C8EEAC /* math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5474CEE1624903B00C8EEAC /* math.cpp */; }; A901B882143B65C500D77063 /* DrawQable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A901B880143B65C400D77063 /* DrawQable.cpp */; }; A901B885143B661400D77063 /* Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A901B883143B661300D77063 /* Quad.cpp */; }; + A911D2DB15DFECC8005B7EB8 /* Module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A911D2DA15DFECC8005B7EB8 /* Module.cpp */; }; + A911D3C815DFF24D005B7EB8 /* Game_Music_Emu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */; }; + A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */; }; A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E4810420B4A007D418B /* FreeType.framework */; }; A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5210420B57007D418B /* SDL.framework */; }; A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; }; @@ -252,6 +256,7 @@ A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */, A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */, A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */, + A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */, ); name = "Copy Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -261,10 +266,13 @@ /* Begin PBXFileReference section */ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 8D1107320486CEB800E47090 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; }; + A5474CEE1624903B00C8EEAC /* math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = math.cpp; sourceTree = ""; }; A901B880143B65C400D77063 /* DrawQable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawQable.cpp; sourceTree = ""; }; A901B881143B65C400D77063 /* DrawQable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawQable.h; sourceTree = ""; }; A901B883143B661300D77063 /* Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Quad.cpp; sourceTree = ""; }; A901B884143B661300D77063 /* Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Quad.h; sourceTree = ""; }; + A911D2DA15DFECC8005B7EB8 /* Module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Module.cpp; sourceTree = ""; }; + A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Game_Music_Emu.framework; path = /Library/Frameworks/Game_Music_Emu.framework; sourceTree = ""; }; A9255DEA1043188D00BA1496 /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = ""; }; A9255DEB1043188D00BA1496 /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = ""; }; A9255E021043195A00BA1496 /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = /Library/Frameworks/Vorbis.framework; sourceTree = ""; }; @@ -740,11 +748,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A9255F461043247300BA1496 /* IL.framework in Frameworks */, - A9255EE810431BD000BA1496 /* Vorbis.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, A93E6E4910420B4A007D418B /* OpenAL.framework in Frameworks */, A93E6E4A10420B4A007D418B /* OpenGL.framework in Frameworks */, + A9255F461043247300BA1496 /* IL.framework in Frameworks */, + A9255EE810431BD000BA1496 /* Vorbis.framework in Frameworks */, A93E6E4B10420B4A007D418B /* FreeType.framework in Frameworks */, A93E6E5410420B57007D418B /* SDL.framework in Frameworks */, A93E6E5510420B57007D418B /* Lua.framework in Frameworks */, @@ -752,6 +760,7 @@ A9D307EA106635C3004FEDF8 /* physfs.framework in Frameworks */, A9F16927109E7BAD00FC83D1 /* libmodplug.framework in Frameworks */, A9F169A7109E824900FC83D1 /* mpg123.framework in Frameworks */, + A911D3C815DFF24D005B7EB8 /* Game_Music_Emu.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -761,6 +770,7 @@ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( + A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */, A9F169A6109E824900FC83D1 /* mpg123.framework */, A9F16926109E7BAD00FC83D1 /* libmodplug.framework */, A9D307E9106635C3004FEDF8 /* physfs.framework */, @@ -852,11 +862,13 @@ A93E69E010420ABF007D418B /* Exception.cpp */, A93E69E110420ABF007D418B /* Exception.h */, A9A5BE4C14A2D2D000D9931C /* int.h */, + A5474CEE1624903B00C8EEAC /* math.cpp */, A93E69E210420ABF007D418B /* math.h */, A93E69E310420ABF007D418B /* Matrix.cpp */, A93E69E410420ABF007D418B /* Matrix.h */, A9D5C47C142E32ED0044ECF7 /* Memoizer.cpp */, A9D5C47B142E31350044ECF7 /* Memoizer.h */, + A911D2DA15DFECC8005B7EB8 /* Module.cpp */, A93E69E710420ABF007D418B /* Module.h */, A93E69E810420ABF007D418B /* Object.cpp */, A93E69E910420ABF007D418B /* Object.h */, @@ -1943,6 +1955,8 @@ A9642D7514D1A66000CE0B02 /* OpenGL.cpp in Sources */, A9F6E6AE15A1080D00C86200 /* love.cpp in Sources */, A9F6E6B115A1099C00C86200 /* GmeDecoder.cpp in Sources */, + A911D2DB15DFECC8005B7EB8 /* Module.cpp in Sources */, + A5474CEF1624903B00C8EEAC /* math.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1959,6 +1973,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = love_Prefix.pch; INSTALL_PATH = "$(HOME)/Applications"; + OTHER_CFLAGS = "-DLOVE_SUPPORT_GME=1"; PRODUCT_NAME = love; }; name = Debug; @@ -1971,6 +1986,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = love_Prefix.pch; INSTALL_PATH = "$(HOME)/Applications"; + OTHER_CFLAGS = "-DLOVE_SUPPORT_GME=1"; PRODUCT_NAME = love; }; name = Release; diff --git a/platform/msvc2010/liblove.vcxproj b/platform/msvc2010/liblove.vcxproj index 824bdb221..db1abbe72 100644 --- a/platform/msvc2010/liblove.vcxproj +++ b/platform/msvc2010/liblove.vcxproj @@ -296,8 +296,10 @@ + + diff --git a/platform/msvc2010/liblove.vcxproj.filters b/platform/msvc2010/liblove.vcxproj.filters index 4dfb51d48..26676fa14 100644 --- a/platform/msvc2010/liblove.vcxproj.filters +++ b/platform/msvc2010/liblove.vcxproj.filters @@ -738,6 +738,12 @@ modules\love + + common + + + common + diff --git a/platform/msvc2010/love.sln b/platform/msvc2010/love.sln index e78aa0104..ef69a54a3 100644 --- a/platform/msvc2010/love.sln +++ b/platform/msvc2010/love.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual C++ Express 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "love", "love.vcxproj", "{0078B97A-F6DB-E014-BED9-BE378D93CEA4}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "love", "love.vcxproj", "{B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}" ProjectSection(ProjectDependencies) = postProject {A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8} = {A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8} EndProjectSection @@ -18,17 +18,17 @@ Global Release Static|x64 = Release Static|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Debug Dynamic|Win32.ActiveCfg = Debug Dynamic|Win32 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Debug Dynamic|Win32.Build.0 = Debug Dynamic|Win32 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Debug Dynamic|x64.ActiveCfg = Debug Dynamic|x64 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|Win32.ActiveCfg = Release Dynamic|Win32 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|Win32.Build.0 = Release Dynamic|Win32 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|x64.ActiveCfg = Release Dynamic|x64 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Dynamic|x64.Build.0 = Release Dynamic|x64 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|Win32.ActiveCfg = Release Static|Win32 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|Win32.Build.0 = Release Static|Win32 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|x64.ActiveCfg = Release Static|x64 - {0078B97A-F6DB-E014-BED9-BE378D93CEA4}.Release Static|x64.Build.0 = Release Static|x64 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Debug Dynamic|Win32.ActiveCfg = Debug Dynamic|Win32 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Debug Dynamic|Win32.Build.0 = Debug Dynamic|Win32 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Debug Dynamic|x64.ActiveCfg = Debug Dynamic|x64 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|Win32.ActiveCfg = Release Dynamic|Win32 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|Win32.Build.0 = Release Dynamic|Win32 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|x64.ActiveCfg = Release Dynamic|x64 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Dynamic|x64.Build.0 = Release Dynamic|x64 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|Win32.ActiveCfg = Release Static|Win32 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|Win32.Build.0 = Release Static|Win32 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|x64.ActiveCfg = Release Static|x64 + {B496CCF6-9B6D-0794-8F41-67A6EC86B4AA}.Release Static|x64.Build.0 = Release Static|x64 {A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8}.Debug Dynamic|Win32.ActiveCfg = Debug Dynamic|Win32 {A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8}.Debug Dynamic|Win32.Build.0 = Debug Dynamic|Win32 {A3FCC735-3E18-4D6B-9DA9-01D9E910B7F8}.Debug Dynamic|x64.ActiveCfg = Debug Dynamic|x64 diff --git a/platform/msvc2010/love.vcxproj b/platform/msvc2010/love.vcxproj index 511f92fe1..190e435fb 100644 --- a/platform/msvc2010/love.vcxproj +++ b/platform/msvc2010/love.vcxproj @@ -125,7 +125,7 @@ Level3 ProgramDatabase Disabled - include\SDL;..\..\src;%(AdditionalIncludeDirectories) + include;include\SDL;..\..\src;%(AdditionalIncludeDirectories) false @@ -146,7 +146,7 @@ Level3 ProgramDatabase Disabled - include\SDL;..\..\src;%(AdditionalIncludeDirectories) + include;include\SDL;..\..\src;%(AdditionalIncludeDirectories) false @@ -165,7 +165,7 @@ MultiThreadedDLL Level1 ProgramDatabase - include\SDL;..\..\src;%(AdditionalIncludeDirectories) + include;include\SDL;..\..\src;%(AdditionalIncludeDirectories) true true false @@ -189,7 +189,7 @@ MultiThreadedDLL Level1 ProgramDatabase - include\SDL;..\..\src;%(AdditionalIncludeDirectories) + include;include\SDL;..\..\src;%(AdditionalIncludeDirectories) true true false @@ -208,7 +208,7 @@ - include\SDL;..\..\src;%(AdditionalIncludeDirectories) + include;include\SDL;..\..\src;%(AdditionalIncludeDirectories) true NDEBUG;%(PreprocessorDefinitions) true @@ -227,7 +227,7 @@ - include\SDL;..\..\src;%(AdditionalIncludeDirectories) + include;include\SDL;..\..\src;%(AdditionalIncludeDirectories) true NDEBUG;%(PreprocessorDefinitions) true diff --git a/platform/unix/automagic b/platform/unix/automagic index dfa3e4c6b..eca181b0d 100755 --- a/platform/unix/automagic +++ b/platform/unix/automagic @@ -18,7 +18,7 @@ AUTOMAKE=$(which automake) [[ -x ${AUTOMAKE} ]] || die "Could not find automake." automagic() { - cp platform/unix/configure.in . + cp platform/unix/configure.ac . cp platform/unix/Makefile.am . if ! sh platform/unix/gen-makefile; then diff --git a/platform/unix/configure.in b/platform/unix/configure.ac similarity index 98% rename from platform/unix/configure.in rename to platform/unix/configure.ac index 2ab096e06..8ba3bc264 100644 --- a/platform/unix/configure.in +++ b/platform/unix/configure.ac @@ -6,7 +6,7 @@ AC_CONFIG_SRCDIR([src/love.cpp]) AM_INIT_AUTOMAKE([foreign -Wall foreign tar-ustar silent-rules]) AM_SILENT_RULES AC_PREFIX_DEFAULT([/usr]) -AM_PROG_AR +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_PROG_LIBTOOL AC_PROG_CC AC_PROG_CXX diff --git a/src/common/Module.cpp b/src/common/Module.cpp new file mode 100644 index 000000000..6970bb37f --- /dev/null +++ b/src/common/Module.cpp @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2006-2012 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +// LOVE +#include "Module.h" +#include "Exception.h" + +// std +#include +#include +#include + +namespace +{ + std::map registry; +} // anonymous namespace + +namespace love +{ + void Module::registerInstance(Module *instance) + { + if (instance == NULL) + throw Exception("Module instance is NULL"); + + std::string name(instance->getName()); + + std::map::iterator it = registry.find(name); + + if (registry.end() != it) + { + if (it->second == instance) + return; + throw Exception("Module %s already registered!", instance->getName()); + } + + registry.insert(make_pair(name, instance)); + } + + Module *Module::getInstance(const char *name) + { + std::map::iterator it = registry.find(std::string(name)); + + if (registry.end() == it) + return NULL; + + return it->second; + } +} // namespace love diff --git a/src/common/Module.h b/src/common/Module.h index a1f98711a..0e36ddac1 100644 --- a/src/common/Module.h +++ b/src/common/Module.h @@ -48,6 +48,21 @@ public: **/ virtual const char *getName() const = 0; + /** + * Add module to internal registry. To be used /only/ in + * runtime.cpp:luax_register_module() + * @param instance The module instance. + */ + static void registerInstance(Module *instance); + + /** + * Retrieve module instance from internal registry. May return NULL + * if module not registered. + * @param name The full name of the module. + * @returns Module instance of NULL if the module is not registered. + */ + static Module *getInstance(const char *name); + }; // Module } // love diff --git a/src/common/math.cpp b/src/common/math.cpp new file mode 100644 index 000000000..facece23d --- /dev/null +++ b/src/common/math.cpp @@ -0,0 +1,33 @@ +#include "math.h" +#include +#include + +namespace +{ + // The Box–Muller transform generates two random numbers, one of which we + // cache here. A value of +infinity is used to signal the cache is invalid + // and that new numbers have to be generated. + float last_randnormal = std::numeric_limits::infinity(); +} + +namespace love +{ + +float random_normal(float o) +{ + // number in cache? + if (last_randnormal != std::numeric_limits::infinity()) + { + float r = last_randnormal; + last_randnormal = std::numeric_limits::infinity(); + return r * o; + } + + // else: generate numbers using the Box-Muller transform + float a = sqrt(-2.0f * log(random())); + float b = float(LOVE_M_PI) * 2.0f * random(); + last_randnormal = a * cos(b); + return a * sin(b) * o; +} + +} // namespace love diff --git a/src/common/math.h b/src/common/math.h index 44979d4b2..683ef46a6 100644 --- a/src/common/math.h +++ b/src/common/math.h @@ -22,6 +22,7 @@ #define LOVE_MATH_H #include // for CHAR_BIT +#include // for rand() and RAND_MAX /* Definitions of useful mathematical constants * M_E - e @@ -80,6 +81,42 @@ inline float next_p2(float x) return static_cast(next_p2(static_cast(x))); } +/** + * Draws a random number from a uniform distribution. + * @returns Uniformly distributed random number in [0:1). + */ +inline float random() +{ + // to satisfy picky compilers... + return float(double(rand() % RAND_MAX) / double(RAND_MAX)); +} + +/** + * Draws a random number from a uniform distribution. + * @return Uniformly distributed random number in [0:max). + */ +inline float random(float max) +{ + return random() * max; +} + +/** + * Draws a random number from a uniform distribution. + * @return Uniformly distributed random number in [min:max). + */ +inline float random(float min, float max) +{ + return random(max - min) + min; +} + +/** + * Draws a random number from a normal/gaussian distribution. + * @param o Standard deviation of the distribution. + * @returns Normal distributed random number with mean 0 and variance o^2. + */ +float random_normal(float o = 1.); +#define random_gaussian random_normal + } // love #endif // LOVE_MATH_H diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index d7f45a33d..38de20f20 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -196,6 +196,9 @@ int luax_register_module(lua_State *L, const WrappedModule &m) lua_setfield(L, -3, m.name); // love.graphics = table lua_remove(L, -2); // love + // Register module instance + Module::registerInstance(m.module); + return 1; } diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index bd4c18a35..4168b0fb1 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -91,22 +91,24 @@ Message *Event::convert(SDL_Event &e) switch (e.type) { case SDL_KEYDOWN: - if (keys.find(e.key.keysym.sym, key) && love::event::Event::keys.find(key, txt)) - { - arg1 = new Variant(txt, strlen(txt)); - arg2 = new Variant((double) e.key.keysym.unicode); - msg = new Message("keypressed", arg1, arg2); - arg1->release(); - arg2->release(); - } + if (!keys.find(e.key.keysym.sym, key)) + key = love::keyboard::Keyboard::KEY_UNKNOWN; + if (!love::event::Event::keys.find(key, txt)) + txt = "unknown"; + arg1 = new Variant(txt, strlen(txt)); + arg2 = new Variant((double) e.key.keysym.unicode); + msg = new Message("keypressed", arg1, arg2); + arg1->release(); + arg2->release(); break; case SDL_KEYUP: - if (keys.find(e.key.keysym.sym, key) && love::event::Event::keys.find(key, txt)) - { - arg1 = new Variant(txt, strlen(txt)); - msg = new Message("keyreleased", arg1); - arg1->release(); - } + if (!keys.find(e.key.keysym.sym, key)) + key = love::keyboard::Keyboard::KEY_UNKNOWN; + if (!love::event::Event::keys.find(key, txt)) + txt = "unknown"; + arg1 = new Variant(txt, strlen(txt)); + msg = new Message("keyreleased", arg1); + arg1->release(); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: diff --git a/src/modules/filesystem/File.h b/src/modules/filesystem/File.h index 638de6598..ac12721c6 100644 --- a/src/modules/filesystem/File.h +++ b/src/modules/filesystem/File.h @@ -29,6 +29,7 @@ #include "common/Object.h" #include "common/StringMap.h" #include "common/int.h" +#include "FileData.h" namespace love { @@ -93,7 +94,7 @@ public: * @param size The number of bytes to attempt reading, or -1 for EOF. * @return A newly allocated Data object. **/ - virtual Data *read(int64 size = ALL) = 0; + virtual FileData *read(int64 size = ALL) = 0; /** * Reads data into the destination buffer. diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 0ca71bc83..1f40cb7bd 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -111,7 +111,7 @@ int64 File::getSize() } -Data *File::read(int64 size) +FileData *File::read(int64 size) { bool isOpen = (file != 0); diff --git a/src/modules/filesystem/physfs/File.h b/src/modules/filesystem/physfs/File.h index 856a31879..6aa3d9100 100644 --- a/src/modules/filesystem/physfs/File.h +++ b/src/modules/filesystem/physfs/File.h @@ -69,7 +69,7 @@ public: bool open(Mode mode); bool close(); int64 getSize(); - Data *read(int64 size = ALL); + FileData *read(int64 size = ALL); int64 read(void *dst, int64 size); bool write(const void *data, int64 size); bool write(const Data *data, int64 size = ALL); diff --git a/src/modules/font/ImageRasterizer.cpp b/src/modules/font/ImageRasterizer.cpp index 9891a18fa..21f45539b 100644 --- a/src/modules/font/ImageRasterizer.cpp +++ b/src/modules/font/ImageRasterizer.cpp @@ -131,6 +131,16 @@ void ImageRasterizer::load() widths[c] = (end - start); } + // Find spacing of last glyph + if (length > 0) + { + start = end; + while (start < imgw && equal(pixels[start], spacer)) + ++start; + + spacing[glyphs[length - 1]] = (start > end) ? (start - end) : 0; + } + // Replace spacer color with an empty pixel for (unsigned int i = 0; i < imgs; ++i) { diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 5f4205150..cd8403f0e 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -156,6 +156,7 @@ StringMap Graphics::pointStyles( StringMap::Entry Graphics::supportEntries[] = { { "canvas", Graphics::SUPPORT_CANVAS }, + { "hdrcanvas", Graphics::SUPPORT_HDR_CANVAS }, { "pixeleffect", Graphics::SUPPORT_PIXELEFFECT }, { "npot", Graphics::SUPPORT_NPOT }, { "subtractive", Graphics::SUPPORT_SUBTRACTIVE }, diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 13d2cc660..ed0da81a2 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -85,6 +85,7 @@ public: enum Support { SUPPORT_CANVAS = 1, + SUPPORT_HDR_CANVAS, SUPPORT_PIXELEFFECT, SUPPORT_NPOT, SUPPORT_SUBTRACTIVE, diff --git a/src/modules/graphics/Quad.h b/src/modules/graphics/Quad.h index 341bc224d..f5c804961 100644 --- a/src/modules/graphics/Quad.h +++ b/src/modules/graphics/Quad.h @@ -50,11 +50,6 @@ public: virtual void flip(bool x, bool y) = 0; - /** - * Mirror texture coordinates around 0.5 - */ - virtual void mirror(bool x, bool y) = 0; - /** * Gets a pointer to the vertices. **/ diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 88f50586b..72708f4a1 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -42,9 +42,10 @@ struct FramebufferStrategy * @param[out] img Texture name * @param[in] width Width of framebuffer * @param[in] height Height of framebuffer + * @param[in] texture_type Type of the canvas texture. * @return Creation status */ - virtual GLenum createFBO(GLuint &, GLuint &, GLuint &, int, int) + virtual GLenum createFBO(GLuint &, GLuint &, GLuint &, int, int, Canvas::TextureType) { return GL_FRAMEBUFFER_UNSUPPORTED; } @@ -60,7 +61,7 @@ struct FramebufferStrategy struct FramebufferStrategyGL3 : public FramebufferStrategy { - virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil, GLuint &img, int width, int height) + virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil, GLuint &img, int width, int height, Canvas::TextureType texture_type) { // get currently bound fbo to reset to it later GLint current_fbo; @@ -75,27 +76,41 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, depth_stencil); + GL_RENDERBUFFER, depth_stencil); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depth_stencil); + GL_RENDERBUFFER, depth_stencil); // generate texture save target + GLint internalFormat; + GLenum format; + switch (texture_type) + { + case Canvas::TYPE_HDR: + internalFormat = GL_RGBA16F; + format = GL_FLOAT; + break; + case Canvas::TYPE_NORMAL: + default: + internalFormat = GL_RGBA8; + format = GL_UNSIGNED_BYTE; + } + glGenTextures(1, &img); bindTexture(img); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, + 0, GL_RGBA, format, NULL); bindTexture(0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, img, 0); + GL_TEXTURE_2D, img, 0); // check status GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); // unbind framebuffer glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)current_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, (GLuint) current_fbo); return status; } virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint img) @@ -111,10 +126,9 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy } }; -struct FramebufferStrategyEXT : public FramebufferStrategy +struct FramebufferStrategyPackedEXT : public FramebufferStrategy { - - virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil, GLuint &img, int width, int height) + virtual GLenum createFBO(GLuint &framebuffer, GLuint &depth_stencil, GLuint &img, int width, int height, Canvas::TextureType texture_type) { GLint current_fbo; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, ¤t_fbo); @@ -126,29 +140,45 @@ struct FramebufferStrategyEXT : public FramebufferStrategy // create stencil buffer glGenRenderbuffersEXT(1, &depth_stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, width, height); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, + width, height); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, depth_stencil); + GL_RENDERBUFFER_EXT, depth_stencil); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, depth_stencil); + GL_RENDERBUFFER_EXT, depth_stencil); // generate texture save target + GLint internalFormat; + GLenum format; + switch (texture_type) + { + case Canvas::TYPE_HDR: + internalFormat = GL_RGBA16F; + format = GL_FLOAT; + break; + case Canvas::TYPE_NORMAL: + default: + internalFormat = GL_RGBA8; + format = GL_UNSIGNED_BYTE; + } + glGenTextures(1, &img); bindTexture(img); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, + 0, GL_RGBA, format, NULL); bindTexture(0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, img, 0); + GL_TEXTURE_2D, img, 0); // check status GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // unbind framebuffer glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)current_fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint) current_fbo); return status; } @@ -165,45 +195,112 @@ struct FramebufferStrategyEXT : public FramebufferStrategy } }; +struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT +{ + virtual GLenum createFBO(GLuint &framebuffer, GLuint &stencil, GLuint &img, int width, int height, Canvas::TextureType texture_type) + { + GLint current_fbo; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, ¤t_fbo); + + // create framebuffer + glGenFramebuffersEXT(1, &framebuffer); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer); + + // create stencil buffer + glGenRenderbuffersEXT(1, &stencil); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, + width, height); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, stencil); + + // generate texture save target + GLint internalFormat; + GLenum format; + switch (texture_type) + { + case Canvas::TYPE_HDR: + internalFormat = GL_RGBA16F; + format = GL_FLOAT; + break; + case Canvas::TYPE_NORMAL: + default: + internalFormat = GL_RGBA8; + format = GL_UNSIGNED_BYTE; + } + + glGenTextures(1, &img); + bindTexture(img); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, + 0, GL_RGBA, format, NULL); + bindTexture(0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, img, 0); + + // check status + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + // unbind framebuffer + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint) current_fbo); + return status; + } + + bool isSupported() + { + GLuint fb, stencil, img; + GLenum status = createFBO(fb, stencil, img, 2, 2, Canvas::TYPE_NORMAL); + deleteFBO(fb, stencil, img); + return status == GL_FRAMEBUFFER_COMPLETE; + } +}; + FramebufferStrategy *strategy = NULL; FramebufferStrategy strategyNone; FramebufferStrategyGL3 strategyGL3; +FramebufferStrategyPackedEXT strategyPackedEXT; + FramebufferStrategyEXT strategyEXT; Canvas *Canvas::current = NULL; -static void loadStrategy() +static void getStrategy() { if (!strategy) { if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) strategy = &strategyGL3; else if (GLEE_EXT_framebuffer_object && GLEE_EXT_packed_depth_stencil) + strategy = &strategyPackedEXT; + else if (GLEE_EXT_framebuffer_object && strategyEXT.isSupported()) strategy = &strategyEXT; else strategy = &strategyNone; } } -Canvas::Canvas(int width, int height) +Canvas::Canvas(int width, int height, TextureType texture_type) : width(width) , height(height) + , texture_type(texture_type) { float w = static_cast(width); float h = static_cast(height); // world coordinates vertices[0].x = 0; - vertices[0].y = 0; + vertices[0].y = h; vertices[1].x = 0; - vertices[1].y = h; + vertices[1].y = 0; vertices[2].x = w; - vertices[2].y = h; + vertices[2].y = 0; vertices[3].x = w; - vertices[3].y = 0; + vertices[3].y = h; // texture coordinates vertices[0].s = 0; @@ -215,7 +312,7 @@ Canvas::Canvas(int width, int height) vertices[3].s = 1; vertices[3].t = 1; - loadStrategy(); + getStrategy(); loadVolatile(); } @@ -231,10 +328,15 @@ Canvas::~Canvas() bool Canvas::isSupported() { - loadStrategy(); + getStrategy(); return (strategy != &strategyNone); } +bool Canvas::isHdrSupported() +{ + return GLEE_VERSION_3_0 || GLEE_ARB_texture_float; +} + void Canvas::bindDefaultCanvas() { if (current != NULL) @@ -262,7 +364,7 @@ void Canvas::startGrab() glLoadIdentity(); // Set up orthographic view (no depth) - glOrtho(0.0, width, height, 0.0, -1.0, 1.0); + glOrtho(0.0, width, 0.0, height, -1.0, 1.0); // Switch back to modelview matrix glMatrixMode(GL_MODELVIEW); @@ -312,12 +414,10 @@ void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, f void Canvas::drawq(love::graphics::Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const { static Matrix t; - quad->mirror(false, true); const vertex *v = quad->getVertices(); t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); drawv(t, v); - quad->mirror(false, true); } love::image::ImageData *Canvas::getImageData(love::image::Image *image) @@ -325,7 +425,6 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) int row = 4 * width; int size = row * height; GLubyte *pixels = new GLubyte[size]; - GLubyte *screenshot = new GLubyte[size]; strategy->bindFBO(fbo); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); @@ -334,15 +433,8 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) else strategy->bindFBO(0); - GLubyte *src = pixels - row; // second line of source image - GLubyte *dst = screenshot + size; // last row of destination image + love::image::ImageData *img = image->newImageData(width, height, (void *)pixels); - for (int i = 0; i < height; ++i) - memcpy(dst -= row, src += row, row); - - love::image::ImageData *img = image->newImageData(width, height, (void *)screenshot); - - delete[] screenshot; delete[] pixels; return img; @@ -399,7 +491,7 @@ Image::Wrap Canvas::getWrap() const bool Canvas::loadVolatile() { - status = strategy->createFBO(fbo, depth_stencil, img, width, height); + status = strategy->createFBO(fbo, depth_stencil, img, width, height, texture_type); if (status != GL_FRAMEBUFFER_COMPLETE) return false; @@ -447,6 +539,23 @@ void Canvas::drawv(const Matrix &t, const vertex *v) const glPopMatrix(); } +bool Canvas::getConstant(const char *in, Canvas::TextureType &out) +{ + return textureTypes.find(in, out); +} + +bool Canvas::getConstant(Canvas::TextureType in, const char *&out) +{ + return textureTypes.find(in, out); +} + +StringMap::Entry Canvas::textureTypeEntries[] = +{ + {"normal", Canvas::TYPE_NORMAL}, + {"hdr", Canvas::TYPE_HDR}, +}; +StringMap Canvas::textureTypes(Canvas::textureTypeEntries, sizeof(Canvas::textureTypeEntries)); + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index b226a36d1..0da184631 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -42,19 +42,15 @@ namespace opengl class Canvas : public DrawQable, public Volatile { public: - Canvas(int width, int height); + enum TextureType { + TYPE_NORMAL, + TYPE_HDR, + TYPE_MAX_ENUM + }; + + Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL); virtual ~Canvas(); - static bool isSupported(); - - unsigned int getStatus() const - { - return status; - } - - static Canvas *current; - static void bindDefaultCanvas(); - void startGrab(); void stopGrab(); @@ -78,9 +74,27 @@ public: int getWidth(); int getHeight(); + unsigned int getStatus() const + { + return status; + } + + TextureType getTextureType() const + { + return texture_type; + } + bool loadVolatile(); void unloadVolatile(); + static bool isSupported(); + static bool isHdrSupported(); + static bool getConstant(const char *in, TextureType &out); + static bool getConstant(TextureType in, const char *&out); + + static Canvas *current; + static void bindDefaultCanvas(); + private: friend class PixelEffect; GLuint getTextureName() const @@ -94,6 +108,8 @@ private: GLuint depth_stencil; GLuint img; + TextureType texture_type; + vertex vertices[4]; GLenum status; @@ -101,10 +117,13 @@ private: struct { Image::Filter filter; - Image::Wrap wrap; + Image::Wrap wrap; } settings; void drawv(const Matrix &t, const vertex *v) const; + + static StringMap::Entry textureTypeEntries[]; + static StringMap textureTypes; }; } // opengl diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index a174231cf..0c9e5dc99 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -400,9 +400,15 @@ ParticleSystem *Graphics::newParticleSystem(Image *image, int size) return new ParticleSystem(image, size); } -Canvas *Graphics::newCanvas(int width, int height) +Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type) { - Canvas *canvas = new Canvas(width, height); + if (texture_type == Canvas::TYPE_HDR && !Canvas::isHdrSupported()) + throw Exception("HDR Canvases are not supported by your OpenGL implementation"); + + while (GL_NO_ERROR != glGetError()) + /* clear opengl error flag */; + + Canvas *canvas = new Canvas(width, height, texture_type); GLenum err = canvas->getStatus(); // everything ok, return canvas (early out) @@ -543,7 +549,7 @@ void Graphics::setBlendMode(Graphics::BlendMode mode) if (mode == BLEND_ALPHA) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); else if (mode == BLEND_MULTIPLICATIVE) - glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_DST_COLOR, GL_ZERO); else if (mode == BLEND_PREMULTIPLIED) glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); else // mode == BLEND_ADDITIVE || mode == BLEND_SUBTRACTIVE @@ -582,7 +588,7 @@ Graphics::BlendMode Graphics::getBlendMode() return BLEND_ADDITIVE; else if (src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) // && equation == GL_FUNC_ADD return BLEND_ALPHA; - else if (src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) // && equation == GL_FUNC_ADD + else if (src == GL_DST_COLOR && dst == GL_ZERO) // && equation == GL_FUNC_ADD return BLEND_MULTIPLICATIVE; else if (src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) // && equation == GL_FUNC_ADD return BLEND_PREMULTIPLIED; diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index e55fdf9d4..0799bee86 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -267,7 +267,7 @@ public: ParticleSystem *newParticleSystem(Image *image, int size); - Canvas *newCanvas(int width, int height); + Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL); PixelEffect *newPixelEffect(const std::string &code); diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 2b6604dd2..47e4b6552 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -45,10 +45,18 @@ float calculate_variation(float inner, float outer, float var) { float low = inner - (outer/2.0f)*var; float high = inner + (outer/2.0f)*var; - float r = (rand() / (float(RAND_MAX)+1)); + float r = random(); return low*(1-r)+high*r; } +StringMap::Entry ParticleSystem::distributionsEntries[] = { + { "none", ParticleSystem::DISTRIBUTION_NONE }, + { "uniform", ParticleSystem::DISTRIBUTION_UNIFORM }, + { "normal", ParticleSystem::DISTRIBUTION_NORMAL }, +}; + +StringMap ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries)); + ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer) : pStart(0) @@ -57,6 +65,7 @@ ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer) , active(true) , emissionRate(0) , emitCounter(0) + , areaSpreadDistribution(DISTRIBUTION_NONE) , lifetime(-1) , life(0) , particleLifeMin(0) @@ -108,45 +117,60 @@ void ParticleSystem::add() if (min == max) pLast->life = min; else - pLast->life = (rand() / (float(RAND_MAX)+1)) * (max - min) + min; + pLast->life = random(min, max); pLast->lifetime = pLast->life; pLast->position[0] = position.getX(); pLast->position[1] = position.getY(); + switch (areaSpreadDistribution) + { + case DISTRIBUTION_UNIFORM: + pLast->position[0] += random(-areaSpread.getX(), areaSpread.getX()); + pLast->position[1] += random(-areaSpread.getY(), areaSpread.getY()); + break; + case DISTRIBUTION_NORMAL: + pLast->position[0] += random_normal(areaSpread.getX()); + pLast->position[1] += random_normal(areaSpread.getY()); + break; + case DISTRIBUTION_NONE: + default: + break; + } + min = direction - spread/2.0f; max = direction + spread/2.0f; - pLast->direction = (rand() / (float(RAND_MAX)+1)) * (max - min) + min; + pLast->direction = random(min, max); pLast->origin = position; min = speedMin; max = speedMax; - float speed = (rand() / (float(RAND_MAX)+1)) * (max - min) + min; + float speed = random(min, max); pLast->speed = love::Vector(cos(pLast->direction), sin(pLast->direction)); pLast->speed *= speed; min = gravityMin; max = gravityMax; - pLast->gravity = (rand() / (float(RAND_MAX)+1)) * (max - min) + min; + pLast->gravity = random(min, max); min = radialAccelerationMin; max = radialAccelerationMax; - pLast->radialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min; + pLast->radialAcceleration = random(min, max); min = tangentialAccelerationMin; max = tangentialAccelerationMax; - pLast->tangentialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min; + pLast->tangentialAcceleration = random(min, max); - pLast->sizeOffset = (rand() / (float(RAND_MAX)+1)) * sizeVariation; // time offset for size change - pLast->sizeIntervalSize = (1.0f - (rand() / (float(RAND_MAX)+1)) * sizeVariation) - pLast->sizeOffset; + pLast->sizeOffset = random(sizeVariation); // time offset for size change + pLast->sizeIntervalSize = (1.0f - random(sizeVariation)) - pLast->sizeOffset; pLast->size = sizes[(size_t)(pLast->sizeOffset - .5f) * (sizes.size() - 1)]; min = rotationMin; max = rotationMax; pLast->spinStart = calculate_variation(spinStart, spinEnd, spinVariation); pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation); - pLast->rotation = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;; + pLast->rotation = random(min, max); pLast->color = colors[0]; @@ -204,6 +228,13 @@ void ParticleSystem::setPosition(float x, float y) position = love::Vector(x, y); } + +void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y) +{ + areaSpread = love::Vector(x, y); + areaSpreadDistribution = distribution; +} + void ParticleSystem::setDirection(float direction) { this->direction = direction; @@ -349,6 +380,16 @@ const love::Vector &ParticleSystem::getPosition() const return position; } +ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const +{ + return areaSpreadDistribution; +} + +const love::Vector &ParticleSystem::getAreaSpreadParameters() const +{ + return areaSpread; +} + float ParticleSystem::getDirection() const { return direction; @@ -543,6 +584,16 @@ void ParticleSystem::update(float dt) } // while } +bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out) +{ + return distributions.find(in, out); +} + +bool ParticleSystem::getConstant(AreaSpreadDistribution in, const char *&out) +{ + return distributions.find(in, out); +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 186437ad4..64cb5c519 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -72,6 +72,16 @@ struct particle class ParticleSystem : public Drawable { public: + /** + * Type of distribution new particles are drawn from: None, uniform, normal. + */ + enum AreaSpreadDistribution + { + DISTRIBUTION_NONE, + DISTRIBUTION_UNIFORM, + DISTRIBUTION_NORMAL, + DISTRIBUTION_MAX_ENUM, + }; /** * Creates a particle system with the specified buffersize and sprite. @@ -122,6 +132,19 @@ public: **/ void setPosition(float x, float y); + /** + * Sets the emission area spread parameters and distribution type. The interpretation of + * the parameters depends on the distribution type: + * + * * None: Parameters are ignored. No area spread. + * * Uniform: Parameters denote maximal (symmetric) displacement from emitter position. + * * Normal: Parameters denote the standard deviation in x and y direction. x and y are assumed to be uncorrelated. + * @param x First parameter. Interpretation depends on distribution type. + * @param y Second parameter. Interpretation depends on distribution type. + * @param distribution Distribution type + * */ + void setAreaSpread(AreaSpreadDistribution distribution, float x, float y); + /** * Sets the direction and the spread of the particle emitter. * @param direction The direction (in degrees). @@ -285,6 +308,16 @@ public: **/ const love::Vector &getPosition() const; + /** + * Returns area spread distribution type. + */ + AreaSpreadDistribution getAreaSpreadDistribution() const; + + /** + * Returns area spread parameters. + */ + const love::Vector &getAreaSpreadParameters() const; + /** * Returns the direction of the emitter (in degrees). **/ @@ -357,6 +390,9 @@ public: * @param dt Time since last update. **/ void update(float dt); + + static bool getConstant(const char *in, AreaSpreadDistribution &out); + static bool getConstant(AreaSpreadDistribution in, const char *&out); protected: // The max amount of particles. @@ -386,6 +422,10 @@ protected: // The relative position of the particle emitter. love::Vector position; + // Emission area spread. + AreaSpreadDistribution areaSpreadDistribution; + love::Vector areaSpread; + // The lifetime of the particle emitter (-1 means infinite) and the life it has left. float lifetime; float life; @@ -439,6 +479,9 @@ protected: void add(); void remove(particle *p); + + static StringMap::Entry distributionsEntries[]; + static StringMap distributions; }; } // opengl diff --git a/src/modules/graphics/opengl/PixelEffect.cpp b/src/modules/graphics/opengl/PixelEffect.cpp index 619fceab8..8e570fb27 100644 --- a/src/modules/graphics/opengl/PixelEffect.cpp +++ b/src/modules/graphics/opengl/PixelEffect.cpp @@ -20,6 +20,7 @@ #include "PixelEffect.h" #include "GLee.h" +#include "Graphics.h" namespace { @@ -134,6 +135,7 @@ bool PixelEffect::loadVolatile() } glDeleteShader(shader); + return true; } @@ -149,24 +151,25 @@ void PixelEffect::unloadVolatile() std::string PixelEffect::getGLSLVersion() { - // GL_SHADING_LANGUAGE_VERSION is not available in OpenGL < 2.1. - // Be very pessimistic about the GLSL version in that case. - if (!GLEE_VERSION_2_1) + // GL_SHADING_LANGUAGE_VERSION may not be available in OpenGL < 2.0. + const char *tmp = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); + if (NULL == tmp) return "0.0"; // the version string always begins with a version number of the format // major_number.minor_number // or // major_number.minor_number.release_number - std::string versionString((const char *)glGetString(GL_SHADING_LANGUAGE_VERSION)); - size_t minorEndPos = versionString.find(" "); + // we can keep release_number, since it does not affect the check below. + std::string versionString(tmp); + size_t minorEndPos = versionString.find(' '); return versionString.substr(0, minorEndPos); } bool PixelEffect::isSupported() { - return GLEE_VERSION_2_0 && GLEE_ARB_shader_objects && GLEE_ARB_fragment_shader && getGLSLVersion() >= "1.2"; + return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2"; } std::string PixelEffect::getWarnings() const diff --git a/src/modules/graphics/opengl/Quad.cpp b/src/modules/graphics/opengl/Quad.cpp index 242cd2053..842fd64d1 100644 --- a/src/modules/graphics/opengl/Quad.cpp +++ b/src/modules/graphics/opengl/Quad.cpp @@ -113,17 +113,6 @@ void Quad::flip(bool x, bool y) } } -void Quad::mirror(bool x, bool y) -{ - for (size_t i = 0; i < NUM_VERTICES; ++i) - { - if (x) - vertices[i].s = 1.0f - vertices[i].s; - if (y) - vertices[i].t = 1.0f - vertices[i].t; - } -} - const vertex *Quad::getVertices() const { return vertices; diff --git a/src/modules/graphics/opengl/Quad.h b/src/modules/graphics/opengl/Quad.h index fd400005b..699bc08a4 100644 --- a/src/modules/graphics/opengl/Quad.h +++ b/src/modules/graphics/opengl/Quad.h @@ -54,7 +54,6 @@ public: Viewport getViewport() const; void flip(bool x, bool y); - void mirror(bool x, bool y); /** * Gets a pointer to the vertices. diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 53d9ac637..3af47051c 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -181,6 +181,16 @@ int w_Canvas_getHeight(lua_State *L) return 1; } +int w_Canvas_getType(lua_State *L) +{ + Canvas *canvas = luax_checkcanvas(L, 1); + Canvas::TextureType type = canvas->getTextureType(); + const char *str; + Canvas::getConstant(type, str); + lua_pushstring(L, str); + return 1; +} + static const luaL_Reg functions[] = { { "renderTo", w_Canvas_renderTo }, @@ -192,6 +202,7 @@ static const luaL_Reg functions[] = { "clear", w_Canvas_clear }, { "getWidth", w_Canvas_getWidth }, { "getHeight", w_Canvas_getHeight }, + { "getType", w_Canvas_getType }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Canvas.h b/src/modules/graphics/opengl/wrap_Canvas.h index 20c70941a..924fe833a 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.h +++ b/src/modules/graphics/opengl/wrap_Canvas.h @@ -43,6 +43,7 @@ int w_Canvas_getWrap(lua_State *L); int w_Canvas_clear(lua_State *L); int w_Canvas_getWidth(lua_State *L); int w_Canvas_getHeight(lua_State *L); +int w_Canvas_getType(lua_State *L); extern "C" int luaopen_canvas(lua_State *L); } // opengl diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 2f1d7c101..de6168192 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -361,6 +361,9 @@ int w_newImageFont(lua_State *L) Image::Filter img_filter; bool setFilter = false; + // For the filter modes.. + int startIndex = 2; + // Convert to ImageData if necessary. if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T) || (luax_istype(L, 1, DATA_T) && !luax_istype(L, 1, IMAGE_IMAGE_DATA_T))) luax_convobj(L, 1, "image", "newImageData"); @@ -379,16 +382,17 @@ int w_newImageFont(lua_State *L) { int idxs[] = {1, 2}; luax_convobj(L, idxs, 2, "font", "newRasterizer"); + startIndex = 3; // There's a glyphs args in there, move up } love::font::Rasterizer *rasterizer = luax_checktype(L, 1, "Rasterizer", FONT_RASTERIZER_T); - if (lua_isstring(L, 2) && lua_isstring(L, 3)) + if (lua_isstring(L, startIndex) && lua_isstring(L, startIndex+1)) { Image::FilterMode min; Image::FilterMode mag; - const char *minstr = luaL_checkstring(L, 2); - const char *magstr = luaL_checkstring(L, 3); + const char *minstr = luaL_checkstring(L, startIndex); + const char *magstr = luaL_checkstring(L, startIndex+1); if (!Image::getConstant(minstr, min)) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, mag)) @@ -449,14 +453,18 @@ int w_newParticleSystem(lua_State *L) int w_newCanvas(lua_State *L) { // 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()); - glGetError(); // clear opengl error flag + int width = luaL_optint(L, 1, instance->getWidth()); + int height = luaL_optint(L, 2, instance->getHeight()); + const char *str = luaL_optstring(L, 3, "normal"); + + Canvas::TextureType texture_type; + if (!Canvas::getConstant(str, texture_type)) + return luaL_error(L, "Invalid canvas type: %s", str); Canvas *canvas = NULL; try { - canvas = instance->newCanvas(width, height); + canvas = instance->newCanvas(width, height, texture_type); } catch(Exception &e) { @@ -874,6 +882,10 @@ int w_isSupported(lua_State *L) if (!Canvas::isSupported()) supported = false; break; + case Graphics::SUPPORT_HDR_CANVAS: + if (!Canvas::isHdrSupported()) + supported = false; + break; case Graphics::SUPPORT_PIXELEFFECT: if (!PixelEffect::isSupported()) supported = false; diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 3054b32a5..69df1c67f 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -86,6 +86,24 @@ int w_ParticleSystem_setPosition(lua_State *L) return 0; } +int w_ParticleSystem_setAreaSpread(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + + ParticleSystem::AreaSpreadDistribution distribution; + const char *str = luaL_checkstring(L, 2); + if (!ParticleSystem::getConstant(str, distribution)) + return luaL_error(L, "Invalid distribution: '%s'", str); + + float x = (float)luaL_checknumber(L, 3); + float y = (float)luaL_checknumber(L, 4); + if (x < 0.0f || y < 0.0f) + return luaL_error(L, "Invalid area spread parameters (must be >= 0)"); + + t->setAreaSpread(distribution, x, y); + return 0; +} + int w_ParticleSystem_setDirection(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); @@ -273,6 +291,21 @@ int w_ParticleSystem_getPosition(lua_State *L) return 2; } +int w_ParticleSystem_getAreaSpread(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + ParticleSystem::AreaSpreadDistribution distribution = t-> getAreaSpreadDistribution(); + const char *str; + ParticleSystem::getConstant(distribution, str); + const love::Vector &p = t->getAreaSpreadParameters(); + + lua_pushstring(L, str); + lua_pushnumber(L, p.x); + lua_pushnumber(L, p.y); + + return 3; +} + int w_ParticleSystem_getDirection(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); @@ -373,6 +406,7 @@ static const luaL_Reg functions[] = { "setLifetime", w_ParticleSystem_setLifetime }, { "setParticleLife", w_ParticleSystem_setParticleLife }, { "setPosition", w_ParticleSystem_setPosition }, + { "setAreaSpread", w_ParticleSystem_setAreaSpread }, { "setDirection", w_ParticleSystem_setDirection }, { "setSpread", w_ParticleSystem_setSpread }, { "setRelativeDirection", w_ParticleSystem_setRelativeDirection }, @@ -390,6 +424,7 @@ static const luaL_Reg functions[] = { "getX", w_ParticleSystem_getX }, { "getY", w_ParticleSystem_getY }, { "getPosition", w_ParticleSystem_getPosition }, + { "getAreaSpread", w_ParticleSystem_getAreaSpread }, { "getDirection", w_ParticleSystem_getDirection }, { "getSpread", w_ParticleSystem_getSpread }, { "getOffsetX", w_ParticleSystem_getOffsetX }, diff --git a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp index 1030208bd..470ba9947 100644 --- a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp @@ -143,19 +143,38 @@ int w_SpriteBatch_getImage(lua_State *L) int w_SpriteBatch_setColor(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); + Color c; if (lua_gettop(L) <= 1) + { t->setColor(); + return 0; + } + else if (lua_istable(L, 2)) + { + lua_rawgeti(L, 2, 1); + c.r = (unsigned char) luaL_checkint(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, 2, 2); + c.g = (unsigned char) luaL_checkint(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, 2, 3); + c.b = (unsigned char) luaL_checkint(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, 2, 4); + c.a = (unsigned char) luaL_optint(L, -1, 255); + lua_pop(L, 1); + } else { - Color c; c.r = (unsigned char)luaL_checkint(L, 2); c.g = (unsigned char)luaL_checkint(L, 3); c.b = (unsigned char)luaL_checkint(L, 4); c.a = (unsigned char)luaL_optint(L, 5, 255); - t->setColor(c); } + t->setColor(c); + return 0; } diff --git a/src/modules/physics/box2d/Contact.cpp b/src/modules/physics/box2d/Contact.cpp index 6d1162bfa..7aa260bc4 100644 --- a/src/modules/physics/box2d/Contact.cpp +++ b/src/modules/physics/box2d/Contact.cpp @@ -39,7 +39,21 @@ Contact::Contact(b2Contact *contact) Contact::~Contact() { - Memoizer::remove(contact); + invalidate(); +} + +void Contact::invalidate() +{ + if (contact != NULL) + { + Memoizer::remove(contact); + contact = NULL; + } +} + +bool Contact::isValid() +{ + return contact != NULL ? true : false; } int Contact::getPositions(lua_State *L) diff --git a/src/modules/physics/box2d/Contact.h b/src/modules/physics/box2d/Contact.h index 6bf5184a4..852a7e635 100644 --- a/src/modules/physics/box2d/Contact.h +++ b/src/modules/physics/box2d/Contact.h @@ -59,6 +59,18 @@ public: virtual ~Contact(); + /** + * Removes the b2Contact pointer from Memoizer and sets it + * to null on the Contact. + **/ + void invalidate(); + + /** + * Returns if the Contact still points to a valid b2Contact. + * @return True if the contact is still valid or false if it has been destroyed. + **/ + bool isValid(); + /** * Gets the position of each point of contact. * @return The position along the x-axis. diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 897e65a78..3f158024c 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -77,9 +77,13 @@ void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse throw love::Exception("A fixture has escaped Memoizer!"); } - Contact *c = new Contact(contact); + Contact *cobj = (Contact *)Memoizer::find(contact); + if (!cobj) + cobj = new Contact(contact); + else + cobj->retain(); - luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void *)c); + luax_newtype(L, "Contact", (PHYSICS_CONTACT_T), (void *)cobj); int args = 3; if (impulse) @@ -117,12 +121,12 @@ bool World::ContactFilter::process(Fixture *a, Fixture *b) a->getFilterData(filterA); b->getFilterData(filterB); - if (filterA[2] != 0 && // 0 is the default group, so this does not count - filterA[2] == filterB[2]) // if they are in the same group + if (filterA[2] != 0 && // 0 is the default group, so this does not count + filterA[2] == filterB[2]) // if they are in the same group return filterA[2] > 0; // Negative indexes mean you don't collide if ((filterA[1] & filterB[0]) == 0 || - (filterB[1] & filterA[0]) == 0) + (filterB[1] & filterA[0]) == 0) return false; // A and B aren't set to collide if (ref != 0) @@ -290,6 +294,11 @@ void World::BeginContact(b2Contact *contact) void World::EndContact(b2Contact *contact) { end.process(contact); + + // Letting the Contact know that the b2Contact will be destroyed any second. + Contact *c = (Contact *)Memoizer::find(contact); + if (c != NULL) + c->invalidate(); } void World::PreSolve(b2Contact *contact, const b2Manifold *oldManifold) @@ -332,19 +341,19 @@ int World::setCallbacks(lua_State *L) case 4: if (postsolve.ref) delete postsolve.ref; - postsolve.ref = luax_refif (L, LUA_TFUNCTION); + postsolve.ref = luax_refif(L, LUA_TFUNCTION); case 3: if (presolve.ref) delete presolve.ref; - presolve.ref = luax_refif (L, LUA_TFUNCTION); + presolve.ref = luax_refif(L, LUA_TFUNCTION); case 2: if (end.ref) delete end.ref; - end.ref = luax_refif (L, LUA_TFUNCTION); + end.ref = luax_refif(L, LUA_TFUNCTION); case 1: if (begin.ref) delete begin.ref; - begin.ref = luax_refif (L, LUA_TFUNCTION); + begin.ref = luax_refif(L, LUA_TFUNCTION); } return 0; @@ -364,7 +373,7 @@ int World::setContactFilter(lua_State *L) luax_assert_argc(L, 1); if (filter.ref) delete filter.ref; - filter.ref = luax_refif (L, LUA_TFUNCTION); + filter.ref = luax_refif(L, LUA_TFUNCTION); return 0; } @@ -468,8 +477,10 @@ int World::getContactList(lua_State *L) const { if (!c) break; Contact *contact = (Contact *)Memoizer::find(c); - if (!contact) throw love::Exception("A contact has escaped Memoizer!"); - contact->retain(); + if (!contact) + contact = new Contact(c); + else + contact->retain(); luax_newtype(L, "Contact", PHYSICS_CONTACT_T, (void *)contact); lua_rawseti(L, -2, i); i++; @@ -494,7 +505,7 @@ int World::queryBoundingBox(lua_State *L) box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly)); box.upperBound = Physics::scaleDown(b2Vec2(ux, uy)); if (query.ref) delete query.ref; - query.ref = luax_refif (L, LUA_TFUNCTION); + query.ref = luax_refif(L, LUA_TFUNCTION); world->QueryAABB(&query, box); return 0; } @@ -510,7 +521,7 @@ int World::rayCast(lua_State *L) b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); if (raycast.ref) delete raycast.ref; - raycast.ref = luax_refif (L, LUA_TFUNCTION); + raycast.ref = luax_refif(L, LUA_TFUNCTION); world->RayCast(&raycast, v1, v2); return 0; } diff --git a/src/modules/physics/box2d/wrap_Contact.cpp b/src/modules/physics/box2d/wrap_Contact.cpp index d2d2db348..625be10ef 100644 --- a/src/modules/physics/box2d/wrap_Contact.cpp +++ b/src/modules/physics/box2d/wrap_Contact.cpp @@ -29,7 +29,10 @@ namespace box2d Contact *luax_checkcontact(lua_State *L, int idx) { - return luax_checktype(L, idx, "Contact", PHYSICS_CONTACT_T); + Contact *c = luax_checktype(L, idx, "Contact", PHYSICS_CONTACT_T); + if (!c->isValid()) + luaL_error(L, "Attempt to use destroyed contact."); + return c; } int w_Contact_getPositions(lua_State *L) diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index 4f093be1f..58e14f260 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -39,7 +39,7 @@ int w_World_update(lua_State *L) { World *t = luax_checkworld(L, 1); float dt = (float)luaL_checknumber(L, 2); - t->update(dt); + ASSERT_GUARD(t->update(dt);) return 0; } diff --git a/src/modules/sound/Sound.h b/src/modules/sound/Sound.h index 7cd61c3ed..066961c71 100644 --- a/src/modules/sound/Sound.h +++ b/src/modules/sound/Sound.h @@ -74,11 +74,11 @@ public: * @param sampleRate Samples per second, or quality of the audio. 44100 is a good value. * @return A Decoder object on success, or zero if no decoder could be found. **/ - virtual Decoder *newDecoder(filesystem::File *file, int bufferSize) = 0; + virtual Decoder *newDecoder(filesystem::FileData *file, int bufferSize) = 0; }; // Sound } // sound } // love -#endif // LOVE_SOUND_SOUND_H \ No newline at end of file +#endif // LOVE_SOUND_SOUND_H diff --git a/src/modules/sound/lullaby/GmeDecoder.cpp b/src/modules/sound/lullaby/GmeDecoder.cpp index 2280dd2be..c16323dc4 100644 --- a/src/modules/sound/lullaby/GmeDecoder.cpp +++ b/src/modules/sound/lullaby/GmeDecoder.cpp @@ -46,11 +46,19 @@ GmeDecoder::GmeDecoder(Data *data, const std::string &ext, int bufferSize) num_tracks = gme_track_count(emu); - if (num_tracks <= 0) - throw love::Exception("Game music file has no tracks"); + try + { + if (num_tracks <= 0) + throw love::Exception("Game music file has no tracks"); - if (gme_start_track(emu, cur_track) != 0) - throw love::Exception("Could not start game music playback"); + if (gme_start_track(emu, cur_track) != 0) + throw love::Exception("Could not start game music playback"); + } + catch (love::Exception &) + { + gme_delete(emu); + throw; + } } GmeDecoder::~GmeDecoder() diff --git a/src/modules/sound/lullaby/GmeDecoder.h b/src/modules/sound/lullaby/GmeDecoder.h index ccbc4dd35..5407eaa82 100644 --- a/src/modules/sound/lullaby/GmeDecoder.h +++ b/src/modules/sound/lullaby/GmeDecoder.h @@ -27,7 +27,11 @@ #include "common/Data.h" #include "Decoder.h" +#ifdef LOVE_MACOSX +#include +#else #include +#endif namespace love { diff --git a/src/modules/sound/lullaby/Sound.cpp b/src/modules/sound/lullaby/Sound.cpp index 9b7df1799..8cebb8e00 100644 --- a/src/modules/sound/lullaby/Sound.cpp +++ b/src/modules/sound/lullaby/Sound.cpp @@ -51,10 +51,9 @@ const char *Sound::getName() const return "love.sound.lullaby"; } -sound::Decoder *Sound::newDecoder(love::filesystem::File *file, int bufferSize) +sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSize) { - Data *data = file->read(); - std::string ext = file->getExtension(); + std::string ext = data->getExtension(); sound::Decoder *decoder = 0; @@ -76,8 +75,6 @@ sound::Decoder *Sound::newDecoder(love::filesystem::File *file, int bufferSize) // else if (OtherDecoder::accept(ext)) - data->release(); - return decoder; } diff --git a/src/modules/sound/lullaby/Sound.h b/src/modules/sound/lullaby/Sound.h index cbf9ac1e6..b821384b1 100644 --- a/src/modules/sound/lullaby/Sound.h +++ b/src/modules/sound/lullaby/Sound.h @@ -59,7 +59,7 @@ public: const char *getName() const; /// @copydoc love::sound::Sound::newDecoder - sound::Decoder *newDecoder(love::filesystem::File *file, int bufferSize); + sound::Decoder *newDecoder(love::filesystem::FileData *file, int bufferSize); }; // Sound @@ -67,4 +67,4 @@ public: } // sound } // love -#endif // LOVE_SOUND_LULLABY_SOUND_H \ No newline at end of file +#endif // LOVE_SOUND_LULLABY_SOUND_H diff --git a/src/modules/sound/wrap_Sound.cpp b/src/modules/sound/wrap_Sound.cpp index 8b5568757..9b1db25b5 100644 --- a/src/modules/sound/wrap_Sound.cpp +++ b/src/modules/sound/wrap_Sound.cpp @@ -83,18 +83,31 @@ int w_newDecoder(lua_State *L) if (lua_isstring(L, 1)) luax_convobj(L, 1, "filesystem", "newFile"); - love::filesystem::File *file = luax_checktype(L, 1, "File", FILESYSTEM_FILE_T); + love::filesystem::FileData *data; + if (luax_istype(L, 1, FILESYSTEM_FILE_T)) + { + love::filesystem::File *file = luax_checktype(L, 1, "File", FILESYSTEM_FILE_T); + data = file->read(); + } + else + { + data = luax_checktype(L, 1, "FileData", FILESYSTEM_FILE_DATA_T); + data->retain(); + } + int bufferSize = luaL_optint(L, 2, Decoder::DEFAULT_BUFFER_SIZE); try { - Decoder *t = instance->newDecoder(file, bufferSize); + Decoder *t = instance->newDecoder(data, bufferSize); + data->release(); if (t == 0) - return luaL_error(L, "Extension \"%s\" not supported.", file->getExtension().c_str()); + return luaL_error(L, "Extension \"%s\" not supported.", data->getExtension().c_str()); luax_newtype(L, "Decoder", SOUND_DECODER_T, (void *)t); } catch(love::Exception &e) { + data->release(); return luaL_error(L, e.what()); } diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 3ddbb93dd..4c583558b 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -430,8 +430,8 @@ function love.run() if love.draw then love.draw() end end - if love.timer then love.timer.sleep(0.001) end if love.graphics then love.graphics.present() end + if love.timer then love.timer.sleep(0.001) end end diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 3aaf84e06..3ca1a78ff 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -737,12 +737,12 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c, 0x65, 0x65, - 0x70, 0x28, 0x30, 0x2e, 0x30, 0x30, 0x31, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c, 0x65, 0x65, + 0x70, 0x28, 0x30, 0x2e, 0x30, 0x30, 0x31, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index e10917d3c..4e411ec54 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1284,24 +1284,20 @@ do end -- PIXEL EFFECTS + local GLSL_HEADER_LINE_COUNT = 6 + local GLSL_HEADER = [[#version 120 + #define number float + #define Image sampler2D + #define extern uniform + #define Texel texture2D + uniform sampler2D _tex0_;]] + local GLSL_FOOTER = [[void main() { + // fix weird crashing issue in OSX when _tex0_ is unused within effect() + float dummy = texture2D(_tex0_, vec2(.5)).r; + gl_FragColor = effect(gl_Color, _tex0_, gl_TexCoord[0].xy, gl_FragCoord.xy); + }]] function love.graphics._effectCodeToGLSL(code) - local header = [[#version 120 - #define number float - #define Image sampler2D - #define extern uniform - #define Texel texture2D - uniform sampler2D _tex0_;]] - local footer = [[void main() { - // fix weird crashing issue in OSX when _tex0_ is unused within effect() - float dummy = texture2D(_tex0_, vec2(.5)).r; - gl_FragColor = effect(gl_Color, _tex0_, gl_TexCoord[0].xy, gl_FragCoord.xy); - }]] - - local function include(quoted_path) return (love.filesystem.read(quoted_path:sub(2,-2))) end - code = code:gsub("#include (%b'')", include) - code = code:gsub('#include (%b"")', include) - - return table.concat{header, "\n", code, footer} + return table.concat{GLSL_HEADER, "\n", code, GLSL_FOOTER} end function love.graphics._transformGLSLErrorMessages(message) @@ -1317,7 +1313,8 @@ do linenumber, what, message = l:match("^%w+: 0:(%d+):%s*(%w+)%([^%)]+%)%s*(.+)$") end if linenumber and what and message then - lines[#lines+1] = ("Line %d: %s: %s"):format(linenumber - 5, what, message) + linenumber = linenumber - GLSL_HEADER_LINE_COUNT + lines[#lines+1] = ("Line %d: %s: %s"):format(linenumber, what, message) end end -- did not match any known error messages diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index 84b0b2535..1eb9df636 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -6260,52 +6260,43 @@ const unsigned char graphics_lua[] = 0x69, 0x6e, 0x74, 0x66, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x20, 0x45, 0x46, 0x46, 0x45, 0x43, 0x54, 0x53, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x5f, 0x4c, 0x49, 0x4e, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x20, 0x3d, 0x20, 0x36, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, + 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x23, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x32, 0x30, 0x0a, + 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x0a, + 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x0a, + 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x75, 0x6e, + 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x0a, + 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x0a, + 0x09, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, + 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x5d, 0x5d, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, + 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, + 0x09, 0x09, 0x2f, 0x2f, 0x20, 0x66, 0x69, 0x78, 0x20, 0x77, 0x65, 0x69, 0x72, 0x64, 0x20, 0x63, 0x72, 0x61, + 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x4f, 0x53, 0x58, + 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x20, 0x69, 0x73, 0x20, 0x75, 0x6e, + 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, + 0x28, 0x29, 0x0a, + 0x09, 0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x3d, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x28, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x76, 0x65, + 0x63, 0x32, 0x28, 0x2e, 0x35, 0x29, 0x29, 0x2e, 0x72, 0x3b, 0x0a, + 0x09, 0x09, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x65, + 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x67, 0x6c, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x5f, 0x74, + 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5b, + 0x30, 0x5d, 0x2e, 0x78, 0x79, 0x2c, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, + 0x64, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0a, + 0x09, 0x7d, 0x5d, 0x5d, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x54, 0x6f, 0x47, 0x4c, 0x53, 0x4c, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x5b, - 0x5b, 0x23, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x32, 0x30, 0x0a, - 0x09, 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, - 0x6c, 0x6f, 0x61, 0x74, 0x0a, - 0x09, 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x73, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x0a, - 0x09, 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x75, - 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x0a, - 0x09, 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x0a, - 0x09, 0x09, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, - 0x44, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x5d, 0x5d, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x5b, - 0x5b, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, - 0x09, 0x09, 0x09, 0x2f, 0x2f, 0x20, 0x66, 0x69, 0x78, 0x20, 0x77, 0x65, 0x69, 0x72, 0x64, 0x20, 0x63, 0x72, - 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x4f, 0x53, - 0x58, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x20, 0x69, 0x73, 0x20, 0x75, - 0x6e, 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, - 0x74, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x3d, 0x20, 0x74, - 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x28, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x76, - 0x65, 0x63, 0x32, 0x28, 0x2e, 0x35, 0x29, 0x29, 0x2e, 0x72, 0x3b, 0x0a, - 0x09, 0x09, 0x09, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, - 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x67, 0x6c, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x5f, - 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, - 0x5b, 0x30, 0x5d, 0x2e, 0x78, 0x79, 0x2c, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, - 0x72, 0x64, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0a, - 0x09, 0x09, 0x7d, 0x5d, 0x5d, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, - 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x28, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, - 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, - 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x28, 0x71, 0x75, 0x6f, 0x74, 0x65, - 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x3a, 0x73, 0x75, 0x62, 0x28, 0x32, 0x2c, 0x2d, 0x32, 0x29, 0x29, 0x29, - 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, - 0x28, 0x22, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x28, 0x25, 0x62, 0x27, 0x27, 0x29, 0x22, - 0x2c, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, - 0x28, 0x27, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x28, 0x25, 0x62, 0x22, 0x22, 0x29, 0x27, - 0x2c, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6e, - 0x63, 0x61, 0x74, 0x7b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x22, 0x2c, 0x20, - 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x7d, 0x0a, + 0x63, 0x61, 0x74, 0x7b, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x2c, 0x20, 0x22, + 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x46, 0x4f, + 0x4f, 0x54, 0x45, 0x52, 0x7d, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x47, 0x4c, @@ -6350,11 +6341,14 @@ const unsigned char graphics_lua[] = 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6c, + 0x69, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x2d, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x48, + 0x45, 0x41, 0x44, 0x45, 0x52, 0x5f, 0x4c, 0x49, 0x4e, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x5b, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x2b, 0x31, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x22, 0x4c, 0x69, 0x6e, 0x65, 0x20, 0x25, 0x64, 0x3a, 0x20, 0x25, 0x73, 0x3a, 0x20, 0x25, 0x73, 0x22, 0x29, 0x3a, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x2d, 0x20, 0x35, 0x2c, 0x20, 0x77, 0x68, 0x61, 0x74, 0x2c, 0x20, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0a, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2c, 0x20, 0x77, 0x68, 0x61, 0x74, 0x2c, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68,