diff --git a/changes.txt b/changes.txt index 2b98cbc6e..d5a383905 100644 --- a/changes.txt +++ b/changes.txt @@ -45,6 +45,7 @@ Released: N/A * Added love.keyboard.isModifierActive. * Added love.system.getPreferredLocales. * Added love.localechanged callback. +* Added World:getFixturesInArea(). * Changed the default font from Vera size 12 to Noto Sans size 13. * Changed the Texture class and implementation to no longer have separate Canvas and Image subclasses. @@ -165,7 +166,7 @@ Released: 2019-10-27 * Fixed audio clicks immediately after playing a Source on iOS. * Fixed Source:play + Source:stop + Source:play looping the first few ms of sound for streaming Sources on iOS. * Fixed Source:play + Source:seek looping the first few ms of sound for streaming Sources on iOS. -* Fixed occasional pops in streaming sources on iOS. +* Fixed occasional pops in streaming sources on iOS. * Fixed love.audio.play(sources) to use previously set playback positions on stopped Sources. * Fixed Source:setEffect(name, true) and Source:getEffect(name) when the effect has no associated Filter. * Fixed love.audio.newSource(filename, "queue") to cause a Lua error. @@ -437,7 +438,7 @@ Released: 2016-10-31 * Improved performance of Channel methods by roughly 2x in many cases. * Improved performance of Shader:send when small numbers of arguments are given. - + * Updated love.filesystem.mount to accept a DroppedFile as the first parameter. * Updated Shader:send to do type and argument checking based on the specified uniform variable's information instead of the arguments to the function. * Updated Shader:send to accept a flat table for matrix uniforms. diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 415a71ce3..ace4c02b1 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -89,55 +89,35 @@ static const char render_uniforms[] = R"( // According to the GLSL ES 1.0 spec, uniform precision must match between stages, // but we can't guarantee that highp is always supported in fragment shaders... // We *really* don't want to use mediump for these in vertex shaders though. +#ifdef LOVE_SPLIT_UNIFORMS_PER_DRAW +uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[12]; +uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw2[1]; +#else uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13]; +#endif -// These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't -// do it as an initializer. -LOVE_HIGHP_OR_MEDIUMP mat4 TransformMatrix; -LOVE_HIGHP_OR_MEDIUMP mat4 ProjectionMatrix; -LOVE_HIGHP_OR_MEDIUMP mat3 NormalMatrix; - -LOVE_HIGHP_OR_MEDIUMP vec4 love_ScreenSize; -LOVE_HIGHP_OR_MEDIUMP vec4 ConstantColor; - -LOVE_HIGHP_OR_MEDIUMP float CurrentDPIScale; - -LOVE_HIGHP_OR_MEDIUMP float ConstantPointSize; - +// Older GLSL doesn't support preprocessor line continuations... +#define TransformMatrix mat4(love_UniformsPerDraw[0], love_UniformsPerDraw[1], love_UniformsPerDraw[2], love_UniformsPerDraw[3]) +#define ProjectionMatrix mat4(love_UniformsPerDraw[4], love_UniformsPerDraw[5], love_UniformsPerDraw[6], love_UniformsPerDraw[7]) #define TransformProjectionMatrix (ProjectionMatrix * TransformMatrix) +#define NormalMatrix mat3(love_UniformsPerDraw[8].xyz, love_UniformsPerDraw[9].xyz, love_UniformsPerDraw[10].xyz) + +#define CurrentDPIScale (love_UniformsPerDraw[8].w) +#define ConstantPointSize (love_UniformsPerDraw[9].w) +#define ConstantColor (love_UniformsPerDraw[11]) + +#ifdef LOVE_SPLIT_UNIFORMS_PER_DRAW +#define love_ScreenSize (love_UniformsPerDraw2[0]) +#else +#define love_ScreenSize (love_UniformsPerDraw[12]) +#endif + // Alternate names #define ViewSpaceFromLocal TransformMatrix #define ClipSpaceFromView ProjectionMatrix #define ClipSpaceFromLocal TransformProjectionMatrix #define ViewNormalFromLocal NormalMatrix - -void love_initializeBuiltinUniforms() { - TransformMatrix = mat4( - love_UniformsPerDraw[0], - love_UniformsPerDraw[1], - love_UniformsPerDraw[2], - love_UniformsPerDraw[3] - ); - - ProjectionMatrix = mat4( - love_UniformsPerDraw[4], - love_UniformsPerDraw[5], - love_UniformsPerDraw[6], - love_UniformsPerDraw[7] - ); - - NormalMatrix = mat3( - love_UniformsPerDraw[8].xyz, - love_UniformsPerDraw[9].xyz, - love_UniformsPerDraw[10].xyz - ); - - CurrentDPIScale = love_UniformsPerDraw[8].w; - ConstantPointSize = love_UniformsPerDraw[9].w; - love_ScreenSize = love_UniformsPerDraw[11]; - ConstantColor = love_UniformsPerDraw[12]; -} )"; static const char global_functions[] = R"( @@ -274,7 +254,6 @@ LOVE_IO_LOCATION(1) varying vec4 VaryingColor; vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition); void main() { - love_initializeBuiltinUniforms(); VaryingTexCoord = VertexTexCoord; VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor; love_Position = position(ClipSpaceFromLocal, VertexPosition); @@ -285,7 +264,6 @@ static const char vertex_main_raw[] = R"( void vertexmain(); void main() { - love_initializeBuiltinUniforms(); vertexmain(); } )"; @@ -344,7 +322,6 @@ LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor; vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord); void main() { - love_initializeBuiltinUniforms(); love_PixelColor = effect(VaryingColor, MainTex, VaryingTexCoord.st, love_PixelCoord); } )"; @@ -380,7 +357,6 @@ LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor; void effect(); void main() { - love_initializeBuiltinUniforms(); effect(); } )"; @@ -389,7 +365,6 @@ static const char pixel_main_raw[] = R"( void pixelmain(); void main() { - love_initializeBuiltinUniforms(); pixelmain(); } )"; @@ -404,7 +379,6 @@ static const char compute_header[] = R"( )"; static const char compute_uniforms[] = R"( -void love_initializeBuiltinUniforms() {} )"; static const char compute_functions[] = R"()"; @@ -413,7 +387,6 @@ static const char compute_main[] = R"( void computemain(); void main() { - love_initializeBuiltinUniforms(); computemain(); } )"; @@ -575,7 +548,12 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, if (info.usesMRT) ss << "#define LOVE_MULTI_RENDER_TARGETS 1\n"; - for (const auto& def : options.defines) + // Note: backends are expected to handle this situation if highp is ever + // conditional in that backend. + if (!gfx->getCapabilities().features[Graphics::FEATURE_PIXEL_SHADER_HIGHP]) + ss << "#define LOVE_SPLIT_UNIFORMS_PER_DRAW 1"; + + for (const auto &def : options.defines) ss << "#define " + def.first + " " + def.second + "\n"; ss << "#define " << stageinfo.name << " " << stageinfo.name << "\n"; @@ -1204,11 +1182,12 @@ static StringMap languages(language static StringMap::Entry builtinNameEntries[] = { - { "MainTex", Shader::BUILTIN_TEXTURE_MAIN }, - { "love_VideoYChannel", Shader::BUILTIN_TEXTURE_VIDEO_Y }, - { "love_VideoCbChannel", Shader::BUILTIN_TEXTURE_VIDEO_CB }, - { "love_VideoCrChannel", Shader::BUILTIN_TEXTURE_VIDEO_CR }, - { "love_UniformsPerDraw", Shader::BUILTIN_UNIFORMS_PER_DRAW }, + { "MainTex", Shader::BUILTIN_TEXTURE_MAIN }, + { "love_VideoYChannel", Shader::BUILTIN_TEXTURE_VIDEO_Y }, + { "love_VideoCbChannel", Shader::BUILTIN_TEXTURE_VIDEO_CB }, + { "love_VideoCrChannel", Shader::BUILTIN_TEXTURE_VIDEO_CR }, + { "love_UniformsPerDraw", Shader::BUILTIN_UNIFORMS_PER_DRAW }, + { "love_UniformsPerDraw2", Shader::BUILTIN_UNIFORMS_PER_DRAW_2 }, }; static StringMap builtinNames(builtinNameEntries, sizeof(builtinNameEntries)); diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 862e9f268..579ca3a10 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -64,6 +64,7 @@ public: BUILTIN_TEXTURE_VIDEO_CB, BUILTIN_TEXTURE_VIDEO_CR, BUILTIN_UNIFORMS_PER_DRAW, + BUILTIN_UNIFORMS_PER_DRAW_2, BUILTIN_MAX_ENUM }; @@ -176,8 +177,10 @@ public: Matrix4 transformMatrix; Matrix4 projectionMatrix; Vector4 normalMatrix[3]; // 3x3 matrix padded to an array of 3 vector4s. - Vector4 screenSizeParams; Colorf constantColor; + + // Pixel shader-centric variables past this point. + Vector4 screenSizeParams; }; // Pointer to currently active Shader. diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index bdcc4d8ab..ee75d0c8c 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -46,6 +46,7 @@ static bool isBuffer(Shader::UniformType utype) Shader::Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM]) : love::graphics::Shader(stages) , program(0) + , splitUniformsPerDraw(false) , builtinUniforms() , builtinUniformInfo() { @@ -486,6 +487,11 @@ bool Shader::loadVolatile() { OpenGL::TempDebugGroup debuggroup("Shader load"); + // love::graphics::Shader sets up the shader code-side of this. + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr) + splitUniformsPerDraw = gfx->getCapabilities().features[Graphics::FEATURE_PIXEL_SHADER_HIGHP]; + // zero out active texture list textureUnits.clear(); textureUnits.push_back(TextureUnit()); @@ -1014,9 +1020,27 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, data.constantColor = gfx->getColor(); gammaCorrectColor(data.constantColor); - GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; - if (location >= 0) - glUniform4fv(location, 13, (const GLfloat *) &data); + // This branch is to avoid always declaring the whole array as highp in the + // vertex shader and mediump in the pixel shader for love's default shaders, + // on systems that don't support highp in pixel shaders. The default shaders + // use the transform matrices in vertex shaders and screen size params in + // pixel shaders. If there's a single array containing both and each shader + // stage declares a different precision, that's a compile error. + if (splitUniformsPerDraw) + { + GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; + if (location >= 0) + glUniform4fv(location, 12, (const GLfloat *) &data); + GLint location2 = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW_2]; + if (location2 >= 0) + glUniform4fv(location2, 1, (const GLfloat *) &data.screenSizeParams); + } + else + { + GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; + if (location >= 0) + glUniform4fv(location, 13, (const GLfloat *) &data); + } } int Shader::getUniformTypeComponents(GLenum type) const diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 40545a2a2..12ae79ae6 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -112,6 +112,8 @@ private: // volatile GLuint program; + bool splitUniformsPerDraw; + // Location values for any built-in uniform variables. GLint builtinUniforms[BUILTIN_MAX_ENUM]; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; diff --git a/src/modules/joystick/Joystick.cpp b/src/modules/joystick/Joystick.cpp index 1a3172dd4..7fec99840 100644 --- a/src/modules/joystick/Joystick.cpp +++ b/src/modules/joystick/Joystick.cpp @@ -58,16 +58,20 @@ STRINGMAP_CLASS_END(Joystick, Joystick::Hat, Joystick::HAT_MAX_ENUM, hat) STRINGMAP_CLASS_BEGIN(Joystick, Joystick::GamepadType, Joystick::GAMEPAD_TYPE_MAX_ENUM, gamepadType) { - { "unknown", Joystick::GAMEPAD_TYPE_UNKNOWN }, - { "xbox360", Joystick::GAMEPAD_TYPE_XBOX360 }, - { "xboxone", Joystick::GAMEPAD_TYPE_XBOXONE }, - { "ps3", Joystick::GAMEPAD_TYPE_PS3 }, - { "ps4", Joystick::GAMEPAD_TYPE_PS4 }, - { "ps5", Joystick::GAMEPAD_TYPE_PS5 }, - { "switchpro", Joystick::GAMEPAD_TYPE_NINTENDO_SWITCH_PRO }, - { "amazonluna", Joystick::GAMEPAD_TYPE_AMAZON_LUNA }, - { "stadia", Joystick::GAMEPAD_TYPE_STADIA }, - { "virtual", Joystick::GAMEPAD_TYPE_VIRTUAL }, + { "unknown", Joystick::GAMEPAD_TYPE_UNKNOWN }, + { "xbox360", Joystick::GAMEPAD_TYPE_XBOX360 }, + { "xboxone", Joystick::GAMEPAD_TYPE_XBOXONE }, + { "ps3", Joystick::GAMEPAD_TYPE_PS3 }, + { "ps4", Joystick::GAMEPAD_TYPE_PS4 }, + { "ps5", Joystick::GAMEPAD_TYPE_PS5 }, + { "switchpro", Joystick::GAMEPAD_TYPE_NINTENDO_SWITCH_PRO }, + { "amazonluna", Joystick::GAMEPAD_TYPE_AMAZON_LUNA }, + { "stadia", Joystick::GAMEPAD_TYPE_STADIA }, + { "virtual", Joystick::GAMEPAD_TYPE_VIRTUAL }, + { "shield", Joystick::GAMEPAD_TYPE_NVIDIA_SHIELD }, + { "joyconleft", Joystick::GAMEPAD_TYPE_JOYCON_LEFT }, + { "joyconright", Joystick::GAMEPAD_TYPE_JOYCON_RIGHT }, + { "joyconpair", Joystick::GAMEPAD_TYPE_JOYCON_PAIR }, } STRINGMAP_CLASS_END(Joystick, Joystick::GamepadType, Joystick::GAMEPAD_TYPE_MAX_ENUM, gamepadType) diff --git a/src/modules/joystick/Joystick.h b/src/modules/joystick/Joystick.h index 4ca9d26e2..40002b460 100644 --- a/src/modules/joystick/Joystick.h +++ b/src/modules/joystick/Joystick.h @@ -68,6 +68,10 @@ public: GAMEPAD_TYPE_AMAZON_LUNA, GAMEPAD_TYPE_STADIA, GAMEPAD_TYPE_VIRTUAL, + GAMEPAD_TYPE_NVIDIA_SHIELD, + GAMEPAD_TYPE_JOYCON_LEFT, + GAMEPAD_TYPE_JOYCON_RIGHT, + GAMEPAD_TYPE_JOYCON_PAIR, GAMEPAD_TYPE_MAX_ENUM }; diff --git a/src/modules/joystick/sdl/Joystick.cpp b/src/modules/joystick/sdl/Joystick.cpp index 3a43f7190..482a4b48a 100644 --- a/src/modules/joystick/sdl/Joystick.cpp +++ b/src/modules/joystick/sdl/Joystick.cpp @@ -260,6 +260,12 @@ Joystick::GamepadType Joystick::getGamepadType() const #if SDL_VERSION_ATLEAST(2, 0, 16) case SDL_CONTROLLER_TYPE_AMAZON_LUNA: return GAMEPAD_TYPE_AMAZON_LUNA; case SDL_CONTROLLER_TYPE_GOOGLE_STADIA: return GAMEPAD_TYPE_STADIA; +#endif +#if SDL_VERSION_ATLEAST(2, 24, 0) + case SDL_CONTROLLER_TYPE_NVIDIA_SHIELD: return GAMEPAD_TYPE_NVIDIA_SHIELD; + case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: return GAMEPAD_TYPE_JOYCON_LEFT; + case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: return GAMEPAD_TYPE_JOYCON_RIGHT; + case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: return GAMEPAD_TYPE_JOYCON_PAIR; #endif } #endif @@ -509,7 +515,7 @@ bool Joystick::setVibration(float left, float right, float duration) Uint32 length = SDL_HAPTIC_INFINITY; if (duration >= 0.0f) { - float maxduration = std::numeric_limits::max() / 1000.0f; + float maxduration = (float) (std::numeric_limits::max() / 1000.0); length = Uint32(std::min(duration, maxduration) * 1000); } diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index d7ba8d11d..598918d86 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -171,6 +171,28 @@ bool World::QueryCallback::ReportFixture(b2Fixture *fixture) return true; } +World::CollectCallback::CollectCallback(World *world, lua_State *L) + : world(world) + , L(L) +{ + lua_newtable(L); +} + +World::CollectCallback::~CollectCallback() +{ +} + +bool World::CollectCallback::ReportFixture(b2Fixture *f) +{ + Fixture *fixture = (Fixture *)world->findObject(f); + if (!fixture) + throw love::Exception("A fixture has escaped Memoizer!"); + luax_pushtype(L, fixture); + lua_rawseti(L, -2, i); + i++; + return true; +} + World::RayCastCallback::RayCastCallback(World *world, lua_State *L, int idx) : world(world) , L(L) @@ -556,6 +578,20 @@ int World::queryBoundingBox(lua_State *L) return 0; } +int World::getFixturesInArea(lua_State *L) +{ + float lx = (float)luaL_checknumber(L, 1); + float ly = (float)luaL_checknumber(L, 2); + float ux = (float)luaL_checknumber(L, 3); + float uy = (float)luaL_checknumber(L, 4); + b2AABB box; + box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly)); + box.upperBound = Physics::scaleDown(b2Vec2(ux, uy)); + CollectCallback query(this, L); + world->QueryAABB(&query, box); + return 1; +} + int World::rayCast(lua_State *L) { float x1 = (float)luaL_checknumber(L, 1); diff --git a/src/modules/physics/box2d/World.h b/src/modules/physics/box2d/World.h index 39bfe0333..a2d48f8ce 100644 --- a/src/modules/physics/box2d/World.h +++ b/src/modules/physics/box2d/World.h @@ -102,6 +102,18 @@ public: int funcidx; }; + class CollectCallback : public b2QueryCallback + { + public: + CollectCallback(World *world, lua_State *L); + ~CollectCallback(); + virtual bool ReportFixture(b2Fixture *fixture); + private: + World *world; + lua_State *L; + int i = 1; + }; + class RayCastCallback : public b2RayCastCallback { public: @@ -270,10 +282,15 @@ public: b2Body *getGroundBody() const; /** - * Gets all fixtures that overlap a given bounding box. + * Calls a callback on all fixtures that overlap a given bounding box. **/ int queryBoundingBox(lua_State *L); + /** + * Gets all fixtures that overlap a given bounding box. + **/ + int getFixturesInArea(lua_State *L); + /** * Raycasts the World for all Fixtures in the path of the ray. **/ diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index 6b3e13a48..e5dbae297 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -185,6 +185,15 @@ int w_World_queryBoundingBox(lua_State *L) return t->queryBoundingBox(L); } +int w_World_getFixturesInArea(lua_State *L) +{ + World *t = luax_checkworld(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&](){ ret = t->getFixturesInArea(L); }); + return ret; +} + int w_World_rayCast(lua_State *L) { World *t = luax_checkworld(L, 1); @@ -228,6 +237,7 @@ static const luaL_Reg w_World_functions[] = { "getJoints", w_World_getJoints }, { "getContacts", w_World_getContacts }, { "queryBoundingBox", w_World_queryBoundingBox }, + { "getFixturesInArea", w_World_getFixturesInArea }, { "rayCast", w_World_rayCast }, { "destroy", w_World_destroy }, { "isDestroyed", w_World_isDestroyed }, diff --git a/src/modules/sound/Decoder.cpp b/src/modules/sound/Decoder.cpp index 355b783c9..9b8923db6 100644 --- a/src/modules/sound/Decoder.cpp +++ b/src/modules/sound/Decoder.cpp @@ -39,7 +39,14 @@ Decoder::Decoder(Stream *stream, int bufferSize) if (!stream->isReadable() || !stream->isSeekable()) throw love::Exception("Decoder input stream must be readable and seekable."); - buffer = new char[bufferSize]; + try + { + buffer = new char[bufferSize]; + } + catch (std::exception &) + { + throw love::Exception("Out of memory."); + } } Decoder::~Decoder()