diff --git a/jni/love/src/common/runtime.cpp b/jni/love/src/common/runtime.cpp index dca9bb2d..a2a70cfd 100644 --- a/jni/love/src/common/runtime.cpp +++ b/jni/love/src/common/runtime.cpp @@ -465,7 +465,11 @@ bool luax_istype(lua_State *L, int idx, love::Type type) return false; Proxy *p = (Proxy *) lua_touserdata(L, idx); - return typeFlags[p->type][type]; + + if (p->type > INVALID_ID && p->type < TYPE_MAX_ENUM) + return typeFlags[p->type][type]; + else + return false; } int luax_getfunction(lua_State *L, const char *mod, const char *fn) diff --git a/jni/love/src/modules/event/wrap_Event.cpp b/jni/love/src/modules/event/wrap_Event.cpp index 8f9af72c..6f9d967f 100644 --- a/jni/love/src/modules/event/wrap_Event.cpp +++ b/jni/love/src/modules/event/wrap_Event.cpp @@ -32,11 +32,11 @@ namespace event #define instance() (Module::getInstance(Module::M_EVENT)) -static int poll_i(lua_State *L) +static int w_poll_i(lua_State *L) { - Message *m; + Message *m = nullptr; - while (instance()->poll(m)) + if (instance()->poll(m)) { int args = m->toLua(L); m->release(); @@ -47,23 +47,22 @@ static int poll_i(lua_State *L) return 0; } +int w_poll(lua_State *L) +{ + lua_pushcclosure(L, &w_poll_i, 0); + return 1; +} + int w_pump(lua_State *) { instance()->pump(); return 0; } -int w_poll(lua_State *L) -{ - lua_pushcclosure(L, &poll_i, 0); - return 1; -} - int w_wait(lua_State *L) { - Message *m; - - if ((m = instance()->wait())) + Message *m = instance()->wait(); + if (m) { int args = m->toLua(L); m->release(); @@ -75,12 +74,11 @@ int w_wait(lua_State *L) int w_push(lua_State *L) { - Message *m; + Message *m = Message::fromLua(L, 1); - bool success = (m = Message::fromLua(L, 1)) != NULL; - luax_pushboolean(L, success); + luax_pushboolean(L, m != nullptr); - if (!success) + if (m == nullptr) return 1; instance()->push(m); @@ -143,7 +141,9 @@ extern "C" int luaopen_love_event(lua_State *L) w.functions = functions; w.types = nullptr; - return luax_register_module(L, w); + int ret = luax_register_module(L, w); + + return ret; } } // event diff --git a/jni/love/src/modules/filesystem/Filesystem.h b/jni/love/src/modules/filesystem/Filesystem.h index 257c456a..f2114157 100644 --- a/jni/love/src/modules/filesystem/Filesystem.h +++ b/jni/love/src/modules/filesystem/Filesystem.h @@ -156,6 +156,12 @@ public: **/ virtual std::string getRealDirectory(const char *filename) const = 0; + /** + * Checks if a path exists. + * @param path The path to check. + **/ + virtual bool exists(const char *path) const = 0; + /** * Checks if a path is a directory. * @param dir The directory name to check. @@ -168,6 +174,12 @@ public: **/ virtual bool isFile(const char *file) const = 0; + /** + * Gets whether a filepath is actually a symlink. + * Always returns false if symlinks are not enabled. + **/ + virtual bool isSymlink(const char *filename) const = 0; + /** * Creates a directory. Write dir must be set. * @param dir The directory to create. @@ -232,12 +244,6 @@ public: **/ virtual bool areSymlinksEnabled() const = 0; - /** - * Gets whether a filepath is actually a symlink. - * Always returns false if symlinks are not enabled. - **/ - virtual bool isSymlink(const char *filename) const = 0; - // Require path accessors // Not const because it's R/W virtual std::vector &getRequirePath() = 0; diff --git a/jni/love/src/modules/filesystem/physfs/File.cpp b/jni/love/src/modules/filesystem/physfs/File.cpp index 8b07390b..12be9e5e 100644 --- a/jni/love/src/modules/filesystem/physfs/File.cpp +++ b/jni/love/src/modules/filesystem/physfs/File.cpp @@ -154,7 +154,11 @@ int64 File::read(void *dst, int64 size) if (size < 0) throw love::Exception("Invalid read size."); +#ifdef LOVE_USE_PHYSFS_2_1 + int64 read = PHYSFS_readBytes(file, dst, (PHYSFS_uint64) size); +#else int64 read = (int64)PHYSFS_read(file, dst, 1, (PHYSFS_uint32) size); +#endif return read; } @@ -171,7 +175,11 @@ bool File::write(const void *data, int64 size) throw love::Exception("Invalid write size."); // Try to write. +#ifdef LOVE_USE_PHYSFS_2_1 + int64 written = PHYSFS_writeBytes(file, data, (PHYSFS_uint64) size); +#else int64 written = (int64) PHYSFS_write(file, data, 1, (PHYSFS_uint32) size); +#endif // Check that correct amount of data was written. if (written != size) diff --git a/jni/love/src/modules/filesystem/physfs/File.h b/jni/love/src/modules/filesystem/physfs/File.h index 999c28e3..43609a9a 100644 --- a/jni/love/src/modules/filesystem/physfs/File.h +++ b/jni/love/src/modules/filesystem/physfs/File.h @@ -22,6 +22,7 @@ #define LOVE_FILESYSTEM_PHYSFS_FILE_H // LOVE +#include "common/config.h" #include "filesystem/File.h" // PhysFS @@ -34,6 +35,12 @@ // STD #include +// These platforms always use PhysFS 2.1. +#if (defined(LOVE_IOS) || defined(LOVE_ANDROID)) \ +&& (PHYSFS_VER_MAJOR == 2 && PHYSFS_VER_MINOR >= 1) +#define LOVE_USE_PHYSFS_2_1 +#endif + namespace love { namespace filesystem diff --git a/jni/love/src/modules/filesystem/physfs/Filesystem.cpp b/jni/love/src/modules/filesystem/physfs/Filesystem.cpp index bf5f09e8..ee0498cc 100644 --- a/jni/love/src/modules/filesystem/physfs/Filesystem.cpp +++ b/jni/love/src/modules/filesystem/physfs/Filesystem.cpp @@ -188,7 +188,13 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath) // We don't want old read-only save paths to accumulate when we set a new // identity. if (!old_save_path.empty()) + { +#ifdef LOVE_USE_PHYSFS_2_1 + PHYSFS_unmount(old_save_path.c_str()); +#else PHYSFS_removeFromSearchPath(old_save_path.c_str()); +#endif + } // Try to add the save directory to the search path. // (No error on fail, it means that the path doesn't exist). @@ -433,7 +439,11 @@ bool Filesystem::unmount(const char *archive) if (!mountPoint) return false; +#ifdef LOVE_USE_PHYSFS_2_1 + return PHYSFS_unmount(realPath.c_str()) != 0; +#else return PHYSFS_removeFromSearchPath(realPath.c_str()) != 0; +#endif } love::filesystem::File *Filesystem::newFile(const char *filename) const @@ -569,14 +579,40 @@ std::string Filesystem::getRealDirectory(const char *filename) const return std::string(dir); } +bool Filesystem::exists(const char *path) const +{ + return PHYSFS_exists(path) != 0; +} + bool Filesystem::isDirectory(const char *dir) const { +#ifdef LOVE_USE_PHYSFS_2_1 + PHYSFS_Stat stat = {}; + if (PHYSFS_stat(dir, &stat)) + return stat.filetype == PHYSFS_FILETYPE_DIRECTORY; + else + return false; +#else return PHYSFS_isDirectory(dir) != 0; +#endif } bool Filesystem::isFile(const char *file) const { - return PHYSFS_exists(file) && !PHYSFS_isDirectory(file); + return PHYSFS_exists(file) && !isDirectory(file); +} + +bool Filesystem::isSymlink(const char *filename) const +{ +#ifdef LOVE_USE_PHYSFS_2_1 + PHYSFS_Stat stat = {}; + if (PHYSFS_stat(filename, &stat)) + return stat.filetype == PHYSFS_FILETYPE_SYMLINK; + else + return false; +#else + return PHYSFS_isSymbolicLink(filename) != 0; +#endif } bool Filesystem::createDirectory(const char *dir) @@ -643,7 +679,15 @@ void Filesystem::getDirectoryItems(const char *dir, std::vector &it int64 Filesystem::getLastModified(const char *filename) const { - PHYSFS_sint64 time = PHYSFS_getLastModTime(filename); + PHYSFS_sint64 time = -1; + +#ifdef LOVE_USE_PHYSFS_2_1 + PHYSFS_Stat stat = {}; + if (PHYSFS_stat(filename, &stat)) + time = stat.modtime; +#else + time = PHYSFS_getLastModTime(filename); +#endif if (time == -1) throw love::Exception("Could not determine file modification date."); @@ -679,11 +723,6 @@ bool Filesystem::areSymlinksEnabled() const return PHYSFS_symbolicLinksPermitted() != 0; } -bool Filesystem::isSymlink(const char *filename) const -{ - return PHYSFS_isSymbolicLink(filename) != 0; -} - std::vector &Filesystem::getRequirePath() { return requirePath; diff --git a/jni/love/src/modules/filesystem/physfs/Filesystem.h b/jni/love/src/modules/filesystem/physfs/Filesystem.h index d3cd9665..fc6941e4 100644 --- a/jni/love/src/modules/filesystem/physfs/Filesystem.h +++ b/jni/love/src/modules/filesystem/physfs/Filesystem.h @@ -75,8 +75,10 @@ public: std::string getRealDirectory(const char *filename) const; + bool exists(const char *path) const; bool isDirectory(const char *dir) const; bool isFile(const char *file) const; + bool isSymlink(const char *filename) const; bool createDirectory(const char *dir); @@ -93,7 +95,6 @@ public: void setSymlinksEnabled(bool enable); bool areSymlinksEnabled() const; - bool isSymlink(const char *filename) const; std::vector &getRequirePath(); diff --git a/jni/love/src/modules/filesystem/wrap_Filesystem.cpp b/jni/love/src/modules/filesystem/wrap_Filesystem.cpp index 9b22b60c..9c7e26d5 100644 --- a/jni/love/src/modules/filesystem/wrap_Filesystem.cpp +++ b/jni/love/src/modules/filesystem/wrap_Filesystem.cpp @@ -316,6 +316,13 @@ int w_getExecutablePath(lua_State *L) return 1; } +int w_exists(lua_State *L) +{ + const char *arg = luaL_checkstring(L, 1); + luax_pushboolean(L, instance()->exists(arg)); + return 1; +} + int w_isDirectory(lua_State *L) { const char *arg = luaL_checkstring(L, 1); @@ -330,6 +337,13 @@ int w_isFile(lua_State *L) return 1; } +int w_isSymlink(lua_State *L) +{ + const char *filename = luaL_checkstring(L, 1); + luax_pushboolean(L, instance()->isSymlink(filename)); + return 1; +} + int w_createDirectory(lua_State *L) { const char *arg = luaL_checkstring(L, 1); @@ -551,13 +565,6 @@ int w_areSymlinksEnabled(lua_State *L) return 1; } -int w_isSymlink(lua_State *L) -{ - const char *filename = luaL_checkstring(L, 1); - luax_pushboolean(L, instance()->isSymlink(filename)); - return 1; -} - int w_getRequirePath(lua_State *L) { std::stringstream path; @@ -715,8 +722,10 @@ static const luaL_Reg functions[] = { "getSourceBaseDirectory", w_getSourceBaseDirectory }, { "getRealDirectory", w_getRealDirectory }, { "getExecutablePath", w_getExecutablePath }, + { "exists", w_exists }, { "isDirectory", w_isDirectory }, { "isFile", w_isFile }, + { "isSymlink", w_isSymlink }, { "createDirectory", w_createDirectory }, { "remove", w_remove }, { "read", w_read }, @@ -729,7 +738,6 @@ static const luaL_Reg functions[] = { "getSize", w_getSize }, { "setSymlinksEnabled", w_setSymlinksEnabled }, { "areSymlinksEnabled", w_areSymlinksEnabled }, - { "isSymlink", w_isSymlink }, { "newFileData", w_newFileData }, { "getRequirePath", w_getRequirePath }, { "setRequirePath", w_setRequirePath }, diff --git a/jni/love/src/modules/graphics/Graphics.cpp b/jni/love/src/modules/graphics/Graphics.cpp index 8dbfd21d..6c23bd3c 100644 --- a/jni/love/src/modules/graphics/Graphics.cpp +++ b/jni/love/src/modules/graphics/Graphics.cpp @@ -82,6 +82,16 @@ bool Graphics::getConstant(BlendMode in, const char *&out) return blendModes.find(in, out); } +bool Graphics::getConstant(const char *in, BlendAlpha &out) +{ + return blendAlphaModes.find(in, out); +} + +bool Graphics::getConstant(BlendAlpha in, const char *&out) +{ + return blendAlphaModes.find(in, out); +} + bool Graphics::getConstant(const char *in, LineStyle &out) { return lineStyles.find(in, out); @@ -102,6 +112,26 @@ bool Graphics::getConstant(LineJoin in, const char *&out) return lineJoins.find(in, out); } +bool Graphics::getConstant(const char *in, StencilAction &out) +{ + return stencilActions.find(in, out); +} + +bool Graphics::getConstant(StencilAction in, const char *&out) +{ + return stencilActions.find(in, out); +} + +bool Graphics::getConstant(const char *in, CompareMode &out) +{ + return compareModes.find(in, out); +} + +bool Graphics::getConstant(CompareMode in, const char *&out) +{ + return compareModes.find(in, out); +} + bool Graphics::getConstant(const char *in, Support &out) { return support.find(in, out); @@ -152,16 +182,24 @@ StringMap Graphics::drawModes(Graph StringMap::Entry Graphics::blendModeEntries[] = { - { "alpha", BLEND_ALPHA }, - { "add", BLEND_ADD }, + { "alpha", BLEND_ALPHA }, + { "add", BLEND_ADD }, { "subtract", BLEND_SUBTRACT }, { "multiply", BLEND_MULTIPLY }, - { "screen", BLEND_SCREEN }, - { "replace", BLEND_REPLACE }, + { "screen", BLEND_SCREEN }, + { "replace", BLEND_REPLACE }, }; StringMap Graphics::blendModes(Graphics::blendModeEntries, sizeof(Graphics::blendModeEntries)); +StringMap::Entry Graphics::blendAlphaEntries[] = +{ + { "alphamultiply", BLENDALPHA_MULTIPLY }, + { "premultiplied", BLENDALPHA_PREMULTIPLIED }, +}; + +StringMap Graphics::blendAlphaModes(Graphics::blendAlphaEntries, sizeof(Graphics::blendAlphaEntries)); + StringMap::Entry Graphics::lineStyleEntries[] = { { "smooth", LINE_SMOOTH }, @@ -179,6 +217,31 @@ StringMap::Entry Graphics::lin StringMap Graphics::lineJoins(Graphics::lineJoinEntries, sizeof(Graphics::lineJoinEntries)); +StringMap::Entry Graphics::stencilActionEntries[] = +{ + { "replace", STENCIL_REPLACE }, + { "increment", STENCIL_INCREMENT }, + { "decrement", STENCIL_DECREMENT }, + { "incrementwrap", STENCIL_INCREMENT_WRAP }, + { "decrementwrap", STENCIL_DECREMENT_WRAP }, + { "invert", STENCIL_INVERT }, +}; + +StringMap Graphics::stencilActions(Graphics::stencilActionEntries, sizeof(Graphics::stencilActionEntries)); + +StringMap::Entry Graphics::compareModeEntries[] = +{ + { "less", COMPARE_LESS }, + { "lequal", COMPARE_LEQUAL }, + { "equal", COMPARE_EQUAL }, + { "gequal", COMPARE_GEQUAL }, + { "greater", COMPARE_GREATER }, + { "notequal", COMPARE_NOTEQUAL }, + { "always", COMPARE_ALWAYS }, +}; + +StringMap Graphics::compareModes(Graphics::compareModeEntries, sizeof(Graphics::compareModeEntries)); + StringMap::Entry Graphics::supportEntries[] = { { "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS }, diff --git a/jni/love/src/modules/graphics/Graphics.h b/jni/love/src/modules/graphics/Graphics.h index ede4eba0..583822c5 100644 --- a/jni/love/src/modules/graphics/Graphics.h +++ b/jni/love/src/modules/graphics/Graphics.h @@ -81,6 +81,13 @@ public: BLEND_MAX_ENUM }; + enum BlendAlpha + { + BLENDALPHA_MULTIPLY, + BLENDALPHA_PREMULTIPLIED, + BLENDALPHA_MAX_ENUM + }; + enum LineStyle { LINE_ROUGH, @@ -96,6 +103,29 @@ public: LINE_JOIN_MAX_ENUM }; + enum StencilAction + { + STENCIL_REPLACE, + STENCIL_INCREMENT, + STENCIL_DECREMENT, + STENCIL_INCREMENT_WRAP, + STENCIL_DECREMENT_WRAP, + STENCIL_INVERT, + STENCIL_MAX_ENUM + }; + + enum CompareMode + { + COMPARE_LESS, + COMPARE_LEQUAL, + COMPARE_EQUAL, + COMPARE_GEQUAL, + COMPARE_GREATER, + COMPARE_NOTEQUAL, + COMPARE_ALWAYS, + COMPARE_MAX_ENUM + }; + enum Support { SUPPORT_MULTI_CANVAS_FORMATS, @@ -232,12 +262,21 @@ public: static bool getConstant(const char *in, BlendMode &out); static bool getConstant(BlendMode in, const char *&out); + static bool getConstant(const char *in, BlendAlpha &out); + static bool getConstant(BlendAlpha in, const char *&out); + static bool getConstant(const char *in, LineStyle &out); static bool getConstant(LineStyle in, const char *&out); static bool getConstant(const char *in, LineJoin &out); static bool getConstant(LineJoin in, const char *&out); + static bool getConstant(const char *in, StencilAction &out); + static bool getConstant(StencilAction in, const char *&out); + + static bool getConstant(const char *in, CompareMode &out); + static bool getConstant(CompareMode in, const char *&out); + static bool getConstant(const char *in, Support &out); static bool getConstant(Support in, const char *&out); @@ -258,12 +297,21 @@ private: static StringMap::Entry blendModeEntries[]; static StringMap blendModes; + static StringMap::Entry blendAlphaEntries[]; + static StringMap blendAlphaModes; + static StringMap::Entry lineStyleEntries[]; static StringMap lineStyles; static StringMap::Entry lineJoinEntries[]; static StringMap lineJoins; + static StringMap::Entry stencilActionEntries[]; + static StringMap stencilActions; + + static StringMap::Entry compareModeEntries[]; + static StringMap compareModes; + static StringMap::Entry supportEntries[]; static StringMap support; diff --git a/jni/love/src/modules/graphics/opengl/Canvas.cpp b/jni/love/src/modules/graphics/opengl/Canvas.cpp index a2904c6c..9881c9ca 100644 --- a/jni/love/src/modules/graphics/opengl/Canvas.cpp +++ b/jni/love/src/modules/graphics/opengl/Canvas.cpp @@ -558,7 +558,7 @@ bool Canvas::checkCreateStencil() if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil) { - format = GL_DEPTH_STENCIL; + format = GL_DEPTH24_STENCIL8; attachment = GL_DEPTH_STENCIL_ATTACHMENT; } diff --git a/jni/love/src/modules/graphics/opengl/Font.cpp b/jni/love/src/modules/graphics/opengl/Font.cpp index 25391875..d98372ec 100644 --- a/jni/love/src/modules/graphics/opengl/Font.cpp +++ b/jni/love/src/modules/graphics/opengl/Font.cpp @@ -617,7 +617,7 @@ std::vector Font::generateVerticesFormatted(const ColoredCode return drawcommands; } -void Font::drawVertices(const std::vector &drawcommands) +void Font::drawVertices(const std::vector &drawcommands, bool bufferedvertices) { // Vertex attribute pointers need to be set before calling this function. // This assumes that the attribute pointers are constant for all vertices. @@ -634,7 +634,12 @@ void Font::drawVertices(const std::vector &drawcommands) const GLenum gltype = quadIndices.getType(); const size_t elemsize = quadIndices.getElementSize(); - GLBuffer::Bind bind(*quadIndices.getBuffer()); + // We only get indices from the index buffer if we're also using vertex + // buffers, because at least one graphics driver (the one for Kepler nvidia + // GPUs in OS X 10.11) fails to render geometry if an index buffer is used + // with client-side vertex arrays. + if (bufferedvertices) + quadIndices.getBuffer()->bind(); // We need a separate draw call for every section of the text which uses a // different texture than the previous section. @@ -645,8 +650,15 @@ void Font::drawVertices(const std::vector &drawcommands) // TODO: Use glDrawElementsBaseVertex when supported? gl.bindTexture(cmd.texture); - gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getPointer(offset)); + + if (bufferedvertices) + gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getPointer(offset)); + else + gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getIndices(offset)); } + + if (bufferedvertices) + quadIndices.getBuffer()->unbind(); } void Font::printv(const Matrix4 &t, const std::vector &drawcommands, const std::vector &vertices) @@ -665,7 +677,7 @@ void Font::printv(const Matrix4 &t, const std::vector &drawcommands gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR); - drawVertices(drawcommands); + drawVertices(drawcommands, false); } void Font::print(const std::vector &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) diff --git a/jni/love/src/modules/graphics/opengl/Font.h b/jni/love/src/modules/graphics/opengl/Font.h index 6ed474b0..3f65d777 100644 --- a/jni/love/src/modules/graphics/opengl/Font.h +++ b/jni/love/src/modules/graphics/opengl/Font.h @@ -109,7 +109,7 @@ public: std::vector generateVerticesFormatted(const ColoredCodepoints &text, float wrap, AlignMode align, std::vector &vertices, TextInfo *info = nullptr); - void drawVertices(const std::vector &drawcommands); + void drawVertices(const std::vector &drawcommands, bool bufferedvertices); static void getCodepointsFromString(const std::string &str, Codepoints &codepoints); static void getCodepointsFromString(const std::vector &strs, ColoredCodepoints &codepoints); diff --git a/jni/love/src/modules/graphics/opengl/GLBuffer.cpp b/jni/love/src/modules/graphics/opengl/GLBuffer.cpp index 2a778924..ad17a009 100644 --- a/jni/love/src/modules/graphics/opengl/GLBuffer.cpp +++ b/jni/love/src/modules/graphics/opengl/GLBuffer.cpp @@ -244,7 +244,9 @@ void GLBuffer::unload() size_t QuadIndices::maxSize = 0; size_t QuadIndices::elementSize = 0; size_t QuadIndices::objectCount = 0; + GLBuffer *QuadIndices::indexBuffer = nullptr; +char *QuadIndices::indices = nullptr; QuadIndices::QuadIndices(size_t size) : size(size) @@ -259,6 +261,7 @@ QuadIndices::QuadIndices(size_t size) if (indexBuffer == nullptr || size > maxSize) { GLBuffer *newbuffer = nullptr; + char *newindices = nullptr; // Depending on the size, a switch to int and more memory is needed. GLenum targettype = getType(size); @@ -271,9 +274,12 @@ QuadIndices::QuadIndices(size_t size) try { newbuffer = new GLBuffer(buffersize, nullptr, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW); + newindices = new char[buffersize]; } catch (std::bad_alloc &) { + delete[] newbuffer; + delete[] newindices; throw love::Exception("Out of memory."); } @@ -281,6 +287,10 @@ QuadIndices::QuadIndices(size_t size) // The old GLBuffer can now be deleted. delete indexBuffer; indexBuffer = newbuffer; + + delete[] indices; + indices = newindices; + maxSize = size; elementSize = elemsize; @@ -319,6 +329,9 @@ QuadIndices::~QuadIndices() { delete indexBuffer; indexBuffer = nullptr; + + delete[] indices; + indices = nullptr; } } @@ -355,13 +368,15 @@ const void *QuadIndices::getPointer(size_t offset) const return indexBuffer->getPointer(offset); } +const void *QuadIndices::getIndices(size_t offset) const +{ + return indices + offset; +} + template void QuadIndices::fill() { - GLBuffer::Bind bind(*indexBuffer); - GLBuffer::Mapper mapper(*indexBuffer); - - T *indices = (T *) mapper.get(); + T *inds = (T *) indices; // 0----2 // | / | @@ -369,14 +384,17 @@ void QuadIndices::fill() // 1----3 for (size_t i = 0; i < maxSize; ++i) { - indices[i*6+0] = T(i * 4 + 0); - indices[i*6+1] = T(i * 4 + 1); - indices[i*6+2] = T(i * 4 + 2); + inds[i*6+0] = T(i * 4 + 0); + inds[i*6+1] = T(i * 4 + 1); + inds[i*6+2] = T(i * 4 + 2); - indices[i*6+3] = T(i * 4 + 2); - indices[i*6+4] = T(i * 4 + 1); - indices[i*6+5] = T(i * 4 + 3); + inds[i*6+3] = T(i * 4 + 2); + inds[i*6+4] = T(i * 4 + 1); + inds[i*6+5] = T(i * 4 + 3); } + + GLBuffer::Bind bind(*indexBuffer); + indexBuffer->fill(0, indexBuffer->getSize(), indices); } } // opengl diff --git a/jni/love/src/modules/graphics/opengl/GLBuffer.h b/jni/love/src/modules/graphics/opengl/GLBuffer.h index 940db89b..9b64442b 100644 --- a/jni/love/src/modules/graphics/opengl/GLBuffer.h +++ b/jni/love/src/modules/graphics/opengl/GLBuffer.h @@ -384,6 +384,20 @@ public: */ const void *getPointer(size_t offset) const; + /** + * Returns a direct pointer to the index data. + * + * At least one graphics driver (the one for Kepler nvidia GPUs in OS X) + * fails to render geometry if the vertex data was a direct CPU pointer but + * the index data came from an Index Buffer. + * So the direct pointer to the index buffer should be used instead of the + * index buffer when rendering using client-side vertex arrays. + * + * @param offset An offset in bytes into the index data. + * @return A direct pointer to the index data at the specified offset. + **/ + const void *getIndices(size_t offset) const; + private: /** @@ -406,6 +420,9 @@ private: // The GLBuffer for the element array. Can be null. static GLBuffer *indexBuffer; + + // The array of indices that will also be stored in the index buffer. + static char *indices; }; } // opengl diff --git a/jni/love/src/modules/graphics/opengl/Graphics.cpp b/jni/love/src/modules/graphics/opengl/Graphics.cpp index 6215082a..8339b045 100644 --- a/jni/love/src/modules/graphics/opengl/Graphics.cpp +++ b/jni/love/src/modules/graphics/opengl/Graphics.cpp @@ -106,7 +106,7 @@ void Graphics::restoreState(const DisplayState &s) setColor(s.color); setBackgroundColor(s.backgroundColor); - setBlendMode(s.blendMode, s.blendMultiplyAlpha); + setBlendMode(s.blendMode, s.blendAlphaMode); setLineWidth(s.lineWidth); setLineStyle(s.lineStyle); @@ -119,7 +119,7 @@ void Graphics::restoreState(const DisplayState &s) else setScissor(); - setStencilTest(s.stencilTest, s.stencilInvert); + setStencilTest(s.stencilCompare, s.stencilTestValue); setFont(s.font.get()); setShader(s.shader.get()); @@ -141,8 +141,8 @@ void Graphics::restoreStateChecked(const DisplayState &s) setBackgroundColor(s.backgroundColor); - if (s.blendMode != cur.blendMode || s.blendMultiplyAlpha != cur.blendMultiplyAlpha) - setBlendMode(s.blendMode, s.blendMultiplyAlpha); + if (s.blendMode != cur.blendMode || s.blendAlphaMode != cur.blendAlphaMode) + setBlendMode(s.blendMode, s.blendAlphaMode); // These are just simple assignments. setLineWidth(s.lineWidth); @@ -160,8 +160,8 @@ void Graphics::restoreStateChecked(const DisplayState &s) setScissor(); } - if (s.stencilTest != cur.stencilTest || s.stencilInvert != cur.stencilInvert) - setStencilTest(s.stencilTest, s.stencilInvert); + if (s.stencilCompare != cur.stencilCompare || s.stencilTestValue != cur.stencilTestValue) + setStencilTest(s.stencilCompare, s.stencilTestValue); setFont(s.font.get()); setShader(s.shader.get()); @@ -433,7 +433,7 @@ void Graphics::setDebug(bool enable) void Graphics::reset() { DisplayState s; - drawToStencilBuffer(false); + stopDrawToStencilBuffer(); restoreState(s); origin(); } @@ -641,24 +641,9 @@ bool Graphics::getScissor(int &x, int &y, int &width, int &height) const return state.scissor; } -void Graphics::drawToStencilBuffer(bool enable) +void Graphics::drawToStencilBuffer(StencilAction action, int value) { - if (writingToStencil == enable) - return; - - writingToStencil = enable; - - if (!enable) - { - const DisplayState &state = states.back(); - - // Revert the color write mask. - setColorMask(state.colorMask); - - // Use the user-set stencil test state when writes are disabled. - setStencilTest(state.stencilTest, state.stencilInvert); - return; - } + writingToStencil = true; // Make sure the active canvas has a stencil buffer. if (Canvas::current) @@ -667,23 +652,63 @@ void Graphics::drawToStencilBuffer(bool enable) // Disable color writes but don't save the state for it. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + GLenum glaction = GL_REPLACE; + + switch (action) + { + case STENCIL_REPLACE: + default: + glaction = GL_REPLACE; + break; + case STENCIL_INCREMENT: + glaction = GL_INCR; + break; + case STENCIL_DECREMENT: + glaction = GL_DECR; + break; + case STENCIL_INCREMENT_WRAP: + glaction = GL_INCR_WRAP; + break; + case STENCIL_DECREMENT_WRAP: + glaction = GL_DECR_WRAP; + break; + case STENCIL_INVERT: + glaction = GL_INVERT; + break; + } + // The stencil test must be enabled in order to write to the stencil buffer. glEnable(GL_STENCIL_TEST); - - glStencilFunc(GL_ALWAYS, 1, 1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glStencilFunc(GL_ALWAYS, value, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, glaction); } -void Graphics::setStencilTest(bool enable, bool invert) +void Graphics::stopDrawToStencilBuffer() +{ + if (!writingToStencil) + return; + + writingToStencil = false; + + const DisplayState &state = states.back(); + + // Revert the color write mask. + setColorMask(state.colorMask); + + // Use the user-set stencil test state when writes are disabled. + setStencilTest(state.stencilCompare, state.stencilTestValue); +} + +void Graphics::setStencilTest(CompareMode compare, int value) { DisplayState &state = states.back(); - state.stencilTest = enable; - state.stencilInvert = invert; + state.stencilCompare = compare; + state.stencilTestValue = value; if (writingToStencil) return; - if (!enable) + if (compare == COMPARE_ALWAYS) { glDisable(GL_STENCIL_TEST); return; @@ -693,16 +718,61 @@ void Graphics::setStencilTest(bool enable, bool invert) if (Canvas::current) Canvas::current->checkCreateStencil(); + GLenum glcompare = GL_EQUAL; + + /** + * Q: Why are some of the compare modes inverted (e.g. COMPARE_LESS becomes + * GL_GREATER)? + * + * A: OpenGL / GPUs do the comparison in the opposite way that makes sense + * for this API. For example, if the compare function is GL_GREATER then the + * stencil test will pass if the reference value is greater than the value + * in the stencil buffer. With our API it's more intuitive to assume that + * setStencilTest(COMPARE_GREATER, 4) will make it pass if the stencil + * buffer has a value greater than 4. + **/ + + switch (compare) + { + case COMPARE_LESS: + glcompare = GL_GREATER; + break; + case COMPARE_LEQUAL: + glcompare = GL_GEQUAL; + break; + case COMPARE_EQUAL: + default: + glcompare = GL_EQUAL; + break; + case COMPARE_GEQUAL: + glcompare = GL_LEQUAL; + break; + case COMPARE_GREATER: + glcompare = GL_LESS; + break; + case COMPARE_NOTEQUAL: + glcompare = GL_NOTEQUAL; + break; + case COMPARE_ALWAYS: + glcompare = GL_ALWAYS; + break; + } + glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_EQUAL, invert ? 0 : 1, 1); + glStencilFunc(glcompare, value, 0xFFFFFFFF); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); } -void Graphics::getStencilTest(bool &enable, bool &invert) +void Graphics::setStencilTest() +{ + setStencilTest(COMPARE_ALWAYS, 0); +} + +void Graphics::getStencilTest(CompareMode &compare, int &value) { const DisplayState &state = states.back(); - enable = state.stencilTest; - invert = state.stencilInvert; + compare = state.stencilCompare; + value = state.stencilTestValue; } void Graphics::clearStencil() @@ -987,7 +1057,7 @@ Graphics::ColorMask Graphics::getColorMask() const return states.back().colorMask; } -void Graphics::setBlendMode(BlendMode mode, bool multiplyalpha) +void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode) { GLenum func = GL_FUNC_ADD; GLenum srcRGB = GL_ONE; @@ -1024,19 +1094,19 @@ void Graphics::setBlendMode(BlendMode mode, bool multiplyalpha) } // We can only do alpha-multiplication when srcRGB would have been unmodified. - if (srcRGB == GL_ONE && multiplyalpha) + if (srcRGB == GL_ONE && alphamode == BLENDALPHA_MULTIPLY) srcRGB = GL_SRC_ALPHA; glBlendEquation(func); glBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA); states.back().blendMode = mode; - states.back().blendMultiplyAlpha = multiplyalpha; + states.back().blendAlphaMode = alphamode; } -Graphics::BlendMode Graphics::getBlendMode(bool &multiplyalpha) const +Graphics::BlendMode Graphics::getBlendMode(BlendAlpha &alphamode) const { - multiplyalpha = states.back().blendMultiplyAlpha; + alphamode = states.back().blendAlphaMode; return states.back().blendMode; } diff --git a/jni/love/src/modules/graphics/opengl/Graphics.h b/jni/love/src/modules/graphics/opengl/Graphics.h index 8bf2d982..3fab2773 100644 --- a/jni/love/src/modules/graphics/opengl/Graphics.h +++ b/jni/love/src/modules/graphics/opengl/Graphics.h @@ -146,13 +146,15 @@ public: * Enables or disables drawing to the stencil buffer. When enabled, the * color buffer is disabled. **/ - void drawToStencilBuffer(bool enable); + void drawToStencilBuffer(StencilAction action, int value); + void stopDrawToStencilBuffer(); /** * Sets whether stencil testing is enabled. **/ - void setStencilTest(bool enable, bool invert); - void getStencilTest(bool &enable, bool &invert); + void setStencilTest(CompareMode compare, int value); + void setStencilTest(); + void getStencilTest(CompareMode &compare, int &value); /** * Clear the stencil buffer in the active Canvas(es.) @@ -241,12 +243,12 @@ public: /** * Sets the current blend mode. **/ - void setBlendMode(BlendMode mode, bool multiplyalpha); + void setBlendMode(BlendMode mode, BlendAlpha alphamode); /** * Gets the current blend mode. **/ - BlendMode getBlendMode(bool &multiplyalpha) const; + BlendMode getBlendMode(BlendAlpha &alphamode) const; /** * Sets the default filter for images, canvases, and fonts. @@ -476,7 +478,7 @@ private: Colorf backgroundColor = Colorf(0.0, 0.0, 0.0, 255.0); BlendMode blendMode = BLEND_ALPHA; - bool blendMultiplyAlpha = true; + BlendAlpha blendAlphaMode = BLENDALPHA_MULTIPLY; float lineWidth = 1.0f; LineStyle lineStyle = LINE_SMOOTH; @@ -488,8 +490,8 @@ private: ScissorRect scissorRect = ScissorRect(); // Stencil. - bool stencilTest = false; - bool stencilInvert = false; + CompareMode stencilCompare = COMPARE_ALWAYS; + int stencilTestValue = 0; StrongRef font; StrongRef shader; diff --git a/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp b/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp index 83cb4969..43dee397 100644 --- a/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp @@ -141,11 +141,14 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].x); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].s); - { - GLsizei count = (GLsizei) quadIndices.getIndexCount(pCount); - GLBuffer::Bind ibo_bind(*quadIndices.getBuffer()); - gl.drawElements(GL_TRIANGLES, count, quadIndices.getType(), quadIndices.getPointer(0)); - } + GLsizei count = (GLsizei) quadIndices.getIndexCount(pCount); + GLenum gltype = quadIndices.getType(); + + // We use a client-side index array instead of an Index Buffers, because + // at least one graphics driver (the one for Kepler nvidia GPUs in OS X + // 10.11) fails to render geometry if an index buffer is used with + // client-side vertex arrays. + gl.drawElements(GL_TRIANGLES, count, gltype, quadIndices.getIndices(0)); } } // opengl diff --git a/jni/love/src/modules/graphics/opengl/Text.cpp b/jni/love/src/modules/graphics/opengl/Text.cpp index 06a0ac47..b6327107 100644 --- a/jni/love/src/modules/graphics/opengl/Text.cpp +++ b/jni/love/src/modules/graphics/opengl/Text.cpp @@ -245,7 +245,7 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR); - font->drawVertices(draw_commands); + font->drawVertices(draw_commands, true); } void Text::setFont(Font *f) diff --git a/jni/love/src/modules/graphics/opengl/Video.cpp b/jni/love/src/modules/graphics/opengl/Video.cpp index 4f33f4fb..e552b804 100644 --- a/jni/love/src/modules/graphics/opengl/Video.cpp +++ b/jni/love/src/modules/graphics/opengl/Video.cpp @@ -79,23 +79,23 @@ bool Video::loadVolatile() // Create the textures using the initial frame data. auto frame = (const love::video::VideoStream::Frame*) stream->getFrontBuffer(); - gl.bindTexture(textures[0]); - gl.setTextureFilter(filter); + int widths[3] = {frame->yw, frame->cw, frame->cw}; + int heights[3] = {frame->yh, frame->ch, frame->ch}; - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->yw, frame->yh, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->yplane); + const unsigned char *data[3] = {frame->yplane, frame->cbplane, frame->crplane}; - gl.bindTexture(textures[1]); - gl.setTextureFilter(filter); + Texture::Wrap wrap; // Clamp wrap mode. - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->cw, frame->ch, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->cbplane); + for (int i = 0; i < 3; i++) + { + gl.bindTexture(textures[i]); - gl.bindTexture(textures[2]); - gl.setTextureFilter(filter); + gl.setTextureFilter(filter); + gl.setTextureWrap(wrap); - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->cw, frame->ch, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->crplane); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widths[i], heights[i], 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, data[i]); + } return true; } @@ -154,17 +154,17 @@ void Video::update() { auto frame = (const love::video::VideoStream::Frame*) stream->getFrontBuffer(); - gl.bindTexture(textures[0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame->yw, frame->yh, - GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->yplane); + int widths[3] = {frame->yw, frame->cw, frame->cw}; + int heights[3] = {frame->yh, frame->ch, frame->ch}; - gl.bindTexture(textures[1]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame->cw, frame->ch, - GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->cbplane); + const unsigned char *data[3] = {frame->yplane, frame->cbplane, frame->crplane}; - gl.bindTexture(textures[2]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame->cw, frame->ch, - GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->crplane); + for (int i = 0; i < 3; i++) + { + gl.bindTexture(textures[i]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widths[i], heights[i], + GL_LUMINANCE, GL_UNSIGNED_BYTE, data[i]); + } } } diff --git a/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp b/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp index 9d98032b..b3a888d1 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -217,35 +217,63 @@ int w_stencil(lua_State *L) { luaL_checktype(L, 1, LUA_TFUNCTION); - // Second argument: whether to keep the contents of the stencil buffer. - if (lua_toboolean(L, 2) == 0) + Graphics::StencilAction action = Graphics::STENCIL_REPLACE; + + if (!lua_isnoneornil(L, 2)) + { + const char *actionstr = luaL_checkstring(L, 2); + if (!Graphics::getConstant(actionstr, action)) + return luaL_error(L, "Invalid stencil draw action: %s", actionstr); + } + + int stencilvalue = (int) luaL_optnumber(L, 3, 1); + + // Fourth argument: whether to keep the contents of the stencil buffer. + if (lua_toboolean(L, 4) == 0) instance()->clearStencil(); - instance()->drawToStencilBuffer(true); + instance()->drawToStencilBuffer(action, stencilvalue); // Call stencilfunc() lua_pushvalue(L, 1); lua_call(L, 0, 0); - instance()->drawToStencilBuffer(false); - + instance()->stopDrawToStencilBuffer(); return 0; } int w_setStencilTest(lua_State *L) { - bool enable = luax_toboolean(L, 1); - bool invert = luax_toboolean(L, 2); - instance()->setStencilTest(enable, invert); + // COMPARE_ALWAYS effectively disables stencil testing. + Graphics::CompareMode compare = Graphics::COMPARE_ALWAYS; + int comparevalue = 0; + + if (!lua_isnoneornil(L, 1)) + { + const char *comparestr = luaL_checkstring(L, 1); + if (!Graphics::getConstant(comparestr, compare)) + return luaL_error(L, "Invalid compare mode: %s", comparestr); + + comparevalue = (int) luaL_checknumber(L, 2); + } + + instance()->setStencilTest(compare, comparevalue); return 0; } int w_getStencilTest(lua_State *L) { - bool enabled, inverted; - instance()->getStencilTest(enabled, inverted); - luax_pushboolean(L, enabled); - luax_pushboolean(L, inverted); + Graphics::CompareMode compare = Graphics::COMPARE_ALWAYS; + int comparevalue = 1; + + instance()->getStencilTest(compare, comparevalue); + + const char *comparestr; + if (!Graphics::getConstant(compare, comparestr)) + return luaL_error(L, "Unknown compare mode."); + + lua_pushstring(L, comparestr); + lua_pushnumber(L, comparevalue); return 2; } @@ -1014,25 +1042,34 @@ int w_setBlendMode(lua_State *L) if (!Graphics::getConstant(str, mode)) return luaL_error(L, "Invalid blend mode: %s", str); - bool multiplyalpha = luax_optboolean(L, 2, true); + Graphics::BlendAlpha alphamode = Graphics::BLENDALPHA_MULTIPLY; + if (!lua_isnoneornil(L, 2)) + { + const char *alphastr = luaL_checkstring(L, 2); + if (!Graphics::getConstant(alphastr, alphamode)) + return luaL_error(L, "Invalid blend alpha mode: %s", alphastr); + } - luax_catchexcept(L, [&](){ instance()->setBlendMode(mode, multiplyalpha); }); + luax_catchexcept(L, [&](){ instance()->setBlendMode(mode, alphamode); }); return 0; } int w_getBlendMode(lua_State *L) { const char *str; - Graphics::BlendMode mode; - bool multiplyalpha = false; + const char *alphastr; - luax_catchexcept(L, [&](){ mode = instance()->getBlendMode(multiplyalpha); }); + Graphics::BlendAlpha alphamode; + Graphics::BlendMode mode = instance()->getBlendMode(alphamode); if (!Graphics::getConstant(mode, str)) return luaL_error(L, "Unknown blend mode"); + if (!Graphics::getConstant(alphamode, alphastr)) + return luaL_error(L, "Unknown blend alpha mode"); + lua_pushstring(L, str); - lua_pushboolean(L, multiplyalpha); + lua_pushstring(L, alphastr); return 2; } @@ -1201,7 +1238,7 @@ int w_newScreenshot(lua_State *L) int w_setCanvas(lua_State *L) { // Disable stencil writes. - instance()->drawToStencilBuffer(false); + instance()->stopDrawToStencilBuffer(); // called with none -> reset to default buffer if (lua_isnoneornil(L, 1)) diff --git a/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua b/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua index 823779cc..8940bd79 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua +++ b/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua @@ -366,7 +366,7 @@ function love.graphics.newVideo(file, loadaudio) elseif loadaudio == true then error("Video had no audio track", 2) else - video:getStream():setSync(love.video.newRemote()) + video:getStream():setSync() end return video diff --git a/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp b/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp index d430c48b..9c0bff21 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -26,6 +26,7 @@ // C++ #include +#include namespace love { @@ -108,12 +109,28 @@ const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int compon int w_Mesh_setVertices(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); - luaL_checktype(L, 2, LUA_TTABLE); size_t vertoffset = (size_t) luaL_optnumber(L, 3, 1) - 1; if (vertoffset >= t->getVertexCount()) return luaL_error(L, "Invalid vertex start index (must be between 1 and %d)", (int) t->getVertexCount()); + size_t stride = t->getVertexStride(); + size_t byteoffset = vertoffset * stride; + + if (luax_istype(L, 2, DATA_ID)) + { + Data *d = luax_checktype(L, 2, DATA_ID); + + size_t datasize = std::min(d->getSize(), (t->getVertexCount() - vertoffset) * stride); + char *bytedata = (char *) t->mapVertexData() + byteoffset; + + memcpy(bytedata, d->getData(), datasize); + + t->unmapVertexData(byteoffset, datasize); + return 0; + } + + luaL_checktype(L, 2, LUA_TTABLE); size_t nvertices = luax_objlen(L, 2); if (vertoffset + nvertices > t->getVertexCount()) @@ -125,9 +142,6 @@ int w_Mesh_setVertices(lua_State *L) for (const Mesh::AttribFormat &format : vertexformat) ncomponents += format.components; - size_t stride = t->getVertexStride(); - size_t byteoffset = vertoffset * stride; - char *data = (char *) t->mapVertexData() + byteoffset; for (size_t i = 0; i < nvertices; i++) diff --git a/jni/love/src/modules/graphics/opengl/wrap_Mesh.h b/jni/love/src/modules/graphics/opengl/wrap_Mesh.h index 9a95bbd6..f1f900ec 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Mesh.h +++ b/jni/love/src/modules/graphics/opengl/wrap_Mesh.h @@ -22,6 +22,7 @@ #define LOVE_GRAPHICS_OPENGL_WRAP_MESH_H // LOVE +#include "common/config.h" #include "common/runtime.h" #include "Mesh.h" diff --git a/jni/love/src/modules/graphics/opengl/wrap_Video.lua b/jni/love/src/modules/graphics/opengl/wrap_Video.lua index 216c869e..93104019 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Video.lua +++ b/jni/love/src/modules/graphics/opengl/wrap_Video.lua @@ -25,20 +25,9 @@ misrepresented as being the original software. local Video_mt = ... local Video = Video_mt.__index -function Video:loadRemote() - local stream = self:getStream() - local remote = love.video.newRemote() - stream:setSync(remote) - return remote -end - function Video:setSource(source) self:_setSource(source) - if source then - self:getStream():setSync(source) - else - self:getStream():setSync(love.video.newRemote()) - end + self:getStream():setSync(source) end function Video:play() diff --git a/jni/love/src/modules/math/MathModule.h b/jni/love/src/modules/math/MathModule.h index 0f0edf80..d1c73484 100644 --- a/jni/love/src/modules/math/MathModule.h +++ b/jni/love/src/modules/math/MathModule.h @@ -55,56 +55,9 @@ public: virtual ~Math(); - /** - * @copydoc RandomGenerator::random() - **/ - inline double random() + RandomGenerator *getRandomGenerator() { - return rng.random(); - } - - /** - * @copydoc RandomGenerator::random(double) - **/ - inline double random(double max) - { - return rng.random(max); - } - - /** - * @copydoc RandomGenerator::random(double,double) - **/ - inline double random(double min, double max) - { - return rng.random(min, max); - } - - /** - * @copydoc RandomGenerator::randomNormal() - **/ - inline double randomNormal(double stddev) - { - return rng.randomNormal(stddev); - } - - inline void setRandomSeed(RandomGenerator::Seed seed) - { - rng.setSeed(seed); - } - - inline RandomGenerator::Seed getRandomSeed() const - { - return rng.getSeed(); - } - - inline void setRandomState(const std::string &statestr) - { - rng.setState(statestr); - } - - inline std::string getRandomState() const - { - return rng.getState(); + return &rng; } /** diff --git a/jni/love/src/modules/math/wrap_Math.cpp b/jni/love/src/modules/math/wrap_Math.cpp index 54ac46c0..ff95aea9 100644 --- a/jni/love/src/modules/math/wrap_Math.cpp +++ b/jni/love/src/modules/math/wrap_Math.cpp @@ -39,44 +39,10 @@ namespace love namespace math { -int w_random(lua_State *L) +int w__getRandomGenerator(lua_State *L) { - return luax_getrandom(L, 1, Math::instance.random()); -} - -int w_randomNormal(lua_State *L) -{ - double stddev = luaL_optnumber(L, 1, 1.0); - double mean = luaL_optnumber(L, 2, 0.0); - double r = Math::instance.randomNormal(stddev); - - lua_pushnumber(L, r + mean); - return 1; -} - -int w_setRandomSeed(lua_State *L) -{ - luax_catchexcept(L, [&](){ Math::instance.setRandomSeed(luax_checkrandomseed(L, 1)); }); - return 0; -} - -int w_getRandomSeed(lua_State *L) -{ - RandomGenerator::Seed s = Math::instance.getRandomSeed(); - lua_pushnumber(L, (lua_Number) s.b32.low); - lua_pushnumber(L, (lua_Number) s.b32.high); - return 2; -} - -int w_setRandomState(lua_State *L) -{ - luax_catchexcept(L, [&](){ Math::instance.setRandomState(luax_checkstring(L, 1)); }); - return 0; -} - -int w_getRandomState(lua_State *L) -{ - luax_pushstring(L, Math::instance.getRandomState()); + RandomGenerator *t = Math::instance.getRandomGenerator(); + luax_pushtype(L, MATH_RANDOM_GENERATOR_ID, t); return 1; } @@ -463,12 +429,9 @@ static FFI_Math ffifuncs = // List of functions to wrap. static const luaL_Reg functions[] = { - { "random", w_random }, - { "randomNormal", w_randomNormal }, - { "setRandomSeed", w_setRandomSeed }, - { "getRandomSeed", w_getRandomSeed }, - { "setRandomState", w_setRandomState }, - { "getRandomState", w_getRandomState }, + // love.math.random etc. are defined in wrap_Math.lua. + + { "_getRandomGenerator", w__getRandomGenerator }, { "newRandomGenerator", w_newRandomGenerator }, { "newBezierCurve", w_newBezierCurve }, { "triangulate", w_triangulate }, @@ -502,7 +465,7 @@ extern "C" int luaopen_love_math(lua_State *L) int n = luax_register_module(L, w); - // Execute wrap_Event.lua, sending the math table and ffifuncs pointer as args. + // Execute wrap_Math.lua, sending the math table and ffifuncs pointer as args. luaL_loadbuffer(L, math_lua, sizeof(math_lua), "wrap_Math.lua"); lua_pushvalue(L, -2); lua_pushlightuserdata(L, &ffifuncs); diff --git a/jni/love/src/modules/math/wrap_Math.lua b/jni/love/src/modules/math/wrap_Math.lua index fa6127f1..c2dca8fe 100644 --- a/jni/love/src/modules/math/wrap_Math.lua +++ b/jni/love/src/modules/math/wrap_Math.lua @@ -22,7 +22,36 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --]] -local math, ffifuncspointer = ... +local love_math, ffifuncspointer = ... + +local type, tonumber, error = type, tonumber, error +local floor = math.floor + +local rng = love_math._getRandomGenerator() + +function love_math.random(l, u) + return rng:random(l, u) +end + +function love_math.randomNormal(stddev, mean) + return rng:randomNormal(stddev, mean) +end + +function love_math.setRandomSeed(low, high) + return rng:setSeed(low, high) +end + +function love_math.getRandomSeed() + return rng:getSeed() +end + +function love_math.setRandomState(state) + return rng:setState(state) +end + +function love_math.getRandomState() + return rng:getState() +end if type(jit) ~= "table" or not jit.status() then -- LuaJIT's FFI is *much* slower than LOVE's regular methods when the JIT @@ -33,8 +62,6 @@ end local status, ffi = pcall(require, "ffi") if not status then return end -local type, tonumber = type, tonumber - -- Matches the struct declaration in wrap_Math.cpp. pcall(ffi.cdef, [[ typedef struct FFI_Math @@ -54,7 +81,7 @@ local ffifuncs = ffi.cast("FFI_Math *", ffifuncspointer) -- Overwrite some regular love.math functions with FFI implementations. -function math.noise(x, y, z, w) +function love_math.noise(x, y, z, w) if w ~= nil then return tonumber(ffifuncs.noise4(x, y, z, w)) elseif z ~= nil then @@ -73,7 +100,7 @@ local function gammaToLinear(c) return c end -function math.gammaToLinear(r, g, b, a) +function love_math.gammaToLinear(r, g, b, a) if type(r) == "table" then local t = r return gammaToLinear(t[1]), gammaToLinear(t[2]), gammaToLinear(t[3]), t[4] @@ -88,7 +115,7 @@ local function linearToGamma(c) return c end -function math.linearToGamma(r, g, b, a) +function love_math.linearToGamma(r, g, b, a) if type(r) == "table" then local t = r return linearToGamma(t[1]), linearToGamma(t[2]), linearToGamma(t[3]), t[4] diff --git a/jni/love/src/modules/math/wrap_RandomGenerator.cpp b/jni/love/src/modules/math/wrap_RandomGenerator.cpp index 14dbc315..5a8238c9 100644 --- a/jni/love/src/modules/math/wrap_RandomGenerator.cpp +++ b/jni/love/src/modules/math/wrap_RandomGenerator.cpp @@ -23,6 +23,11 @@ #include #include +// Put the Lua code directly into a raw string literal. +static const char randomgenerator_lua[] = +#include "wrap_RandomGenerator.lua" +; + namespace love { namespace math @@ -56,41 +61,16 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx) return s; } -int luax_getrandom(lua_State *L, int startidx, double r) -{ - int l, u; - // from lua 5.1.4 source code: lmathlib.c:185 ff. - switch (lua_gettop(L) - (startidx - 1)) - { - case 0: - lua_pushnumber(L, r); - break; - case 1: - u = (int) luaL_checknumber(L, startidx); - luaL_argcheck(L, 1 <= u, startidx, "interval is empty"); - lua_pushnumber(L, floor(r * u) + 1); - break; - case 2: - l = (int) luaL_checknumber(L, startidx); - u = (int) luaL_checknumber(L, startidx + 1); - luaL_argcheck(L, l <= u, startidx + 1, "interval is empty"); - lua_pushnumber(L, floor(r * (u - l + 1)) + l); - break; - default: - return luaL_error(L, "wrong number of arguments"); - } - return 1; -} - RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx) { return luax_checktype(L, idx, MATH_RANDOM_GENERATOR_ID); } -int w_RandomGenerator_random(lua_State *L) +int w_RandomGenerator__random(lua_State *L) { RandomGenerator *rng = luax_checkrandomgenerator(L, 1); - return luax_getrandom(L, 2, rng->random()); + lua_pushnumber(L, rng->random()); + return 1; } int w_RandomGenerator_randomNormal(lua_State *L) @@ -135,9 +115,28 @@ int w_RandomGenerator_getState(lua_State *L) return 1; } +// C functions in a struct, necessary for the FFI versions of RandomGenerator functions. +struct FFI_RandomGenerator +{ + double (*random)(Proxy *p); +}; + +static FFI_RandomGenerator ffifuncs = +{ + [](Proxy *p) -> double // random() + { + // FIXME: We need better type-checking... + if (!typeFlags[p->type][MATH_RANDOM_GENERATOR_ID]) + return 0.0; + + RandomGenerator *rng = (RandomGenerator *) p->object; + return rng->random(); + } +}; + static const luaL_Reg w_RandomGenerator_functions[] = { - { "random", w_RandomGenerator_random }, + { "_random", w_RandomGenerator__random }, // random() is defined in wrap_RandomGenerator.lua. { "randomNormal", w_RandomGenerator_randomNormal }, { "setSeed", w_RandomGenerator_setSeed }, { "getSeed", w_RandomGenerator_getSeed }, @@ -148,7 +147,24 @@ static const luaL_Reg w_RandomGenerator_functions[] = extern "C" int luaopen_randomgenerator(lua_State *L) { - return luax_register_type(L, MATH_RANDOM_GENERATOR_ID, "RandomGenerator", w_RandomGenerator_functions, nullptr); + int n = luax_register_type(L, MATH_RANDOM_GENERATOR_ID, "RandomGenerator", w_RandomGenerator_functions, nullptr); + + luax_gettypemetatable(L, MATH_RANDOM_GENERATOR_ID); + + // Load and execute wrap_RandomGenerator.lua, sending the metatable and the + // ffi functions struct pointer as arguments. + if (lua_istable(L, -1)) + { + luaL_loadbuffer(L, randomgenerator_lua, sizeof(randomgenerator_lua), "wrap_RandomGenerator.lua"); + lua_pushvalue(L, -2); + lua_pushlightuserdata(L, &ffifuncs); + lua_call(L, 2, 0); + } + + // Pop the metatable. + lua_pop(L, 1); + + return n; } } // math diff --git a/jni/love/src/modules/math/wrap_RandomGenerator.h b/jni/love/src/modules/math/wrap_RandomGenerator.h index efbe733b..1f9bb7f4 100644 --- a/jni/love/src/modules/math/wrap_RandomGenerator.h +++ b/jni/love/src/modules/math/wrap_RandomGenerator.h @@ -33,7 +33,6 @@ namespace math // Helper functions. RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx); -int luax_getrandom(lua_State *L, int startidx, double r); RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx); extern "C" int luaopen_randomgenerator(lua_State *L); diff --git a/jni/love/src/modules/math/wrap_RandomGenerator.lua b/jni/love/src/modules/math/wrap_RandomGenerator.lua new file mode 100644 index 00000000..a7e4fe88 --- /dev/null +++ b/jni/love/src/modules/math/wrap_RandomGenerator.lua @@ -0,0 +1,80 @@ +R"luastring"--( +-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string. +-- There is a matching delimiter at the bottom of the file. + +--[[ +Copyright (c) 2006-2015 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. +--]] + +local RandomGenerator_mt, ffifuncspointer = ... +local RandomGenerator = RandomGenerator_mt.__index + +local type, tonumber, error = type, tonumber, error +local floor = math.floor + +local _random = RandomGenerator._random + +local function getrandom(r, l, u) + if u ~= nil then + if type(r) ~= "number" then error("bad argument #1 to 'random' (number expected)", 2) end + if type(l) ~= "number" then error("bad argument #2 to 'random' (number expected)", 2) end + return floor(r * (u - l + 1)) + l + elseif l ~= nil then + if type(l) ~= "number" then error("bad argument #1 to 'random' (number expected)", 2) end + return floor(r * l) + 1 + else + return r + end +end + +function RandomGenerator:random(l, u) + local r = _random(self) + return getrandom(r, l, u) +end + +if type(jit) ~= "table" or not jit.status() then + -- LuaJIT's FFI is *much* slower than LOVE's regular methods when the JIT + -- compiler is disabled. + return +end + +local status, ffi = pcall(require, "ffi") +if not status then return end + +pcall(ffi.cdef, [[ +typedef struct Proxy Proxy; + +typedef struct FFI_RandomGenerator +{ + double (*random)(Proxy *p); +} FFI_RandomGenerator; +]]) + +local ffifuncs = ffi.cast("FFI_RandomGenerator *", ffifuncspointer) + + +-- Overwrite some regular love.math functions with FFI implementations. + +function RandomGenerator:random(l, u) + local r = tonumber(ffifuncs.random(self)) + return getrandom(r, l, u) +end + +-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string. +--)luastring"--" diff --git a/jni/love/src/modules/sound/lullaby/ModPlugDecoder.h b/jni/love/src/modules/sound/lullaby/ModPlugDecoder.h index 9b7fb853..f50c37d8 100644 --- a/jni/love/src/modules/sound/lullaby/ModPlugDecoder.h +++ b/jni/love/src/modules/sound/lullaby/ModPlugDecoder.h @@ -30,7 +30,7 @@ #include "Decoder.h" // libmodplug -#ifdef LOVE_ANDROID +#if defined(LOVE_ANDROID) || defined(LOVE_IOS) #include #else #include diff --git a/jni/love/src/modules/window/sdl/Window.cpp b/jni/love/src/modules/window/sdl/Window.cpp index 25fdc9b4..df41b6f0 100644 --- a/jni/love/src/modules/window/sdl/Window.cpp +++ b/jni/love/src/modules/window/sdl/Window.cpp @@ -90,7 +90,7 @@ void Window::setGLFramebufferAttributes(int msaa, bool sRGB) SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (msaa > 0) ? 1 : 0); @@ -122,9 +122,9 @@ void Window::setGLContextAttributes(const ContextAttribs &attribs) int contextflags = 0; if (attribs.gles) - profilemask |= SDL_GL_CONTEXT_PROFILE_ES; + profilemask = SDL_GL_CONTEXT_PROFILE_ES; else if (attribs.debug) - profilemask |= SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; + profilemask = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; if (attribs.debug) contextflags |= SDL_GL_CONTEXT_DEBUG_FLAG; @@ -237,21 +237,24 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla if (preferGLES) std::rotate(attribslist.begin(), attribslist.begin() + 1, attribslist.end()); - if (context) - { - SDL_GL_DeleteContext(context); - context = nullptr; - } - std::string windowerror; + std::string contexterror; std::string glversion; - // Try each context profile in order. - for (ContextAttribs attribs : attribslist) + // Unfortunately some OpenGL context settings are part of the internal + // window state in the Windows and Linux SDL backends, so we have to + // recreate the window when we want to change those settings... + // Also, apparently some Intel drivers on Windows give back a Microsoft + // OpenGL 1.1 software renderer context when high MSAA values are requested! + + const auto create = [&](ContextAttribs attribs) -> bool { - // Unfortunately some OpenGL context settings are part of the internal - // window state in the Windows and Linux SDL backends, so we have to - // recreate the window when we want to change those settings... + if (context) + { + SDL_GL_DeleteContext(context); + context = nullptr; + } + if (window) { SDL_DestroyWindow(window); @@ -259,81 +262,18 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla window = nullptr; } - int curMSAA = msaa; - bool curSRGB = love::graphics::isGammaCorrect(); - - setGLFramebufferAttributes(curMSAA, curSRGB); - setGLContextAttributes(attribs); - window = SDL_CreateWindow(title.c_str(), x, y, w, h, windowflags); - if (!window && curMSAA > 0) - { - // The MSAA setting could have caused the failure. - setGLFramebufferAttributes(0, curSRGB); - window = SDL_CreateWindow(title.c_str(), x, y, w, h, windowflags); - if (window) - curMSAA = 0; - } - - if (!window && curSRGB) - { - // same with sRGB. - setGLFramebufferAttributes(curMSAA, false); - window = SDL_CreateWindow(title.c_str(), x, y, w, h, windowflags); - if (window) - curSRGB = false; - } - - if (!window && curMSAA > 0 && curSRGB) - { - // Or both! - setGLFramebufferAttributes(0, false); - window = SDL_CreateWindow(title.c_str(), x, y, w, h, windowflags); - if (window) - { - curMSAA = 0; - curSRGB = false; - } - } - - // Immediately try the next context profile if window creation failed. if (!window) { windowerror = std::string(SDL_GetError()); - continue; + return false; } - windowerror.clear(); - context = SDL_GL_CreateContext(window); - if (!context && curMSAA > 0) - { - // MSAA and sRGB settings can also cause CreateContext to fail, on - // certain SDL backends. - setGLFramebufferAttributes(0, curSRGB); - context = SDL_GL_CreateContext(window); - } - - if (!context && curSRGB) - { - setGLFramebufferAttributes(curMSAA, false); - context = SDL_GL_CreateContext(window); - } - - if (!context && curMSAA > 0 && curSRGB) - { - setGLFramebufferAttributes(0, false); - context = SDL_GL_CreateContext(window); - } - - if (!context && attribs.debug) - { - attribs.debug = false; - setGLContextAttributes(attribs); - context = SDL_GL_CreateContext(window); - } + if (!context) + contexterror = std::string(SDL_GetError()); // Make sure the context's version is at least what we requested. if (context && !checkGLVersion(attribs, glversion)) @@ -342,7 +282,58 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla context = nullptr; } - if (context) + if (!context) + { + SDL_DestroyWindow(window); + window = nullptr; + return false; + } + + return true; + }; + + // Try each context profile in order. + for (ContextAttribs attribs : attribslist) + { + int curMSAA = msaa; + bool curSRGB = love::graphics::isGammaCorrect(); + + setGLFramebufferAttributes(curMSAA, curSRGB); + setGLContextAttributes(attribs); + + windowerror.clear(); + contexterror.clear(); + + create(attribs); + + if (!window && curMSAA > 0) + { + // The MSAA setting could have caused the failure. + setGLFramebufferAttributes(0, curSRGB); + if (create(attribs)) + curMSAA = 0; + } + + if (!window && curSRGB) + { + // same with sRGB. + setGLFramebufferAttributes(curMSAA, false); + if (create(attribs)) + curSRGB = false; + } + + if (!window && curMSAA > 0 && curSRGB) + { + // Or both! + setGLFramebufferAttributes(0, false); + if (create(attribs)) + { + curMSAA = 0; + curSRGB = false; + } + } + + if (window && context) { love::graphics::setGammaCorrect(curSRGB); break; @@ -370,6 +361,8 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla std::string title = "Unable to initialize OpenGL"; std::string message = "This program requires a graphics card and video drivers which support OpenGL 2.1 or OpenGL ES 2."; + if (!contexterror.empty()) + message += "\n\nOpenGL context creation error: " + contexterror; if (!glversion.empty()) message += " \n\nDetected OpenGL version: " + glversion; @@ -478,7 +471,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) return false; // Make sure the window keeps any previously set icon. - setIcon(curMode.icon.get()); + setIcon(icon.get()); // Make sure the mouse keeps its previous grab setting. setMouseGrab(mouseGrabbed); @@ -497,7 +490,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) - gfx->setMode(curMode.pixelwidth, curMode.pixelheight); + gfx->setMode(pixelWidth, pixelHeight); #ifdef LOVE_ANDROID love::android::setImmersive(f.fullscreen); @@ -511,14 +504,14 @@ bool Window::onSizeChanged(int width, int height) if (!window) return false; - curMode.width = width; - curMode.height = height; + windowWidth = width; + windowHeight = height; - SDL_GL_GetDrawableSize(window, &curMode.pixelwidth, &curMode.pixelheight); + SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight); auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) - gfx->setViewportSize(curMode.pixelwidth, curMode.pixelheight); + gfx->setViewportSize(pixelWidth, pixelHeight); return true; } @@ -528,49 +521,43 @@ void Window::updateSettings(const WindowSettings &newsettings) Uint32 wflags = SDL_GetWindowFlags(window); // Set the new display mode as the current display mode. - SDL_GetWindowSize(window, &curMode.width, &curMode.height); - SDL_GL_GetDrawableSize(window, &curMode.pixelwidth, &curMode.pixelheight); + SDL_GetWindowSize(window, &windowWidth, &windowHeight); + SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight); if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { - curMode.settings.fullscreen = true; - curMode.settings.fstype = FULLSCREEN_DESKTOP; + settings.fullscreen = true; + settings.fstype = FULLSCREEN_DESKTOP; } else if ((wflags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN) { - curMode.settings.fullscreen = true; - curMode.settings.fstype = FULLSCREEN_EXCLUSIVE; + settings.fullscreen = true; + settings.fstype = FULLSCREEN_EXCLUSIVE; } else { - curMode.settings.fullscreen = false; - curMode.settings.fstype = newsettings.fstype; + settings.fullscreen = false; + settings.fstype = newsettings.fstype; } #ifdef LOVE_ANDROID - curMode.settings.fullscreen = love::android::getImmersive(); + settings.fullscreen = love::android::getImmersive(); #endif - // The min width/height is set to 0 internally in SDL when in fullscreen. - if (curMode.settings.fullscreen) - { - curMode.settings.minwidth = newsettings.minwidth; - curMode.settings.minheight = newsettings.minheight; - } - else - SDL_GetWindowMinimumSize(window, &curMode.settings.minwidth, &curMode.settings.minheight); + // SDL_GetWindowMinimumSize gives back 0,0 sometimes... + settings.minwidth = newsettings.minwidth; + settings.minheight = newsettings.minheight; - curMode.settings.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0; - curMode.settings.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0; - curMode.settings.centered = newsettings.centered; + settings.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0; + settings.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0; + settings.centered = newsettings.centered; - getPosition(curMode.settings.x, curMode.settings.y, curMode.settings.display); + getPosition(settings.x, settings.y, settings.display); - curMode.settings.highdpi = (wflags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; + settings.highdpi = (wflags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; - // Only minimize on focus loss if the window is in exclusive-fullscreen - // mode. - if (curMode.settings.fullscreen && curMode.settings.fstype == FULLSCREEN_EXCLUSIVE) + // Only minimize on focus loss if the window is in exclusive-fullscreen mode + if (settings.fullscreen && settings.fstype == FULLSCREEN_EXCLUSIVE) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1"); else SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); @@ -581,25 +568,25 @@ void Window::updateSettings(const WindowSettings &newsettings) SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers); SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples); - curMode.settings.msaa = (buffers > 0 ? samples : 0); - curMode.settings.vsync = SDL_GL_GetSwapInterval() != 0; + settings.msaa = (buffers > 0 ? samples : 0); + settings.vsync = SDL_GL_GetSwapInterval() != 0; SDL_DisplayMode dmode = {}; - SDL_GetCurrentDisplayMode(curMode.settings.display, &dmode); + SDL_GetCurrentDisplayMode(settings.display, &dmode); // May be 0 if the refresh rate can't be determined. - curMode.settings.refreshrate = (double) dmode.refresh_rate; + settings.refreshrate = (double) dmode.refresh_rate; } -void Window::getWindow(int &width, int &height, WindowSettings &settings) +void Window::getWindow(int &width, int &height, WindowSettings &newsettings) { // The window might have been modified (moved, resized, etc.) by the user. if (window) - updateSettings(curMode.settings); + updateSettings(settings); - width = curMode.width; - height = curMode.height; - settings = curMode.settings; + width = windowWidth; + height = windowHeight; + newsettings = settings; } void Window::close() @@ -632,7 +619,7 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) if (!window) return false; - WindowSettings newsettings = curMode.settings; + WindowSettings newsettings = settings; newsettings.fullscreen = fullscreen; newsettings.fstype = fstype; @@ -647,8 +634,8 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) sdlflags = SDL_WINDOW_FULLSCREEN; SDL_DisplayMode mode = {}; - mode.w = curMode.width; - mode.h = curMode.height; + mode.w = windowWidth; + mode.h = windowHeight; SDL_GetClosestDisplayMode(SDL_GetWindowDisplayIndex(window), &mode, &mode); SDL_SetWindowDisplayMode(window, &mode); @@ -664,10 +651,14 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) SDL_GL_MakeCurrent(window, context); updateSettings(newsettings); + // Apparently this gets un-set when we exit fullscreen (at least in OS X). + if (!fullscreen) + SDL_SetWindowMinimumSize(window, settings.minwidth, settings.minheight); + // Update the viewport size now instead of waiting for event polling. auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) - gfx->setViewportSize(curMode.pixelwidth, curMode.pixelheight); + gfx->setViewportSize(pixelWidth, pixelHeight); return true; } @@ -677,7 +668,7 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) bool Window::setFullscreen(bool fullscreen) { - return setFullscreen(fullscreen, curMode.settings.fstype); + return setFullscreen(fullscreen, settings.fstype); } int Window::getDisplayCount() const @@ -749,7 +740,7 @@ void Window::setPosition(int x, int y, int displayindex) SDL_SetWindowPosition(window, x, y); - curMode.settings.useposition = true; + settings.useposition = true; } void Window::getPosition(int &x, int &y, int &displayindex) @@ -801,7 +792,7 @@ bool Window::setIcon(love::image::ImageData *imgd) if (!imgd) return false; - curMode.icon.set(imgd); + icon.set(imgd); if (!window) return false; @@ -842,7 +833,7 @@ bool Window::setIcon(love::image::ImageData *imgd) love::image::ImageData *Window::getIcon() { - return curMode.icon.get(); + return icon.get(); } void Window::setDisplaySleepEnabled(bool enable) @@ -917,24 +908,24 @@ bool Window::isMouseGrabbed() const void Window::getPixelDimensions(int &w, int &h) const { - w = curMode.pixelwidth; - h = curMode.pixelheight; + w = pixelWidth; + h = pixelHeight; } void Window::windowToPixelCoords(double *x, double *y) const { if (x != nullptr) - *x = (*x) * ((double) curMode.pixelwidth / (double) curMode.width); + *x = (*x) * ((double) pixelWidth / (double) windowWidth); if (y != nullptr) - *y = (*y) * ((double) curMode.pixelheight / (double) curMode.height); + *y = (*y) * ((double) pixelHeight / (double) windowHeight); } void Window::pixelToWindowCoords(double *x, double *y) const { if (x != nullptr) - *x = (*x) * ((double) curMode.width / (double) curMode.pixelwidth); + *x = (*x) * ((double) windowWidth / (double) pixelWidth); if (y != nullptr) - *y = (*y) * ((double) curMode.height / (double) curMode.pixelheight); + *y = (*y) * ((double) windowHeight / (double) pixelHeight); } double Window::getPixelScale() const @@ -942,7 +933,7 @@ double Window::getPixelScale() const #ifdef LOVE_ANDROID return love::android::getScreenScale(); #else - return (double) curMode.pixelheight / (double) curMode.height; + return (double) pixelHeight / (double) windowHeight; #endif } diff --git a/jni/love/src/modules/window/sdl/Window.h b/jni/love/src/modules/window/sdl/Window.h index 6eaf2a75..7a720a83 100644 --- a/jni/love/src/modules/window/sdl/Window.h +++ b/jni/love/src/modules/window/sdl/Window.h @@ -131,16 +131,12 @@ private: std::string title; - struct _currentMode - { - int width = 800; - int height = 600; - int pixelwidth = 800; - int pixelheight = 600; - WindowSettings settings; - StrongRef icon; - - } curMode; + int windowWidth = 800; + int windowHeight = 600; + int pixelWidth = 800; + int pixelHeight = 600; + WindowSettings settings; + StrongRef icon; bool open; diff --git a/jni/love/src/scripts/boot.lua b/jni/love/src/scripts/boot.lua index fb931dd9..5430018d 100644 --- a/jni/love/src/scripts/boot.lua +++ b/jni/love/src/scripts/boot.lua @@ -386,13 +386,13 @@ function love.init() end -- If config file exists, load it and allow it to update config table. - if not love.conf and love.filesystem and love.filesystem.isFile("conf.lua") then - require("conf") + local confok, conferr + if (not love.conf) and love.filesystem and love.filesystem.isFile("conf.lua") then + confok, conferr = pcall(require, "conf") end -- Yes, conf.lua might not exist, but there are other ways of making -- love.conf appear, so we should check for it anyway. - local confok, conferr if love.conf then confok, conferr = pcall(love.conf, c) -- If love.conf errors, we'll trigger the error after loading modules so @@ -635,7 +635,7 @@ function love.errhand(msg) return elseif e == "keypressed" and a == "escape" then return - elseif e == "touchreleased" then + elseif e == "touchpressed" then local name = love.window.getTitle() if #name == 0 or name == "Untitled" then name = "Game" end local buttons = {"OK", "Cancel"} diff --git a/jni/love/src/scripts/boot.lua.h b/jni/love/src/scripts/boot.lua.h index bb6e6bd2..87a5075e 100644 --- a/jni/love/src/scripts/boot.lua.h +++ b/jni/love/src/scripts/boot.lua.h @@ -708,12 +708,16 @@ const unsigned char boot_lua[] = 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x2c, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x20, - 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, - 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, - 0x75, 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x22, 0x29, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f, 0x6e, + 0x66, 0x65, 0x72, 0x72, 0x0a, + 0x09, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, + 0x29, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x22, 0x63, 0x6f, 0x6e, 0x66, + 0x2e, 0x6c, 0x75, 0x61, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x20, + 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x2c, 0x20, 0x22, + 0x63, 0x6f, 0x6e, 0x66, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x59, 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x62, @@ -723,8 +727,6 @@ const unsigned char boot_lua[] = 0x61, 0x72, 0x2c, 0x20, 0x73, 0x6f, 0x20, 0x77, 0x65, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x77, 0x61, 0x79, 0x2e, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f, 0x6e, - 0x66, 0x65, 0x72, 0x72, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2c, @@ -1154,7 +1156,7 @@ const unsigned char boot_lua[] = 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x6f, - 0x75, 0x63, 0x68, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x75, 0x63, 0x68, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65, 0x74, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x28, 0x29, 0x0a, diff --git a/jni/love/src/scripts/nogame.lua b/jni/love/src/scripts/nogame.lua index dbca44c5..d92aa7e8 100644 --- a/jni/love/src/scripts/nogame.lua +++ b/jni/love/src/scripts/nogame.lua @@ -887,7 +887,7 @@ function love.nogame() function Mosaic:addGeneration() self.generation = self.generation + 1 if self.generation % 5 == 0 then - if love.math.random(0, 100) < 30 then + if love.math.random(0, 100) < 60 then self.generator = self.generators[love.math.random(2, #self.generators)] else self.generator = self.generators[1] @@ -975,6 +975,12 @@ function love.nogame() g_entities.toast:center() end + function love.keypressed(key) + if key == "escape" then + love.event.quit() + end + end + function love.keyreleased(key) if key == "f" then local is_fs = love.window.getFullscreen() diff --git a/jni/love/src/scripts/nogame.lua.h b/jni/love/src/scripts/nogame.lua.h index 91f27bd7..49cff317 100644 --- a/jni/love/src/scripts/nogame.lua.h +++ b/jni/love/src/scripts/nogame.lua.h @@ -3471,7 +3471,7 @@ const unsigned char nogame_lua[] = 0x09, 0x09, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x25, 0x20, 0x35, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x61, - 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x3c, 0x20, 0x33, 0x30, 0x20, + 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x30, 0x2c, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x3c, 0x20, 0x36, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, @@ -3649,6 +3649,14 @@ const unsigned char nogame_lua[] = 0x3a, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x6b, 0x65, 0x79, 0x29, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, + 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x71, 0x75, 0x69, 0x74, + 0x28, 0x29, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x6b, 0x65, 0x79, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x66, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,