Updated LÖVE source to changeset da332813bc05

This commit is contained in:
Martin Felis
2015-12-20 22:52:22 +01:00
parent eac5db7e10
commit 08d51fbf28
38 changed files with 851 additions and 463 deletions
+5 -1
View File
@@ -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)
+17 -17
View File
@@ -32,11 +32,11 @@ namespace event
#define instance() (Module::getInstance<Event>(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
+12 -6
View File
@@ -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<std::string> &getRequirePath() = 0;
@@ -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)
@@ -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 <string>
// 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
@@ -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<std::string> &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<std::string> &Filesystem::getRequirePath()
{
return requirePath;
@@ -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<std::string> &getRequirePath();
@@ -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 },
+67 -4
View File
@@ -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::DrawMode, Graphics::DRAW_MAX_ENUM> Graphics::drawModes(Graph
StringMap<Graphics::BlendMode, Graphics::BLEND_MAX_ENUM>::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::BlendMode, Graphics::BLEND_MAX_ENUM> Graphics::blendModes(Graphics::blendModeEntries, sizeof(Graphics::blendModeEntries));
StringMap<Graphics::BlendAlpha, Graphics::BLENDALPHA_MAX_ENUM>::Entry Graphics::blendAlphaEntries[] =
{
{ "alphamultiply", BLENDALPHA_MULTIPLY },
{ "premultiplied", BLENDALPHA_PREMULTIPLIED },
};
StringMap<Graphics::BlendAlpha, Graphics::BLENDALPHA_MAX_ENUM> Graphics::blendAlphaModes(Graphics::blendAlphaEntries, sizeof(Graphics::blendAlphaEntries));
StringMap<Graphics::LineStyle, Graphics::LINE_MAX_ENUM>::Entry Graphics::lineStyleEntries[] =
{
{ "smooth", LINE_SMOOTH },
@@ -179,6 +217,31 @@ StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM>::Entry Graphics::lin
StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM> Graphics::lineJoins(Graphics::lineJoinEntries, sizeof(Graphics::lineJoinEntries));
StringMap<Graphics::StencilAction, Graphics::STENCIL_MAX_ENUM>::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::StencilAction, Graphics::STENCIL_MAX_ENUM> Graphics::stencilActions(Graphics::stencilActionEntries, sizeof(Graphics::stencilActionEntries));
StringMap<Graphics::CompareMode, Graphics::COMPARE_MAX_ENUM>::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::CompareMode, Graphics::COMPARE_MAX_ENUM> Graphics::compareModes(Graphics::compareModeEntries, sizeof(Graphics::compareModeEntries));
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::supportEntries[] =
{
{ "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS },
+48
View File
@@ -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<BlendMode, BLEND_MAX_ENUM>::Entry blendModeEntries[];
static StringMap<BlendMode, BLEND_MAX_ENUM> blendModes;
static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM>::Entry blendAlphaEntries[];
static StringMap<BlendAlpha, BLENDALPHA_MAX_ENUM> blendAlphaModes;
static StringMap<LineStyle, LINE_MAX_ENUM>::Entry lineStyleEntries[];
static StringMap<LineStyle, LINE_MAX_ENUM> lineStyles;
static StringMap<LineJoin, LINE_JOIN_MAX_ENUM>::Entry lineJoinEntries[];
static StringMap<LineJoin, LINE_JOIN_MAX_ENUM> lineJoins;
static StringMap<StencilAction, STENCIL_MAX_ENUM>::Entry stencilActionEntries[];
static StringMap<StencilAction, STENCIL_MAX_ENUM> stencilActions;
static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[];
static StringMap<CompareMode, COMPARE_MAX_ENUM> compareModes;
static StringMap<Support, SUPPORT_MAX_ENUM>::Entry supportEntries[];
static StringMap<Support, SUPPORT_MAX_ENUM> support;
@@ -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;
}
+16 -4
View File
@@ -617,7 +617,7 @@ std::vector<Font::DrawCommand> Font::generateVerticesFormatted(const ColoredCode
return drawcommands;
}
void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
void Font::drawVertices(const std::vector<DrawCommand> &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<DrawCommand> &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<DrawCommand> &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<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices)
@@ -665,7 +677,7 @@ void Font::printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR);
drawVertices(drawcommands);
drawVertices(drawcommands, false);
}
void Font::print(const std::vector<ColoredString> &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
+1 -1
View File
@@ -109,7 +109,7 @@ public:
std::vector<DrawCommand> generateVerticesFormatted(const ColoredCodepoints &text, float wrap, AlignMode align, std::vector<GlyphVertex> &vertices, TextInfo *info = nullptr);
void drawVertices(const std::vector<DrawCommand> &drawcommands);
void drawVertices(const std::vector<DrawCommand> &drawcommands, bool bufferedvertices);
static void getCodepointsFromString(const std::string &str, Codepoints &codepoints);
static void getCodepointsFromString(const std::vector<ColoredString> &strs, ColoredCodepoints &codepoints);
@@ -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 <typename T>
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
@@ -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
+110 -40
View File
@@ -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;
}
@@ -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> font;
StrongRef<Shader> shader;
@@ -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
@@ -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)
+21 -21
View File
@@ -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]);
}
}
}
@@ -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))
@@ -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
@@ -26,6 +26,7 @@
// C++
#include <typeinfo>
#include <algorithm>
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<Data>(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++)
@@ -22,6 +22,7 @@
#define LOVE_GRAPHICS_OPENGL_WRAP_MESH_H
// LOVE
#include "common/config.h"
#include "common/runtime.h"
#include "Mesh.h"
@@ -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()
+2 -49
View File
@@ -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;
}
/**
+7 -44
View File
@@ -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);
+33 -6
View File
@@ -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]
@@ -23,6 +23,11 @@
#include <cmath>
#include <algorithm>
// 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<RandomGenerator>(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
@@ -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);
@@ -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"--"
@@ -30,7 +30,7 @@
#include "Decoder.h"
// libmodplug
#ifdef LOVE_ANDROID
#if defined(LOVE_ANDROID) || defined(LOVE_IOS)
#include <modplug.h>
#else
#include <libmodplug/modplug.h>
+127 -136
View File
@@ -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<graphics::Graphics>(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<graphics::Graphics>(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<graphics::Graphics>(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
}
+6 -10
View File
@@ -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<love::image::ImageData> icon;
} curMode;
int windowWidth = 800;
int windowHeight = 600;
int pixelWidth = 800;
int pixelHeight = 600;
WindowSettings settings;
StrongRef<love::image::ImageData> icon;
bool open;
+4 -4
View File
@@ -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"}
+11 -9
View File
@@ -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,
+7 -1
View File
@@ -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()
+9 -1
View File
@@ -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,