mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Merge branch '12.0-development' into metal
This commit is contained in:
@@ -31,8 +31,19 @@ ByteData *luax_checkbytedata(lua_State *L, int idx)
|
||||
return luax_checktype<ByteData>(L, idx);
|
||||
}
|
||||
|
||||
int w_ByteData_clone(lua_State *L)
|
||||
{
|
||||
ByteData *t = luax_checkbytedata(L, 1);
|
||||
ByteData *c = nullptr;
|
||||
luax_catchexcept(L, [&](){ c = t->clone(); });
|
||||
luax_pushtype(L, c);
|
||||
c->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg w_ByteData_functions[] =
|
||||
{
|
||||
{ "clone", w_ByteData_clone },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -26,13 +26,24 @@ namespace love
|
||||
namespace data
|
||||
{
|
||||
|
||||
DataView *luax_checkdataView(lua_State *L, int idx)
|
||||
DataView *luax_checkdataview(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<DataView>(L, idx);
|
||||
}
|
||||
|
||||
int w_DataView_clone(lua_State *L)
|
||||
{
|
||||
DataView *t = luax_checkdataview(L, 1);
|
||||
DataView *c = nullptr;
|
||||
luax_catchexcept(L, [&](){ c = t->clone(); });
|
||||
luax_pushtype(L, c);
|
||||
c->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg w_DataView_functions[] =
|
||||
{
|
||||
{ "clone", w_DataView_clone },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ extern "C" int luaopen_love_event(lua_State *L)
|
||||
|
||||
int ret = luax_register_module(L, w);
|
||||
|
||||
if (luaL_loadbuffer(L, (const char *)event_lua, sizeof(event_lua), "wrap_Event.lua") == 0)
|
||||
if (luaL_loadbuffer(L, (const char *)event_lua, sizeof(event_lua), "=[love \"wrap_Event.lua\"]") == 0)
|
||||
lua_call(L, 0, 0);
|
||||
else
|
||||
lua_error(L);
|
||||
|
||||
@@ -122,7 +122,7 @@ static bool getContainingDirectory(const std::string &path, std::string &newpath
|
||||
newpath = path.substr(0, index);
|
||||
|
||||
// Bail if the root has been stripped out.
|
||||
return newpath.find("/\\") != std::string::npos;
|
||||
return newpath.find_first_of("/\\") != std::string::npos;
|
||||
}
|
||||
|
||||
static bool createDirectoryRaw(const std::string &path)
|
||||
|
||||
@@ -240,15 +240,13 @@ bool Filesystem::setSource(const char *source)
|
||||
|
||||
PHYSFS_Io *gameLoveIO;
|
||||
bool hasFusedGame = love::android::checkFusedGame((void **) &gameLoveIO);
|
||||
bool isAAssetMounted = false;
|
||||
|
||||
if (hasFusedGame)
|
||||
{
|
||||
if (gameLoveIO)
|
||||
{
|
||||
// Actually we should just be able to mount gameLoveIO, but that's experimental.
|
||||
gameLoveIO->destroy(gameLoveIO);
|
||||
goto oldschool;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!love::android::initializeVirtualArchive())
|
||||
@@ -256,11 +254,15 @@ bool Filesystem::setSource(const char *source)
|
||||
SDL_Log("Unable to mount AAsset: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// See love::android::initializeVirtualArchive()
|
||||
new_search_path = "ASET.AASSET";
|
||||
isAAssetMounted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (!isAAssetMounted)
|
||||
{
|
||||
oldschool:
|
||||
new_search_path = love::android::getSelectedGameFile();
|
||||
|
||||
// try mounting first, if that fails, load to memory and mount
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
|
||||
#include "physfs/Filesystem.h"
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
#include "common/android.h"
|
||||
#endif
|
||||
|
||||
// SDL
|
||||
#include <SDL_loadso.h>
|
||||
|
||||
@@ -380,11 +384,22 @@ int w_newFileData(lua_State *L)
|
||||
}
|
||||
|
||||
size_t length = 0;
|
||||
const char *str = luaL_checklstring(L, 1, &length);
|
||||
const void *ptr = nullptr;
|
||||
if (luax_istype(L, 1, Data::type))
|
||||
{
|
||||
Data *data = data::luax_checkdata(L, 1);
|
||||
ptr = data->getData();
|
||||
length = data->getSize();
|
||||
}
|
||||
else if (lua_isstring(L, 1))
|
||||
ptr = luaL_checklstring(L, 1, &length);
|
||||
else
|
||||
return luaL_argerror(L, 1, "string or Data expected");
|
||||
|
||||
const char *filename = luaL_checkstring(L, 2);
|
||||
|
||||
FileData *t = nullptr;
|
||||
luax_catchexcept(L, [&](){ t = instance()->newFileData(str, length, filename); });
|
||||
luax_catchexcept(L, [&](){ t = instance()->newFileData(ptr, length, filename); });
|
||||
|
||||
luax_pushtype(L, t);
|
||||
t->release();
|
||||
@@ -849,6 +864,23 @@ int extloader(lua_State *L)
|
||||
void *handle = nullptr;
|
||||
auto *inst = instance();
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
// Specifically Android, look the library path based on getCRequirePath first
|
||||
std::string androidPath(love::android::getCRequirePath());
|
||||
|
||||
if (!androidPath.empty())
|
||||
{
|
||||
// Replace ? with just the dotted filename (not tokenized_name)
|
||||
replaceAll(androidPath, "?", filename);
|
||||
|
||||
// Load directly, don't check for existence.
|
||||
handle = SDL_LoadObject(androidPath.c_str());
|
||||
}
|
||||
|
||||
if (!handle)
|
||||
{
|
||||
#endif // LOVE_ANDROID
|
||||
|
||||
for (const std::string &el : inst->getCRequirePath())
|
||||
{
|
||||
for (const char *ext : library_extensions)
|
||||
@@ -878,6 +910,10 @@ int extloader(lua_State *L)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
} // if (!handle)
|
||||
#endif
|
||||
|
||||
if (!handle)
|
||||
{
|
||||
lua_pushfstring(L, "\n\tno file '%s' in LOVE paths.", tokenized_name.c_str());
|
||||
|
||||
@@ -147,11 +147,30 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
||||
|
||||
// GLSL's std430 packing rules. We also assume all matrices are
|
||||
// column-major.
|
||||
if (info.isMatrix)
|
||||
alignment = info.matrixRows * info.componentSize;
|
||||
else
|
||||
alignment = info.components * info.componentSize;
|
||||
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf
|
||||
|
||||
// "If the member is a column-major matrix with C columns and R rows,
|
||||
// the matrix is stored identically to an array of C column vectors
|
||||
// with R components each".
|
||||
// "If the member is a three-component vector with components
|
||||
// consuming N basic machine units, the base alignment is 4N."
|
||||
int c = info.isMatrix ? info.matrixRows : info.components;
|
||||
alignment = c == 3 ? 4 * info.componentSize : c * info.componentSize;
|
||||
|
||||
// std430 will effectively turn a floatmat3x3 into a floatmat4x3
|
||||
// because of its vec3 padding rules. For now we'd rather not
|
||||
// support those formats at all, because it's not easy for users to
|
||||
// deal with.
|
||||
if (alignment != c * info.componentSize && (decl.arrayLength > 0 || info.isMatrix))
|
||||
{
|
||||
const char *fstr = "unknown";
|
||||
getConstant(decl.format, fstr);
|
||||
throw love::Exception("Data format %s%s is not currently supported in shader storage buffers.", fstr, decl.arrayLength > 0 ? " array" : "");
|
||||
}
|
||||
|
||||
// "If the member is a structure, the base alignment of the structure
|
||||
// is N, where N is the largest base alignment value of any of its
|
||||
// members"
|
||||
structurealignment = std::max(structurealignment, alignment);
|
||||
|
||||
memberoffset = alignUp(memberoffset, alignment);
|
||||
|
||||
@@ -338,7 +338,7 @@ float Font::getKerning(uint32 leftglyph, uint32 rightglyph)
|
||||
if (it != kerning.end())
|
||||
return it->second;
|
||||
|
||||
float k = rasterizers[0]->getKerning(leftglyph, rightglyph) / dpiScale + 0.5f;
|
||||
float k = floorf(rasterizers[0]->getKerning(leftglyph, rightglyph) / dpiScale + 0.5f);
|
||||
|
||||
for (const auto &r : rasterizers)
|
||||
{
|
||||
@@ -901,14 +901,11 @@ void Font::getWrap(const ColoredCodepoints &codepoints, float wraplimit, std::ve
|
||||
}
|
||||
|
||||
// Push the last line.
|
||||
if (!wline.cps.empty())
|
||||
{
|
||||
lines.push_back(wline);
|
||||
lines.push_back(wline);
|
||||
|
||||
// Ignore the width of any trailing spaces, for individual lines.
|
||||
if (linewidths)
|
||||
linewidths->push_back(width - widthoftrailingspace);
|
||||
}
|
||||
// Ignore the width of any trailing spaces, for individual lines.
|
||||
if (linewidths)
|
||||
linewidths->push_back(width - widthoftrailingspace);
|
||||
}
|
||||
|
||||
void Font::getWrap(const std::vector<ColoredString> &text, float wraplimit, std::vector<std::string> &lines, std::vector<int> *linewidths)
|
||||
|
||||
@@ -1526,7 +1526,7 @@ void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h)
|
||||
|
||||
void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry, int points)
|
||||
{
|
||||
if (rx == 0 || ry == 0)
|
||||
if (rx <= 0 || ry <= 0)
|
||||
{
|
||||
rectangle(mode, x, y, w, h);
|
||||
return;
|
||||
@@ -1585,7 +1585,8 @@ void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, floa
|
||||
|
||||
void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, float rx, float ry)
|
||||
{
|
||||
rectangle(mode, x, y, w, h, rx, ry, calculateEllipsePoints(rx, ry));
|
||||
int points = calculateEllipsePoints(std::min(rx, std::abs(w/2)), std::min(ry, std::abs(h/2)));
|
||||
rectangle(mode, x, y, w, h, rx, ry, points);
|
||||
}
|
||||
|
||||
void Graphics::circle(DrawMode mode, float x, float y, float radius, int points)
|
||||
|
||||
@@ -177,7 +177,7 @@ void ParticleSystem::resetOffset()
|
||||
else
|
||||
{
|
||||
Quad::Viewport v = quads[0]->getViewport();
|
||||
offset = love::Vector2(v.x*0.5f, v.y*0.5f);
|
||||
offset = love::Vector2(v.w*0.5f, v.h*0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -896,14 +896,14 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
|
||||
const glslang::TTypeList *structure = type->getStruct();
|
||||
if (structure == nullptr || structure->size() != 1)
|
||||
{
|
||||
err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of structs.";
|
||||
err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of base types or structs.";
|
||||
return false;
|
||||
}
|
||||
|
||||
const glslang::TType* structtype = (*structure)[0].type;
|
||||
if (structtype == nullptr || structtype->getBasicType() != glslang::EbtStruct || !structtype->isUnsizedArray())
|
||||
const glslang::TType* elementtype = (*structure)[0].type;
|
||||
if (elementtype == nullptr || !elementtype->isUnsizedArray())
|
||||
{
|
||||
err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of structs.";
|
||||
err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must contain a single unsized array of base types or structs.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,12 @@ void Shader::mapActiveUniforms()
|
||||
u.storageTextureFormat = reflectionit->second.format;
|
||||
u.access = reflectionit->second.access;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No reflection info - maybe glslang was better at detecting
|
||||
// dead code than the driver's compiler?
|
||||
continue;
|
||||
}
|
||||
|
||||
StorageTextureBinding binding = {};
|
||||
binding.gltexture = gl.getDefaultTexture(u.textureType, u.dataBaseType);
|
||||
@@ -352,6 +358,7 @@ void Shader::mapActiveUniforms()
|
||||
glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numstoragebuffers);
|
||||
|
||||
char namebuffer[2048] = { '\0' };
|
||||
int nextstoragebufferbinding = 0;
|
||||
|
||||
for (int sindex = 0; sindex < numstoragebuffers; sindex++)
|
||||
{
|
||||
@@ -372,6 +379,12 @@ void Shader::mapActiveUniforms()
|
||||
u.bufferMemberCount = reflectionit->second.memberCount;
|
||||
u.access = reflectionit->second.access;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No reflection info - maybe glslang was better at detecting
|
||||
// dead code than the driver's compiler?
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure previously set uniform data is preserved, and shader-
|
||||
// initialized values are retrieved.
|
||||
@@ -393,8 +406,11 @@ void Shader::mapActiveUniforms()
|
||||
memset(u.buffers, 0, sizeof(Buffer*)* u.count);
|
||||
}
|
||||
|
||||
GLenum props[] = { GL_BUFFER_BINDING };
|
||||
glGetProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, sindex, 1, props, 1, nullptr, u.ints);
|
||||
// Unlike local uniforms and attributes, OpenGL doesn't auto-assign storage
|
||||
// block bindings if they're unspecified in the shader. So we overwrite them
|
||||
// regardless, here.
|
||||
u.ints[0] = nextstoragebufferbinding++;
|
||||
glShaderStorageBlockBinding(program, sindex, u.ints[0]);
|
||||
|
||||
BufferBinding binding;
|
||||
binding.bindingindex = u.ints[0];
|
||||
@@ -1074,6 +1090,9 @@ Shader::MatrixSize Shader::getMatrixSize(GLenum type) const
|
||||
m.columns = 4;
|
||||
m.rows = 3;
|
||||
break;
|
||||
default:
|
||||
m.columns = m.rows = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return m;
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
struct StorageTextureBinding
|
||||
{
|
||||
Texture *texture = nullptr;
|
||||
love::graphics::Texture *texture = nullptr;
|
||||
GLuint gltexture = 0;
|
||||
TextureType type = TEXTURE_2D;
|
||||
GLenum access = GL_READ_ONLY;
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "Buffer.h"
|
||||
#include "common/Data.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
|
||||
@@ -3657,7 +3657,7 @@ extern "C" int luaopen_love_graphics(lua_State *L)
|
||||
|
||||
int n = luax_register_module(L, w);
|
||||
|
||||
if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "wrap_Graphics.lua") == 0)
|
||||
if (luaL_loadbuffer(L, (const char *)graphics_lua, sizeof(graphics_lua), "=[love \"wrap_Graphics.lua\"]") == 0)
|
||||
lua_call(L, 0, 0);
|
||||
else
|
||||
lua_error(L);
|
||||
|
||||
@@ -447,18 +447,12 @@ int w_Shader_send(lua_State *L)
|
||||
|
||||
const Shader::UniformInfo *info = shader->getUniformInfo(name);
|
||||
if (info == nullptr)
|
||||
{
|
||||
luax_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
return luaL_error(L, "Shader uniform '%s' does not exist.\nA common error is to define but not use the variable.", name);
|
||||
|
||||
if (luax_istype(L, 3, Data::type) || (info->baseType == Shader::UNIFORM_MATRIX && luax_istype(L, 4, Data::type)))
|
||||
w_Shader_sendData(L, 3, shader, info, false);
|
||||
return w_Shader_sendData(L, 3, shader, info, false);
|
||||
else
|
||||
w_Shader_sendLuaValues(L, 3, shader, info, name);
|
||||
|
||||
luax_pushboolean(L, true);
|
||||
return 1;
|
||||
return w_Shader_sendLuaValues(L, 3, shader, info, name);
|
||||
}
|
||||
|
||||
int w_Shader_sendColors(lua_State *L)
|
||||
|
||||
@@ -168,7 +168,7 @@ int luaopen_video(lua_State *L)
|
||||
{
|
||||
int ret = luax_register_type(L, &Video::type, functions, nullptr);
|
||||
|
||||
luaL_loadbuffer(L, video_lua, sizeof(video_lua), "Video.lua");
|
||||
luaL_loadbuffer(L, video_lua, sizeof(video_lua), "=[love \"Video.lua\"]");
|
||||
luax_gettypemetatable(L, Video::type);
|
||||
lua_call(L, 1, 0);
|
||||
|
||||
|
||||
@@ -440,6 +440,11 @@ bool Joystick::checkCreateHaptic()
|
||||
|
||||
bool Joystick::isVibrationSupported()
|
||||
{
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
||||
if (isConnected() && SDL_JoystickHasRumble(joyhandle) == SDL_TRUE)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (!checkCreateHaptic())
|
||||
return false;
|
||||
|
||||
@@ -490,8 +495,12 @@ bool Joystick::setVibration(float left, float right, float duration)
|
||||
if (left == 0.0f && right == 0.0f)
|
||||
return setVibration();
|
||||
|
||||
if (!checkCreateHaptic())
|
||||
if (!isConnected())
|
||||
{
|
||||
vibration.left = vibration.right = 0.0f;
|
||||
vibration.endtime = SDL_HAPTIC_INFINITY;
|
||||
return false;
|
||||
}
|
||||
|
||||
Uint32 length = SDL_HAPTIC_INFINITY;
|
||||
if (duration >= 0.0f)
|
||||
@@ -501,10 +510,19 @@ bool Joystick::setVibration(float left, float right, float duration)
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
if (SDL_JoystickRumble(joyhandle, (Uint16)(left * LOVE_UINT16_MAX), (Uint16)(right * LOVE_UINT16_MAX), length) == 0)
|
||||
success = true;
|
||||
#endif
|
||||
|
||||
if (!success && !checkCreateHaptic())
|
||||
return false;
|
||||
|
||||
unsigned int features = SDL_HapticQuery(haptic);
|
||||
int axes = SDL_HapticNumAxes(haptic);
|
||||
|
||||
if ((features & SDL_HAPTIC_LEFTRIGHT) != 0)
|
||||
if (!success && (features & SDL_HAPTIC_LEFTRIGHT) != 0)
|
||||
{
|
||||
memset(&vibration.effect, 0, sizeof(SDL_HapticEffect));
|
||||
vibration.effect.type = SDL_HAPTIC_LEFTRIGHT;
|
||||
@@ -576,9 +594,14 @@ bool Joystick::setVibration(float left, float right, float duration)
|
||||
|
||||
bool Joystick::setVibration()
|
||||
{
|
||||
bool success = true;
|
||||
bool success = false;
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1)
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
if (!success)
|
||||
success = isConnected() && SDL_JoystickRumble(joyhandle, 0, 0, 0) == 0;
|
||||
#endif
|
||||
|
||||
if (!success && SDL_WasInit(SDL_INIT_HAPTIC) && haptic && SDL_HapticIndex(haptic) != -1)
|
||||
success = (SDL_HapticStopEffect(haptic, vibration.id) == 0);
|
||||
|
||||
if (success)
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
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-2021 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 love = require("love")
|
||||
|
||||
-- Used for setup:
|
||||
love.path = {}
|
||||
love.arg = {}
|
||||
|
||||
-- Replace any \ with /.
|
||||
function love.path.normalslashes(p)
|
||||
return p:gsub("\\", "/")
|
||||
end
|
||||
|
||||
-- Makes sure there is a slash at the end
|
||||
-- of a path.
|
||||
function love.path.endslash(p)
|
||||
if p:sub(-1) ~= "/" then
|
||||
return p .. "/"
|
||||
else
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
-- Checks whether a path is absolute or not.
|
||||
function love.path.abs(p)
|
||||
|
||||
local tmp = love.path.normalslashes(p)
|
||||
|
||||
-- Path is absolute if it starts with a "/".
|
||||
if tmp:find("/") == 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Path is absolute if it starts with a
|
||||
-- letter followed by a colon.
|
||||
if tmp:find("%a:") == 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Relative.
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
-- Converts any path into a full path.
|
||||
function love.path.getFull(p)
|
||||
|
||||
if love.path.abs(p) then
|
||||
return love.path.normalslashes(p)
|
||||
end
|
||||
|
||||
local cwd = love.filesystem.getWorkingDirectory()
|
||||
cwd = love.path.normalslashes(cwd)
|
||||
cwd = love.path.endslash(cwd)
|
||||
|
||||
-- Construct a full path.
|
||||
local full = cwd .. love.path.normalslashes(p)
|
||||
|
||||
-- Remove trailing /., if applicable
|
||||
return full:match("(.-)/%.$") or full
|
||||
end
|
||||
|
||||
-- Returns the leaf of a full path.
|
||||
function love.path.leaf(p)
|
||||
p = love.path.normalslashes(p)
|
||||
|
||||
local a = 1
|
||||
local last = p
|
||||
|
||||
while a do
|
||||
a = p:find("/", a+1)
|
||||
|
||||
if a then
|
||||
last = p:sub(a+1)
|
||||
end
|
||||
end
|
||||
|
||||
return last
|
||||
end
|
||||
|
||||
-- Finds the key in the table with the lowest integral index. The lowest
|
||||
-- will typically the executable, for instance "lua5.1.exe".
|
||||
function love.arg.getLow(a)
|
||||
local m = math.huge
|
||||
for k,v in pairs(a) do
|
||||
if k < m then
|
||||
m = k
|
||||
end
|
||||
end
|
||||
return a[m], m
|
||||
end
|
||||
|
||||
love.arg.options = {
|
||||
console = { a = 0 },
|
||||
fused = {a = 0 },
|
||||
game = { a = 1 }
|
||||
}
|
||||
|
||||
love.arg.optionIndices = {}
|
||||
|
||||
function love.arg.parseOption(m, i)
|
||||
m.set = true
|
||||
|
||||
if m.a > 0 then
|
||||
m.arg = {}
|
||||
for j=i,i+m.a-1 do
|
||||
love.arg.optionIndices[j] = true
|
||||
table.insert(m.arg, arg[j])
|
||||
end
|
||||
end
|
||||
|
||||
return m.a
|
||||
end
|
||||
|
||||
function love.arg.parseOptions(arg)
|
||||
|
||||
local game
|
||||
local argc = #arg
|
||||
|
||||
local i = 1
|
||||
while i <= argc do
|
||||
-- Look for options.
|
||||
local m = arg[i]:match("^%-%-(.*)")
|
||||
|
||||
if m and m ~= "" and love.arg.options[m] and not love.arg.options[m].set then
|
||||
love.arg.optionIndices[i] = true
|
||||
i = i + love.arg.parseOption(love.arg.options[m], i+1)
|
||||
elseif m == "" then -- handle '--' as an option
|
||||
love.arg.optionIndices[i] = true
|
||||
if not game then -- handle '--' followed by game name
|
||||
game = i + 1
|
||||
end
|
||||
break
|
||||
elseif not game then
|
||||
game = i
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if not love.arg.options.game.set then
|
||||
love.arg.parseOption(love.arg.options.game, game or 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns the arguments that are passed to your game via love.load()
|
||||
-- arguments that were parsed as options are skipped.
|
||||
function love.arg.parseGameArguments(a)
|
||||
local out = {}
|
||||
|
||||
local _, lowindex = love.arg.getLow(a)
|
||||
|
||||
local o = lowindex
|
||||
for i=lowindex, #a do
|
||||
if not love.arg.optionIndices[i] then
|
||||
out[o] = a[i]
|
||||
o = o + 1
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
@@ -0,0 +1,388 @@
|
||||
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-2021 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.
|
||||
--]]
|
||||
|
||||
-- Make sure love exists.
|
||||
local love = require("love")
|
||||
|
||||
-- Essential code boot/init.
|
||||
require("love.arg")
|
||||
require("love.callbacks")
|
||||
|
||||
local function uridecode(s)
|
||||
return s:gsub("%%%x%x", function(str)
|
||||
return string.char(tonumber(str:sub(2), 16))
|
||||
end)
|
||||
end
|
||||
|
||||
local no_game_code = false
|
||||
local invalid_game_path = nil
|
||||
|
||||
-- This can't be overridden.
|
||||
function love.boot()
|
||||
|
||||
-- This is absolutely needed.
|
||||
require("love.filesystem")
|
||||
|
||||
love.rawGameArguments = arg
|
||||
|
||||
local arg0 = love.arg.getLow(love.rawGameArguments)
|
||||
love.filesystem.init(arg0)
|
||||
|
||||
local exepath = love.filesystem.getExecutablePath()
|
||||
if #exepath == 0 then
|
||||
-- This shouldn't happen, but just in case we'll fall back to arg0.
|
||||
exepath = arg0
|
||||
end
|
||||
|
||||
no_game_code = false
|
||||
invalid_game_path = nil
|
||||
|
||||
-- Is this one of those fancy "fused" games?
|
||||
local can_has_game = pcall(love.filesystem.setSource, exepath)
|
||||
|
||||
-- It's a fused game, don't parse --game argument
|
||||
if can_has_game then
|
||||
love.arg.options.game.set = true
|
||||
end
|
||||
|
||||
-- Parse options now that we know which options we're looking for.
|
||||
love.arg.parseOptions(love.rawGameArguments)
|
||||
|
||||
-- parseGameArguments can only be called after parseOptions.
|
||||
love.parsedGameArguments = love.arg.parseGameArguments(love.rawGameArguments)
|
||||
|
||||
local o = love.arg.options
|
||||
|
||||
local is_fused_game = can_has_game or love.arg.options.fused.set
|
||||
|
||||
love.filesystem.setFused(is_fused_game)
|
||||
|
||||
love.setDeprecationOutput(not love.filesystem.isFused())
|
||||
|
||||
local identity = ""
|
||||
if not can_has_game and o.game.set and o.game.arg[1] then
|
||||
local nouri = o.game.arg[1]
|
||||
|
||||
if nouri:sub(1, 7) == "file://" then
|
||||
nouri = uridecode(nouri:sub(8))
|
||||
end
|
||||
|
||||
local full_source = love.path.getFull(nouri)
|
||||
can_has_game = pcall(love.filesystem.setSource, full_source)
|
||||
|
||||
if not can_has_game then
|
||||
invalid_game_path = full_source
|
||||
end
|
||||
|
||||
-- Use the name of the source .love as the identity for now.
|
||||
identity = love.path.leaf(full_source)
|
||||
else
|
||||
-- Use the name of the exe as the identity for now.
|
||||
identity = love.path.leaf(exepath)
|
||||
end
|
||||
|
||||
-- Try to use the archive containing main.lua as the identity name. It
|
||||
-- might not be available, in which case the fallbacks above are used.
|
||||
local realdir = love.filesystem.getRealDirectory("main.lua")
|
||||
if realdir then
|
||||
identity = love.path.leaf(realdir)
|
||||
end
|
||||
|
||||
identity = identity:gsub("^([%.]+)", "") -- strip leading "."'s
|
||||
identity = identity:gsub("%.([^%.]+)$", "") -- strip extension
|
||||
identity = identity:gsub("%.", "_") -- replace remaining "."'s with "_"
|
||||
identity = #identity > 0 and identity or "lovegame"
|
||||
|
||||
-- When conf.lua is initially loaded, the main source should be checked
|
||||
-- before the save directory (the identity should be appended.)
|
||||
pcall(love.filesystem.setIdentity, identity, true)
|
||||
|
||||
if can_has_game and not (love.filesystem.getInfo("main.lua") or love.filesystem.getInfo("conf.lua")) then
|
||||
no_game_code = true
|
||||
end
|
||||
|
||||
if not can_has_game then
|
||||
local nogame = require("love.nogame")
|
||||
nogame()
|
||||
end
|
||||
end
|
||||
|
||||
function love.init()
|
||||
|
||||
-- Create default configuration settings.
|
||||
-- NOTE: Adding a new module to the modules list
|
||||
-- will NOT make it load, see below.
|
||||
local c = {
|
||||
title = "Untitled",
|
||||
version = love._version,
|
||||
window = {
|
||||
width = 800,
|
||||
height = 600,
|
||||
x = nil,
|
||||
y = nil,
|
||||
minwidth = 1,
|
||||
minheight = 1,
|
||||
fullscreen = false,
|
||||
fullscreentype = "desktop",
|
||||
display = 1,
|
||||
vsync = 1,
|
||||
msaa = 0,
|
||||
borderless = false,
|
||||
resizable = false,
|
||||
centered = true,
|
||||
usedpiscale = true,
|
||||
},
|
||||
modules = {
|
||||
data = true,
|
||||
event = true,
|
||||
keyboard = true,
|
||||
mouse = true,
|
||||
timer = true,
|
||||
joystick = true,
|
||||
touch = true,
|
||||
image = true,
|
||||
graphics = true,
|
||||
audio = true,
|
||||
math = true,
|
||||
physics = true,
|
||||
sound = true,
|
||||
system = true,
|
||||
font = true,
|
||||
thread = true,
|
||||
window = true,
|
||||
video = true,
|
||||
},
|
||||
audio = {
|
||||
mixwithsystem = true, -- Only relevant for Android / iOS.
|
||||
mic = false, -- Only relevant for Android.
|
||||
},
|
||||
console = false, -- Only relevant for windows.
|
||||
identity = false,
|
||||
appendidentity = false,
|
||||
externalstorage = false, -- Only relevant for Android.
|
||||
accelerometerjoystick = true, -- Only relevant for Android / iOS.
|
||||
gammacorrect = false,
|
||||
highdpi = false,
|
||||
}
|
||||
|
||||
-- Console hack, part 1.
|
||||
local openedconsole = false
|
||||
if love.arg.options.console.set and love._openConsole then
|
||||
love._openConsole()
|
||||
openedconsole = true
|
||||
end
|
||||
|
||||
-- If config file exists, load it and allow it to update config table.
|
||||
local confok, conferr
|
||||
if (not love.conf) and love.filesystem and love.filesystem.getInfo("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.
|
||||
if love.conf then
|
||||
confok, conferr = pcall(love.conf, c)
|
||||
-- If love.conf errors, we'll trigger the error after loading modules so
|
||||
-- the error message can be displayed in the window.
|
||||
end
|
||||
|
||||
-- Console hack, part 2.
|
||||
if c.console and love._openConsole and not openedconsole then
|
||||
love._openConsole()
|
||||
end
|
||||
|
||||
-- Hack for disabling accelerometer-as-joystick on Android / iOS.
|
||||
if love._setAccelerometerAsJoystick then
|
||||
love._setAccelerometerAsJoystick(c.accelerometerjoystick)
|
||||
end
|
||||
|
||||
if love._setGammaCorrect then
|
||||
love._setGammaCorrect(c.gammacorrect)
|
||||
end
|
||||
|
||||
if love._setHighDPIAllowed then
|
||||
love._setHighDPIAllowed(c.highdpi)
|
||||
end
|
||||
|
||||
if love._setAudioMixWithSystem then
|
||||
if c.audio and c.audio.mixwithsystem ~= nil then
|
||||
love._setAudioMixWithSystem(c.audio.mixwithsystem)
|
||||
end
|
||||
end
|
||||
|
||||
if love._requestRecordingPermission then
|
||||
love._requestRecordingPermission(c.audio and c.audio.mic)
|
||||
end
|
||||
|
||||
-- Gets desired modules.
|
||||
for k,v in ipairs{
|
||||
"data",
|
||||
"thread",
|
||||
"timer",
|
||||
"event",
|
||||
"keyboard",
|
||||
"joystick",
|
||||
"mouse",
|
||||
"touch",
|
||||
"sound",
|
||||
"system",
|
||||
"audio",
|
||||
"image",
|
||||
"video",
|
||||
"font",
|
||||
"window",
|
||||
"graphics",
|
||||
"math",
|
||||
"physics",
|
||||
} do
|
||||
if c.modules[v] then
|
||||
require("love." .. v)
|
||||
end
|
||||
end
|
||||
|
||||
if love.event then
|
||||
love.createhandlers()
|
||||
end
|
||||
|
||||
-- Check the version
|
||||
c.version = tostring(c.version)
|
||||
if not love.isVersionCompatible(c.version) then
|
||||
local major, minor, revision = c.version:match("^(%d+)%.(%d+)%.(%d+)$")
|
||||
if (not major or not minor or not revision) or (major ~= love._version_major and minor ~= love._version_minor) then
|
||||
local msg = ("This game indicates it was made for version '%s' of LOVE.\n"..
|
||||
"It may not be compatible with the running version (%s)."):format(c.version, love._version)
|
||||
|
||||
print(msg)
|
||||
|
||||
if love.window then
|
||||
love.window.showMessageBox("Compatibility Warning", msg, "warning")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not confok and conferr then
|
||||
error(conferr)
|
||||
end
|
||||
|
||||
-- Setup window here.
|
||||
if c.window and c.modules.window then
|
||||
love.window.setTitle(c.window.title or c.title)
|
||||
assert(love.window.setMode(c.window.width, c.window.height,
|
||||
{
|
||||
fullscreen = c.window.fullscreen,
|
||||
fullscreentype = c.window.fullscreentype,
|
||||
vsync = c.window.vsync,
|
||||
msaa = c.window.msaa,
|
||||
stencil = c.window.stencil,
|
||||
depth = c.window.depth,
|
||||
resizable = c.window.resizable,
|
||||
minwidth = c.window.minwidth,
|
||||
minheight = c.window.minheight,
|
||||
borderless = c.window.borderless,
|
||||
centered = c.window.centered,
|
||||
display = c.window.display,
|
||||
highdpi = c.window.highdpi, -- deprecated
|
||||
usedpiscale = c.window.usedpiscale,
|
||||
x = c.window.x,
|
||||
y = c.window.y,
|
||||
}), "Could not set window mode")
|
||||
if c.window.icon then
|
||||
assert(love.image, "If an icon is set in love.conf, love.image must be loaded!")
|
||||
love.window.setIcon(love.image.newImageData(c.window.icon))
|
||||
end
|
||||
end
|
||||
|
||||
-- Our first timestep, because window creation can take some time
|
||||
if love.timer then
|
||||
love.timer.step()
|
||||
end
|
||||
|
||||
if love.filesystem then
|
||||
love.filesystem._setAndroidSaveExternal(c.externalstorage)
|
||||
love.filesystem.setIdentity(c.identity or love.filesystem.getIdentity(), c.appendidentity)
|
||||
if love.filesystem.getInfo("main.lua") then
|
||||
require("main")
|
||||
end
|
||||
end
|
||||
|
||||
if no_game_code then
|
||||
error("No code to run\nYour game might be packaged incorrectly.\nMake sure main.lua is at the top level of the zip.")
|
||||
elseif invalid_game_path then
|
||||
error("Cannot load game at path '" .. invalid_game_path .. "'.\nMake sure a folder exists at the specified path.")
|
||||
end
|
||||
end
|
||||
|
||||
local print, debug, tostring = print, debug, tostring
|
||||
|
||||
local function error_printer(msg, layer)
|
||||
print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", "")))
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
-- The root of all calls.
|
||||
-----------------------------------------------------------
|
||||
|
||||
return function()
|
||||
local func
|
||||
local inerror = false
|
||||
|
||||
local function deferErrhand(...)
|
||||
local errhand = love.errorhandler or love.errhand
|
||||
local handler = (not inerror and errhand) or error_printer
|
||||
inerror = true
|
||||
func = handler(...)
|
||||
end
|
||||
|
||||
local function earlyinit()
|
||||
-- If love.boot fails, return 1 and finish immediately
|
||||
local result = xpcall(love.boot, error_printer)
|
||||
if not result then return 1 end
|
||||
|
||||
-- If love.init or love.run fails, don't return a value,
|
||||
-- as we want the error handler to take over
|
||||
result = xpcall(love.init, deferErrhand)
|
||||
if not result then return end
|
||||
|
||||
-- NOTE: We can't assign to func directly, as we'd
|
||||
-- overwrite the result of deferErrhand with nil on error
|
||||
local main
|
||||
result, main = xpcall(love.run, deferErrhand)
|
||||
if result then
|
||||
func = main
|
||||
end
|
||||
end
|
||||
|
||||
func = earlyinit
|
||||
|
||||
while func do
|
||||
local _, retval, restartvalue = xpcall(func, deferErrhand)
|
||||
if retval then return retval, restartvalue end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
@@ -0,0 +1,313 @@
|
||||
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-2021 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 love = require("love")
|
||||
|
||||
function love.createhandlers()
|
||||
|
||||
-- Standard callback handlers.
|
||||
love.handlers = setmetatable({
|
||||
keypressed = function (b,s,r)
|
||||
if love.keypressed then return love.keypressed(b,s,r) end
|
||||
end,
|
||||
keyreleased = function (b,s)
|
||||
if love.keyreleased then return love.keyreleased(b,s) end
|
||||
end,
|
||||
textinput = function (t)
|
||||
if love.textinput then return love.textinput(t) end
|
||||
end,
|
||||
textedited = function (t,s,l)
|
||||
if love.textedited then return love.textedited(t,s,l) end
|
||||
end,
|
||||
mousemoved = function (x,y,dx,dy,t)
|
||||
if love.mousemoved then return love.mousemoved(x,y,dx,dy,t) end
|
||||
end,
|
||||
mousepressed = function (x,y,b,t,c)
|
||||
if love.mousepressed then return love.mousepressed(x,y,b,t,c) end
|
||||
end,
|
||||
mousereleased = function (x,y,b,t,c)
|
||||
if love.mousereleased then return love.mousereleased(x,y,b,t,c) end
|
||||
end,
|
||||
wheelmoved = function (x,y)
|
||||
if love.wheelmoved then return love.wheelmoved(x,y) end
|
||||
end,
|
||||
touchpressed = function (id,x,y,dx,dy,p)
|
||||
if love.touchpressed then return love.touchpressed(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
touchreleased = function (id,x,y,dx,dy,p)
|
||||
if love.touchreleased then return love.touchreleased(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
touchmoved = function (id,x,y,dx,dy,p)
|
||||
if love.touchmoved then return love.touchmoved(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
joystickpressed = function (j,b)
|
||||
if love.joystickpressed then return love.joystickpressed(j,b) end
|
||||
end,
|
||||
joystickreleased = function (j,b)
|
||||
if love.joystickreleased then return love.joystickreleased(j,b) end
|
||||
end,
|
||||
joystickaxis = function (j,a,v)
|
||||
if love.joystickaxis then return love.joystickaxis(j,a,v) end
|
||||
end,
|
||||
joystickhat = function (j,h,v)
|
||||
if love.joystickhat then return love.joystickhat(j,h,v) end
|
||||
end,
|
||||
gamepadpressed = function (j,b)
|
||||
if love.gamepadpressed then return love.gamepadpressed(j,b) end
|
||||
end,
|
||||
gamepadreleased = function (j,b)
|
||||
if love.gamepadreleased then return love.gamepadreleased(j,b) end
|
||||
end,
|
||||
gamepadaxis = function (j,a,v)
|
||||
if love.gamepadaxis then return love.gamepadaxis(j,a,v) end
|
||||
end,
|
||||
joystickadded = function (j)
|
||||
if love.joystickadded then return love.joystickadded(j) end
|
||||
end,
|
||||
joystickremoved = function (j)
|
||||
if love.joystickremoved then return love.joystickremoved(j) end
|
||||
end,
|
||||
focus = function (f)
|
||||
if love.focus then return love.focus(f) end
|
||||
end,
|
||||
mousefocus = function (f)
|
||||
if love.mousefocus then return love.mousefocus(f) end
|
||||
end,
|
||||
visible = function (v)
|
||||
if love.visible then return love.visible(v) end
|
||||
end,
|
||||
quit = function ()
|
||||
return
|
||||
end,
|
||||
threaderror = function (t, err)
|
||||
if love.threaderror then return love.threaderror(t, err) end
|
||||
end,
|
||||
resize = function (w, h)
|
||||
if love.resize then return love.resize(w, h) end
|
||||
end,
|
||||
filedropped = function (f)
|
||||
if love.filedropped then return love.filedropped(f) end
|
||||
end,
|
||||
directorydropped = function (dir)
|
||||
if love.directorydropped then return love.directorydropped(dir) end
|
||||
end,
|
||||
lowmemory = function ()
|
||||
if love.lowmemory then love.lowmemory() end
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
end,
|
||||
displayrotated = function (display, orient)
|
||||
if love.displayrotated then return love.displayrotated(display, orient) end
|
||||
end,
|
||||
}, {
|
||||
__index = function(self, name)
|
||||
error("Unknown event: " .. name)
|
||||
end,
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
-- Default callbacks.
|
||||
-----------------------------------------------------------
|
||||
|
||||
function love.run()
|
||||
if love.load then love.load(love.parsedGameArguments, love.rawGameArguments) end
|
||||
|
||||
-- We don't want the first frame's dt to include time taken by love.load.
|
||||
if love.timer then love.timer.step() end
|
||||
|
||||
-- Main loop time.
|
||||
return function()
|
||||
-- Process events.
|
||||
if love.event then
|
||||
love.event.pump()
|
||||
for name, a,b,c,d,e,f in love.event.poll() do
|
||||
if name == "quit" then
|
||||
if not love.quit or not love.quit() then
|
||||
return a or 0, b
|
||||
end
|
||||
end
|
||||
love.handlers[name](a,b,c,d,e,f)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update dt, as we'll be passing it to update
|
||||
local dt = love.timer and love.timer.step() or 0
|
||||
|
||||
-- Call update and draw
|
||||
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
|
||||
|
||||
if love.graphics and love.graphics.isActive() then
|
||||
love.graphics.origin()
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
|
||||
if love.draw then love.draw() end
|
||||
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
if love.timer then love.timer.sleep(0.001) end
|
||||
end
|
||||
end
|
||||
|
||||
local debug, print, tostring, error = debug, print, tostring, error
|
||||
|
||||
function love.threaderror(t, err)
|
||||
error("Thread error ("..tostring(t)..")\n\n"..err, 0)
|
||||
end
|
||||
|
||||
local utf8 = require("utf8")
|
||||
|
||||
local function error_printer(msg, layer)
|
||||
print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", "")))
|
||||
end
|
||||
|
||||
function love.errhand(msg)
|
||||
msg = tostring(msg)
|
||||
|
||||
error_printer(msg, 2)
|
||||
|
||||
if not love.window or not love.graphics or not love.event then
|
||||
return
|
||||
end
|
||||
|
||||
if not love.graphics.isCreated() or not love.window.isOpen() then
|
||||
local success, status = pcall(love.window.setMode, 800, 600)
|
||||
if not success or not status then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset state.
|
||||
if love.mouse then
|
||||
love.mouse.setVisible(true)
|
||||
love.mouse.setGrabbed(false)
|
||||
love.mouse.setRelativeMode(false)
|
||||
if love.mouse.isCursorSupported() then
|
||||
love.mouse.setCursor()
|
||||
end
|
||||
end
|
||||
if love.joystick then
|
||||
-- Stop all joystick vibrations.
|
||||
for i,v in ipairs(love.joystick.getJoysticks()) do
|
||||
v:setVibration()
|
||||
end
|
||||
end
|
||||
if love.audio then love.audio.stop() end
|
||||
|
||||
love.graphics.reset()
|
||||
local font = love.graphics.setNewFont(14)
|
||||
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
|
||||
local trace = debug.traceback()
|
||||
|
||||
love.graphics.origin()
|
||||
|
||||
local sanitizedmsg = {}
|
||||
for char in msg:gmatch(utf8.charpattern) do
|
||||
table.insert(sanitizedmsg, char)
|
||||
end
|
||||
sanitizedmsg = table.concat(sanitizedmsg)
|
||||
|
||||
local err = {}
|
||||
|
||||
table.insert(err, "Error\n")
|
||||
table.insert(err, sanitizedmsg)
|
||||
|
||||
if #sanitizedmsg ~= #msg then
|
||||
table.insert(err, "Invalid UTF-8 string in error message.")
|
||||
end
|
||||
|
||||
table.insert(err, "\n")
|
||||
|
||||
for l in trace:gmatch("(.-)\n") do
|
||||
if not l:match("boot.lua") then
|
||||
l = l:gsub("stack traceback:", "Traceback\n")
|
||||
table.insert(err, l)
|
||||
end
|
||||
end
|
||||
|
||||
local p = table.concat(err, "\n")
|
||||
|
||||
p = p:gsub("\t", "")
|
||||
p = p:gsub("%[string \"(.-)\"%]", "%1")
|
||||
|
||||
local function draw()
|
||||
if not love.graphics.isActive() then return end
|
||||
local pos = 70
|
||||
love.graphics.clear(89/255, 157/255, 220/255)
|
||||
love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos)
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
local fullErrorText = p
|
||||
local function copyToClipboard()
|
||||
if not love.system then return end
|
||||
love.system.setClipboardText(fullErrorText)
|
||||
p = p .. "\nCopied to clipboard!"
|
||||
end
|
||||
|
||||
if love.system then
|
||||
p = p .. "\n\nPress Ctrl+C or tap to copy this error"
|
||||
end
|
||||
|
||||
return function()
|
||||
love.event.pump()
|
||||
|
||||
for e, a, b, c in love.event.poll() do
|
||||
if e == "quit" then
|
||||
return 1
|
||||
elseif e == "keypressed" and a == "escape" then
|
||||
return 1
|
||||
elseif e == "keypressed" and a == "c" and love.keyboard.isDown("lctrl", "rctrl") then
|
||||
copyToClipboard()
|
||||
elseif e == "touchpressed" then
|
||||
local name = love.window.getTitle()
|
||||
if #name == 0 or name == "Untitled" then name = "Game" end
|
||||
local buttons = {"OK", "Cancel"}
|
||||
if love.system then
|
||||
buttons[3] = "Copy to clipboard"
|
||||
end
|
||||
local pressed = love.window.showMessageBox("Quit "..name.."?", "", buttons)
|
||||
if pressed == 1 then
|
||||
return 1
|
||||
elseif pressed == 3 then
|
||||
copyToClipboard()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
draw()
|
||||
|
||||
if love.timer then
|
||||
love.timer.sleep(0.1)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
@@ -0,0 +1,71 @@
|
||||
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-2021 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.
|
||||
--]]
|
||||
|
||||
if type(jit) ~= "table" or not jit.status() then
|
||||
return
|
||||
end
|
||||
|
||||
-- Double the defaults.
|
||||
jit.opt.start("maxtrace=2000", "maxrecord=8000")
|
||||
|
||||
-- Somewhat arbitrary value. Needs to be higher than the combined sizes below,
|
||||
-- and higher than the default (512) because that's already too low.
|
||||
jit.opt.start("maxmcode=16384")
|
||||
|
||||
if jit.arch == "arm64" then
|
||||
-- https://github.com/LuaJIT/LuaJIT/issues/285
|
||||
-- LuaJIT 2.1 on arm64 currently (as of commit b4b2dce) can only use memory
|
||||
-- for JIT compilation within a certain short range. Other libraries such as
|
||||
-- SDL can take all the usable space in that range and cause attempts at JIT
|
||||
-- compilation to both fail and take a long time.
|
||||
-- This is a very hacky attempt at a workaround. LuaJIT allocates executable
|
||||
-- code in pools. We'll try "reserving" pools before any external code is
|
||||
-- executed, by causing JIT compilation via a small loop. We can't easily
|
||||
-- tell if JIT compilation succeeded, so we do several successively smaller
|
||||
-- pool allocations in case previous ones fail.
|
||||
-- This is a really hacky hack and by no means foolproof - there are a lot of
|
||||
-- potential situations (especially when threads are used) where previously
|
||||
-- executed external code will still take up space that LuaJIT needed for itself.
|
||||
|
||||
jit.opt.start("sizemcode=2048")
|
||||
for i=1, 100 do end
|
||||
|
||||
jit.opt.start("sizemcode=1024")
|
||||
for i=1, 100 do end
|
||||
|
||||
jit.opt.start("sizemcode=512")
|
||||
for i=1, 100 do end
|
||||
|
||||
jit.opt.start("sizemcode=256")
|
||||
for i=1, 100 do end
|
||||
|
||||
jit.opt.start("sizemcode=128")
|
||||
for i=1, 100 do end
|
||||
else
|
||||
-- Somewhat arbitrary value (>= the default).
|
||||
jit.opt.start("sizemcode=128")
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
+98
-11
@@ -23,6 +23,7 @@
|
||||
#include "common/version.h"
|
||||
#include "common/deprecation.h"
|
||||
#include "common/runtime.h"
|
||||
#include "modules/window/Window.h"
|
||||
|
||||
#include "love.h"
|
||||
|
||||
@@ -32,10 +33,20 @@
|
||||
|
||||
#ifdef LOVE_WINDOWS
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
// VS 2013 and earlier doesn't have snprintf
|
||||
#define snprintf sprintf_s
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||
|
||||
#endif // LOVE_WINDOWS
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
#include <SDL.h>
|
||||
extern "C"
|
||||
{
|
||||
#include "luajit.h"
|
||||
}
|
||||
#endif // LOVE_ANDROID
|
||||
|
||||
#ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK
|
||||
@@ -75,9 +86,25 @@
|
||||
# include "audio/Audio.h"
|
||||
#endif
|
||||
|
||||
// Scripts
|
||||
// Scripts.
|
||||
#include "scripts/nogame.lua.h"
|
||||
#include "scripts/boot.lua.h"
|
||||
|
||||
// Put the Lua code directly into a raw string literal.
|
||||
static const char arg_lua[] =
|
||||
#include "arg.lua"
|
||||
;
|
||||
|
||||
static const char callbacks_lua[] =
|
||||
#include "callbacks.lua"
|
||||
;
|
||||
|
||||
static const char boot_lua[] =
|
||||
#include "boot.lua"
|
||||
;
|
||||
|
||||
static const char jit_setup_lua[] =
|
||||
#include "jitsetup.lua"
|
||||
;
|
||||
|
||||
// All modules define a c-accessible luaopen
|
||||
// so let's make use of those, instead
|
||||
@@ -142,6 +169,9 @@ extern "C"
|
||||
extern int luaopen_love_window(lua_State*);
|
||||
#endif
|
||||
extern int luaopen_love_nogame(lua_State*);
|
||||
extern int luaopen_love_jitsetup(lua_State*);
|
||||
extern int luaopen_love_arg(lua_State*);
|
||||
extern int luaopen_love_callbacks(lua_State*);
|
||||
extern int luaopen_love_boot(lua_State*);
|
||||
}
|
||||
|
||||
@@ -204,6 +234,9 @@ static const luaL_Reg modules[] = {
|
||||
{ "love.window", luaopen_love_window },
|
||||
#endif
|
||||
{ "love.nogame", luaopen_love_nogame },
|
||||
{ "love.jitsetup", luaopen_love_jitsetup },
|
||||
{ "love.arg", luaopen_love_arg },
|
||||
{ "love.callbacks", luaopen_love_callbacks },
|
||||
{ "love.boot", luaopen_love_boot },
|
||||
{ 0, 0 }
|
||||
};
|
||||
@@ -413,6 +446,15 @@ static void luax_addcompatibilityalias(lua_State *L, const char *module, const c
|
||||
|
||||
int luaopen_love(lua_State *L)
|
||||
{
|
||||
// Preload module loaders.
|
||||
for (int i = 0; modules[i].name != nullptr; i++)
|
||||
love::luax_preload(L, modules[i].func, modules[i].name);
|
||||
|
||||
// jitsetup is also loaded in the love executable runlove function. It's
|
||||
// needed here too for threads. Note that it doesn't use the love table.
|
||||
love::luax_require(L, "love.jitsetup");
|
||||
lua_pop(L, 1);
|
||||
|
||||
love::luax_insistpinnedthread(L);
|
||||
|
||||
love::luax_insistglobal(L, "love");
|
||||
@@ -432,6 +474,7 @@ int luaopen_love(lua_State *L)
|
||||
lua_setfield(L, -2, "_version_codename");
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_OFF);
|
||||
lua_register(L, "print", w_print_sdl_log);
|
||||
#endif
|
||||
|
||||
@@ -515,10 +558,6 @@ int luaopen_love(lua_State *L)
|
||||
lua_setfield(L, -2, "hasDeprecationOutput");
|
||||
}
|
||||
|
||||
// Preload module loaders.
|
||||
for (int i = 0; modules[i].name != nullptr; i++)
|
||||
love::luax_preload(L, modules[i].func, modules[i].name);
|
||||
|
||||
// Necessary for Data-creating methods to work properly in Data subclasses.
|
||||
love::luax_require(L, "love.data");
|
||||
lua_pop(L, 1);
|
||||
@@ -540,6 +579,33 @@ int luaopen_love(lua_State *L)
|
||||
love::luax_preload(L, luaopen_luautf8, "utf8");
|
||||
#endif
|
||||
|
||||
#ifdef LOVE_ENABLE_WINDOW
|
||||
// In some environments, LuaJIT is limited to 2GB and LuaJIT sometimes panic when it
|
||||
// reaches OOM and closes the whole program, leaving the user confused about what's
|
||||
// going on.
|
||||
// We can't recover the state at this point, but it's better to inform user that
|
||||
// something very bad happening instead of silently exiting.
|
||||
// Note that this is not foolproof. In some cases, the whole process crashes by
|
||||
// uncaught exception that LuaJIT throws or simply exit as if calling
|
||||
// love.event.quit("not enough memory")
|
||||
lua_atpanic(L, [](lua_State *L)
|
||||
{
|
||||
using namespace love;
|
||||
using namespace love::window;
|
||||
|
||||
char message[128];
|
||||
Window* windowModule = Module::getInstance<Window>(Module::M_WINDOW);
|
||||
|
||||
snprintf(message, sizeof(message), "PANIC: unprotected error in call to Lua API (%s)", lua_tostring(L, -1));
|
||||
|
||||
if (windowModule)
|
||||
windowModule->showMessageBox("Lua Fatal Error", message, Window::MESSAGEBOX_ERROR, windowModule->isOpen());
|
||||
|
||||
fprintf(stderr, "%s\n", message);
|
||||
return 0;
|
||||
});
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -638,7 +704,31 @@ int w__setAccelerometerAsJoystick(lua_State *L)
|
||||
|
||||
int luaopen_love_nogame(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, (const char *)love::nogame_lua, sizeof(love::nogame_lua), "nogame.lua") == 0)
|
||||
if (luaL_loadbuffer(L, (const char *)love::nogame_lua, sizeof(love::nogame_lua), "=[love \"nogame.lua\"]") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int luaopen_love_jitsetup(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, jit_setup_lua, sizeof(jit_setup_lua), "=[love \"jitsetup.lua\"]") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int luaopen_love_arg(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "=[love \"arg.lua\"]") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int luaopen_love_callbacks(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, callbacks_lua, sizeof(callbacks_lua), "=[love \"callbacks.lua\"]") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
@@ -646,11 +736,8 @@ int luaopen_love_nogame(lua_State *L)
|
||||
|
||||
int luaopen_love_boot(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, (const char *)love::boot_lua, sizeof(love::boot_lua), "boot.lua") == 0)
|
||||
if (luaL_loadbuffer(L, boot_lua, sizeof(boot_lua), "=[love \"boot.lua\"]") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ LOVE_EXPORT const char *love_version();
|
||||
LOVE_EXPORT const char *love_codename();
|
||||
LOVE_EXPORT int luaopen_love(lua_State *L);
|
||||
LOVE_EXPORT int luaopen_love_nogame(lua_State *L);
|
||||
LOVE_EXPORT int luaopen_love_jitsetup(lua_State *L);
|
||||
LOVE_EXPORT int luaopen_love_arg(lua_State *L);
|
||||
LOVE_EXPORT int luaopen_love_callbacks(lua_State *L);
|
||||
LOVE_EXPORT int luaopen_love_boot(lua_State *L);
|
||||
|
||||
#ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK
|
||||
|
||||
@@ -83,10 +83,10 @@ float linearToGamma(float c);
|
||||
*
|
||||
* @return Noise value in the range of [0, 1].
|
||||
**/
|
||||
static float noise1(float x);
|
||||
static float noise2(float x, float y);
|
||||
static float noise3(float x, float y, float z);
|
||||
static float noise4(float x, float y, float z, float w);
|
||||
static float noise1(double x);
|
||||
static float noise2(double x, double y);
|
||||
static float noise3(double x, double y, double z);
|
||||
static float noise4(double x, double y, double z, double w);
|
||||
|
||||
|
||||
class Math : public Module
|
||||
@@ -132,12 +132,12 @@ private:
|
||||
}; // Math
|
||||
|
||||
|
||||
static inline float noise1(float x)
|
||||
static inline float noise1(double x)
|
||||
{
|
||||
return SimplexNoise1234::noise(x) * 0.5f + 0.5f;
|
||||
}
|
||||
|
||||
static inline float noise2(float x, float y)
|
||||
static inline float noise2(double x, double y)
|
||||
{
|
||||
return SimplexNoise1234::noise(x, y) * 0.5f + 0.5f;
|
||||
}
|
||||
@@ -145,12 +145,12 @@ static inline float noise2(float x, float y)
|
||||
// Perlin noise is used instead of Simplex noise in the 3D and 4D cases to avoid
|
||||
// patent issues.
|
||||
|
||||
static inline float noise3(float x, float y, float z)
|
||||
static inline float noise3(double x, double y, double z)
|
||||
{
|
||||
return Noise1234::noise(x, y, z) * 0.5f + 0.5f;
|
||||
}
|
||||
|
||||
static inline float noise4(float x, float y, float z, float w)
|
||||
static inline float noise4(double x, double y, double z, double w)
|
||||
{
|
||||
return Noise1234::noise(x, y, z, w) * 0.5f + 0.5f;
|
||||
}
|
||||
|
||||
@@ -319,10 +319,10 @@ int w_linearToGamma(lua_State *L)
|
||||
int w_noise(lua_State *L)
|
||||
{
|
||||
int nargs = std::min(std::max(lua_gettop(L), 1), 4);
|
||||
float args[4];
|
||||
double args[4];
|
||||
|
||||
for (int i = 0; i < nargs; i++)
|
||||
args[i] = (float) luaL_checknumber(L, i + 1);
|
||||
args[i] = luaL_checknumber(L, i + 1);
|
||||
|
||||
float val = 0.0f;
|
||||
|
||||
@@ -349,10 +349,10 @@ int w_noise(lua_State *L)
|
||||
// C functions in a struct, necessary for the FFI versions of math functions.
|
||||
struct FFI_Math
|
||||
{
|
||||
float (*noise1)(float x);
|
||||
float (*noise2)(float x, float y);
|
||||
float (*noise3)(float x, float y, float z);
|
||||
float (*noise4)(float x, float y, float z, float w);
|
||||
float (*noise1)(double x);
|
||||
float (*noise2)(double x, double y);
|
||||
float (*noise3)(double x, double y, double z);
|
||||
float (*noise4)(double x, double y, double z, double w);
|
||||
|
||||
float (*gammaToLinear)(float c);
|
||||
float (*linearToGamma)(float c);
|
||||
@@ -415,7 +415,7 @@ extern "C" int luaopen_love_math(lua_State *L)
|
||||
int n = luax_register_module(L, w);
|
||||
|
||||
// Execute wrap_Math.lua, sending the math table and ffifuncs pointer as args.
|
||||
luaL_loadbuffer(L, math_lua, sizeof(math_lua), "wrap_Math.lua");
|
||||
luaL_loadbuffer(L, math_lua, sizeof(math_lua), "=[love \"wrap_Math.lua\"]");
|
||||
lua_pushvalue(L, -2);
|
||||
luax_pushpointerasstring(L, &ffifuncs);
|
||||
lua_call(L, 2, 0);
|
||||
|
||||
@@ -93,10 +93,10 @@ if not status then return end
|
||||
pcall(ffi.cdef, [[
|
||||
typedef struct FFI_Math
|
||||
{
|
||||
float (*noise1)(float x);
|
||||
float (*noise2)(float x, float y);
|
||||
float (*noise3)(float x, float y, float z);
|
||||
float (*noise4)(float x, float y, float z, float w);
|
||||
float (*noise1)(double x);
|
||||
float (*noise2)(double x, double y);
|
||||
float (*noise3)(double x, double y, double z);
|
||||
float (*noise4)(double x, double y, double z, double w);
|
||||
|
||||
float (*gammaToLinear)(float c);
|
||||
float (*linearToGamma)(float c);
|
||||
|
||||
@@ -101,8 +101,9 @@ float RevoluteJoint::getMotorSpeed() const
|
||||
return joint->GetMotorSpeed();
|
||||
}
|
||||
|
||||
float RevoluteJoint::getMotorTorque(float inv_dt) const
|
||||
float RevoluteJoint::getMotorTorque(float dt) const
|
||||
{
|
||||
float inv_dt = 1.0f / dt;
|
||||
return Physics::scaleUp(Physics::scaleUp(joint->GetMotorTorque(inv_dt)));
|
||||
}
|
||||
|
||||
|
||||
@@ -87,9 +87,9 @@ public:
|
||||
|
||||
/**
|
||||
* Get the current motor torque, usually in N-m.
|
||||
* @param inv_dt The inverse timestep.
|
||||
* @param dt The timestep.
|
||||
**/
|
||||
float getMotorTorque(float inv_dt) const;
|
||||
float getMotorTorque(float dt) const;
|
||||
|
||||
/**
|
||||
* Get the maximum motor torque, usually in N-m.
|
||||
|
||||
@@ -91,8 +91,8 @@ int w_RevoluteJoint_getMotorSpeed(lua_State *L)
|
||||
int w_RevoluteJoint_getMotorTorque(lua_State *L)
|
||||
{
|
||||
RevoluteJoint *t = luax_checkrevolutejoint(L, 1);
|
||||
float inv_dt = (float)luaL_checknumber(L, 2);
|
||||
lua_pushnumber(L, t->getMotorTorque(inv_dt));
|
||||
float dt = (float)luaL_checknumber(L, 2);
|
||||
lua_pushnumber(L, t->getMotorTorque(dt));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ OggDemuxer::~OggDemuxer()
|
||||
ogg_sync_clear(&sync);
|
||||
}
|
||||
|
||||
void OggDemuxer::readPage()
|
||||
bool OggDemuxer::readPage(bool erroreof)
|
||||
{
|
||||
char *syncBuffer = nullptr;
|
||||
while (ogg_sync_pageout(&sync, &page) != 1)
|
||||
@@ -53,8 +53,13 @@ void OggDemuxer::readPage()
|
||||
|
||||
syncBuffer = ogg_sync_buffer(&sync, 8192);
|
||||
size_t read = file->read(syncBuffer, 8192);
|
||||
if (read == 0 && erroreof)
|
||||
return false;
|
||||
|
||||
ogg_sync_wrote(&sync, read);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OggDemuxer::readPacket(ogg_packet &packet, bool mustSucceed)
|
||||
@@ -118,22 +123,25 @@ OggDemuxer::StreamType OggDemuxer::findStream()
|
||||
if (streamInited)
|
||||
{
|
||||
eos = false;
|
||||
streamInited = false;
|
||||
file->seek(0);
|
||||
ogg_stream_clear(&stream);
|
||||
ogg_sync_reset(&sync);
|
||||
}
|
||||
|
||||
streamInited = true;
|
||||
while (true)
|
||||
{
|
||||
if (!readPage(true))
|
||||
return TYPE_UNKNOWN;
|
||||
|
||||
// If this page isn't at the start of a stream, we've seen all streams
|
||||
readPage();
|
||||
if (!ogg_page_bos(&page))
|
||||
break;
|
||||
|
||||
videoSerial = ogg_page_serialno(&page);
|
||||
ogg_stream_init(&stream, videoSerial);
|
||||
ogg_stream_pagein(&stream, &page);
|
||||
streamInited = true;
|
||||
|
||||
StreamType type = determineType();
|
||||
switch(type)
|
||||
@@ -145,10 +153,15 @@ OggDemuxer::StreamType OggDemuxer::findStream()
|
||||
}
|
||||
|
||||
ogg_stream_clear(&stream);
|
||||
streamInited = false;
|
||||
}
|
||||
|
||||
if (streamInited)
|
||||
{
|
||||
streamInited = false;
|
||||
ogg_stream_clear(&stream);
|
||||
}
|
||||
|
||||
streamInited = false;
|
||||
ogg_stream_clear(&stream);
|
||||
ogg_sync_reset(&sync);
|
||||
|
||||
return TYPE_UNKNOWN;
|
||||
|
||||
@@ -67,7 +67,7 @@ private:
|
||||
int videoSerial;
|
||||
bool eos;
|
||||
|
||||
void readPage();
|
||||
bool readPage(bool erroreof = false);
|
||||
StreamType determineType();
|
||||
}; // OggDemuxer
|
||||
|
||||
|
||||
Reference in New Issue
Block a user