updated to latest love-android revision (aada9b59bcdf)

This commit is contained in:
fysx
2014-01-20 10:09:26 +01:00
parent ab51b4cc9b
commit ba5f33f9aa
45 changed files with 1112 additions and 50480 deletions
+3 -1
View File
@@ -3,7 +3,9 @@
android:versionCode="7"
android:versionName="0.9.0-alpha7"
android:installLocation="auto" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/><application
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="Löve for Android"
+1 -2
View File
@@ -43,8 +43,7 @@ LOCAL_SRC_FILES := \
$(wildcard $(LOCAL_PATH)/src/timer/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/unix/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/test/*.c))
$(wildcard $(LOCAL_PATH)/src/video/android/*.c))
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
+2
View File
@@ -71,6 +71,8 @@ LOCAL_SRC_FILES := \
$(wildcard ${LOCAL_PATH}/src/modules/system/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/thread/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/thread/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/touch/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/touch/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/timer/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/timer/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/window/*.cpp) \
+7 -1
View File
@@ -26,7 +26,11 @@
# define LOVE_WINDOWS 1
#endif
#if defined(linux) || defined(__linux) || defined(__linux__)
# define LOVE_LINUX 1
# if defined(__ANDROID__)
# define LOVE_ANDROID 1
# else
# define LOVE_LINUX 1
# endif
#endif
#if defined(__APPLE__)
# define LOVE_MACOSX 1
@@ -123,6 +127,8 @@
# define LOVE_ENABLE_THREAD_SDL
# define LOVE_ENABLE_TIMER
# define LOVE_ENABLE_TIMER_SDL
# define LOVE_ENABLE_TOUCH
# define LOVE_ENABLE_TOUCH_SDL
# define LOVE_ENABLE_UTF8
# define LOVE_ENABLE_WINDOW
# define LOVE_ENABLE_WINDOW_SDL
+1 -1
View File
@@ -464,7 +464,7 @@ void luax_pushtype(lua_State *L, const char *name, bits flags, love::Object *dat
bool luax_istype(lua_State *L, int idx, love::bits type)
{
if (lua_isuserdata(L, idx) == 0)
if (lua_type(L, idx) != LUA_TUSERDATA)
return false;
return ((((Proxy *)lua_touserdata(L, idx))->flags & type) == type);
+1 -1
View File
@@ -401,7 +401,7 @@ extern "C" { // Also called from luasocket
template <typename T>
T *luax_checktype(lua_State *L, int idx, const char *name, love::bits type)
{
if (lua_isuserdata(L, idx) == 0)
if (lua_type(L, idx) != LUA_TUSERDATA)
luax_typerror(L, idx, name);
Proxy *u = (Proxy *)lua_touserdata(L, idx);
+2 -2
View File
@@ -151,7 +151,7 @@ static const struct luaL_Reg sdl_lib[] = {
int main(int argc, char **argv)
{
#ifdef __ANDROID__
#ifdef LOVE_ANDROID
SDL_SetHint("LOVE_GRAPHICS_USE_OPENGLES", "1");
#endif
@@ -248,7 +248,7 @@ int main(int argc, char **argv)
#endif // LOVE_LEGENDARY_UTF8_ARGV_HACK || LOVE_LEGENDARY_APP_ARGV_HACK
SDL_Quit();
#ifdef __ANDROID__
#ifdef LOVE_ANDROID
exit(retval);
#endif
+38 -24
View File
@@ -28,56 +28,70 @@ namespace love
namespace event
{
Message::Message(const std::string &name, Variant *a, Variant *b, Variant *c, Variant *d)
Message::Message(const std::string &name, const std::vector<Variant *> &vargs)
: name(name)
, nargs(0)
, args(vargs)
{
args[0] = a;
args[1] = b;
args[2] = c;
args[3] = d;
for (int i = 0; i < 4; i++)
for (auto it = args.begin(); it != args.end(); ++it)
{
if (!args[i])
break;
args[i]->retain();
nargs++;
if ((*it) != nullptr)
(*it)->retain();
}
}
Message::~Message()
{
for (int i = 0; i < nargs; i++)
args[i]->release();
for (auto it = args.begin(); it != args.end(); ++it)
{
if ((*it) != nullptr)
(*it)->release();
}
}
int Message::toLua(lua_State *L)
{
luax_pushstring(L, name);
for (int i = 0; i < nargs; i++)
args[i]->toLua(L);
return nargs+1;
for (auto it = args.begin(); it != args.end(); ++it)
{
if ((*it) != nullptr)
(*it)->toLua(L);
else
lua_pushnil(L);
}
return (int) args.size() + 1;
}
Message *Message::fromLua(lua_State *L, int n)
{
std::string name = luax_checkstring(L, n);
std::vector<Variant *> vargs;
int count = lua_gettop(L) - n;
n++;
Message *m = new Message(name);
for (int i = 0; i < 4; i++)
for (int i = 0; i < count; i++)
{
if (lua_isnoneornil(L, n+i))
break;
m->args[i] = Variant::fromLua(L, n+i);
if (!m->args[i])
vargs.push_back(Variant::fromLua(L, n+i));
if (!vargs.back())
{
delete m;
for (auto it = vargs.begin(); it != vargs.end(); ++it)
{
if ((*it) != nullptr)
(*it)->release();
}
luaL_error(L, "Argument %d can't be stored safely\nExpected boolean, number, string or userdata.", n+i);
return NULL;
return nullptr;
}
m->nargs++;
}
return m;
return new Message(name, vargs);
}
Event::Event()
+13 -7
View File
@@ -32,29 +32,34 @@
// STL
#include <queue>
#include <vector>
namespace love
{
namespace event
{
class Message : public Object
{
private:
std::string name;
Variant *args[4];
int nargs;
public:
Message(const std::string &name, Variant *a = NULL, Variant *b = NULL, Variant *c = NULL, Variant *d = NULL);
Message(const std::string &name, const std::vector<Variant *> &vargs = std::vector<Variant *>());
~Message();
int toLua(lua_State *L);
static Message *fromLua(lua_State *L, int n);
};
private:
std::string name;
std::vector<Variant *> args;
}; // Message
class Event : public Module
{
public:
Event();
virtual ~Event();
@@ -65,6 +70,7 @@ public:
virtual void pump() = 0;
protected:
thread::Mutex *mutex;
std::queue<Message *> queue;
+154 -127
View File
@@ -38,6 +38,24 @@ namespace event
namespace sdl
{
// SDL reports mouse coordinates in the window coordinate system in OS X, but
// we want them in pixel coordinates (may be different with high-DPI enabled.)
static void windowToPixelCoords(int *x, int *y)
{
double scale = 1.0;
window::Window *window = (window::Window *) Module::findInstance("love.window.");
if (window != nullptr)
scale = window->getPixelScale();
if (x != nullptr)
*x = int(double(*x) * scale);
if (y != nullptr)
*y = int(double(*y) * scale);
}
const char *Event::getName() const
{
return "love.event.sdl";
@@ -96,19 +114,22 @@ void Event::clear()
Message *Event::convert(const SDL_Event &e) const
{
Message *msg = NULL;
Message *msg = nullptr;
love::keyboard::Keyboard *kb = 0;
std::vector<Variant *> vargs;
vargs.reserve(4);
love::keyboard::Keyboard *kb = nullptr;
love::keyboard::Keyboard::Key key;
love::mouse::Mouse::Button button;
Variant *arg1, *arg2, *arg3;
const char *txt;
std::map<SDL_Keycode, love::keyboard::Keyboard::Key>::const_iterator keyit;
switch (e.type)
{
case SDL_KEYDOWN:
SDL_Log ("got keydown for key %d search %d equal = %d", e.key.keysym.sym, SDLK_AC_SEARCH, e.key.keysym.sym == SDLK_AC_SEARCH);
if (e.key.repeat)
{
kb = (love::keyboard::Keyboard *) Module::findInstance("love.keyboard.");
@@ -124,11 +145,10 @@ Message *Event::convert(const SDL_Event &e) const
if (!love::keyboard::Keyboard::getConstant(key, txt))
txt = "unknown";
arg1 = new Variant(txt, strlen(txt));
arg2 = new Variant(e.key.repeat != 0);
msg = new Message("keypressed", arg1, arg2);
arg1->release();
arg2->release();
vargs.push_back(new Variant(txt, strlen(txt)));
vargs.push_back(new Variant(e.key.repeat != 0));
msg = new Message("keypressed", vargs);
break;
case SDL_KEYUP:
keyit = keys.find(e.key.keysym.sym);
@@ -139,39 +159,36 @@ Message *Event::convert(const SDL_Event &e) const
if (!love::keyboard::Keyboard::getConstant(key, txt))
txt = "unknown";
arg1 = new Variant(txt, strlen(txt));
msg = new Message("keyreleased", arg1);
arg1->release();
vargs.push_back(new Variant(txt, strlen(txt)));
msg = new Message("keyreleased", vargs);
break;
case SDL_TEXTINPUT:
txt = e.text.text;
arg1 = new Variant(txt, strlen(txt));
msg = new Message("textinput", arg1);
arg1->release();
vargs.push_back(new Variant(txt, strlen(txt)));
msg = new Message("textinput", vargs);
break;
case SDL_TEXTEDITING:
txt = e.edit.text;
arg1 = new Variant(txt, strlen(txt));
arg2 = new Variant((double) e.edit.start);
arg3 = new Variant((double) e.edit.length);
msg = new Message("textedit", arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
vargs.push_back(new Variant(txt, strlen(txt)));
vargs.push_back(new Variant((double) e.edit.start));
vargs.push_back(new Variant((double) e.edit.length));
msg = new Message("textedit", vargs);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
if (buttons.find(e.button.button, button) && mouse::Mouse::getConstant(button, txt))
{
arg1 = new Variant((double) e.button.x);
arg2 = new Variant((double) e.button.y);
arg3 = new Variant(txt, strlen(txt));
int x = e.button.x;
int y = e.button.y;
windowToPixelCoords(&x, &y);
vargs.push_back(new Variant((double) x));
vargs.push_back(new Variant((double) y));
vargs.push_back(new Variant(txt, strlen(txt)));
vargs.push_back(new Variant(e.button.which == SDL_TOUCH_MOUSEID));
msg = new Message((e.type == SDL_MOUSEBUTTONDOWN) ?
"mousepressed" : "mousereleased",
arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
vargs);
}
break;
case SDL_MOUSEWHEEL:
@@ -183,36 +200,29 @@ Message *Event::convert(const SDL_Event &e) const
int mx, my;
SDL_GetMouseState(&mx, &my);
windowToPixelCoords(&mx, &my);
arg1 = new Variant((double) mx);
arg2 = new Variant((double) my);
arg3 = new Variant(txt, strlen(txt));
msg = new Message("mousepressed", arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
vargs.push_back(new Variant((double) mx));
vargs.push_back(new Variant((double) my));
vargs.push_back(new Variant(txt, strlen(txt)));
vargs.push_back(new Variant(false));
msg = new Message("mousepressed", vargs);
}
break;
case SDL_FINGERDOWN:
case SDL_FINGERUP:
arg1 = new Variant((double) e.tfinger.x);
arg2 = new Variant((double) e.tfinger.y);
arg3 = new Variant((double) e.tfinger.fingerId);
msg = new Message((e.type == SDL_FINGERDOWN) ?
"fingerpressed" : "fingerreleased",
arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
break;
case SDL_FINGERMOTION:
arg1 = new Variant((double) e.tfinger.x);
arg2 = new Variant((double) e.tfinger.y);
arg3 = new Variant((double) e.tfinger.fingerId);
msg = new Message("fingermotion", arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
vargs.push_back(new Variant((double) e.tfinger.fingerId));
vargs.push_back(new Variant((double) e.tfinger.x));
vargs.push_back(new Variant((double) e.tfinger.y));
vargs.push_back(new Variant((double) e.tfinger.pressure));
if (e.type == SDL_FINGERDOWN)
txt = "touchpressed";
else if (e.type == SDL_FINGERUP)
txt = "touchreleased";
else
txt = "touchmoved";
msg = new Message(txt, vargs);
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
@@ -239,6 +249,12 @@ Message *Event::convert(const SDL_Event &e) const
break;
}
for (auto it = vargs.begin(); it != vargs.end(); ++it)
{
if ((*it) != nullptr)
(*it)->release();
}
return msg;
}
@@ -246,14 +262,17 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
{
joystick::JoystickModule *joymodule = (joystick::JoystickModule *) Module::findInstance("love.joystick.");
if (!joymodule)
return 0;
return nullptr;
Message *msg = nullptr;
std::vector<Variant *> vargs;
vargs.reserve(4);
Message *msg = 0;
Proxy proxy;
love::joystick::Joystick::Hat hat;
love::joystick::Joystick::GamepadButton padbutton;
love::joystick::Joystick::GamepadAxis padaxis;
Variant *arg1, *arg2, *arg3;
const char *txt;
switch (e.type)
@@ -265,13 +284,11 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
if (!proxy.data)
break;
arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy);
arg2 = new Variant((double)(e.jbutton.button+1));
vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
vargs.push_back(new Variant((double)(e.jbutton.button+1)));
msg = new Message((e.type == SDL_JOYBUTTONDOWN) ?
"joystickpressed" : "joystickreleased",
arg1, arg2);
arg1->release();
arg2->release();
vargs);
break;
case SDL_JOYAXISMOTION:
{
@@ -280,17 +297,14 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
if (!proxy.data)
break;
arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy);
arg2 = new Variant((double)(e.jaxis.axis+1));
vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
vargs.push_back(new Variant((double)(e.jaxis.axis+1)));
float value = e.jaxis.value / 32768.0f;
if (fabsf(value) < 0.001f) value = 0.0f;
if (value < -0.99f) value = -1.0f;
if (value > 0.99f) value = 1.0f;
arg3 = new Variant((double) value);
msg = new Message("joystickaxis", arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
vargs.push_back(new Variant((double) value));
msg = new Message("joystickaxis", vargs);
}
break;
case SDL_JOYHATMOTION:
@@ -302,13 +316,10 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
if (!proxy.data)
break;
arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy);
arg2 = new Variant((double)(e.jhat.hat+1));
arg3 = new Variant(txt, strlen(txt));
msg = new Message("joystickhat", arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
vargs.push_back(new Variant((double)(e.jhat.hat+1)));
vargs.push_back(new Variant(txt, strlen(txt)));
msg = new Message("joystickhat", vargs);
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
@@ -323,12 +334,10 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
if (!proxy.data)
break;
arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy);
arg2 = new Variant(txt, strlen(txt));
vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
vargs.push_back(new Variant(txt, strlen(txt)));
msg = new Message(e.type == SDL_CONTROLLERBUTTONDOWN ?
"gamepadpressed" : "gamepadreleased", arg1, arg2);
arg1->release();
arg2->release();
"gamepadpressed" : "gamepadreleased", vargs);
break;
case SDL_CONTROLLERAXISMOTION:
if (joystick::sdl::Joystick::getConstant((SDL_GameControllerAxis) e.caxis.axis, padaxis))
@@ -341,18 +350,15 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
if (!proxy.data)
break;
arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy);
vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
arg2 = new Variant(txt, strlen(txt));
vargs.push_back(new Variant(txt, strlen(txt)));
float value = e.jaxis.value / 32768.0f;
if (fabsf(value) < 0.001f) value = 0.0f;
if (value < -0.99f) value = -1.0f;
if (value > 0.99f) value = 1.0f;
arg3 = new Variant((double) value);
msg = new Message("gamepadaxis", arg1, arg2, arg3);
arg1->release();
arg2->release();
arg3->release();
vargs.push_back(new Variant((double) value));
msg = new Message("gamepadaxis", vargs);
}
break;
case SDL_JOYDEVICEADDED:
@@ -361,9 +367,8 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
proxy.flags = JOYSTICK_JOYSTICK_T;
if (proxy.data)
{
arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy);
msg = new Message("joystickadded", arg1);
arg1->release();
vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
msg = new Message("joystickadded", vargs);
}
break;
case SDL_JOYDEVICEREMOVED:
@@ -373,26 +378,34 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const
if (proxy.data)
{
joymodule->removeJoystick((joystick::Joystick *) proxy.data);
arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy);
msg = new Message("joystickremoved", arg1);
arg1->release();
vargs.push_back(new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy));
msg = new Message("joystickremoved", vargs);
}
break;
default:
break;
}
for (auto it = vargs.begin(); it != vargs.end(); ++it)
{
if ((*it) != nullptr)
(*it)->release();
}
return msg;
}
Message *Event::convertWindowEvent(const SDL_Event &e) const
{
Message *msg = 0;
Variant *arg1, *arg2;
window::Window *win = 0;
Message *msg = nullptr;
std::vector<Variant *> vargs;
vargs.reserve(4);
window::Window *win = nullptr;
if (e.type != SDL_WINDOWEVENT)
return 0;
return nullptr;
switch (e.window.event)
{
@@ -404,56 +417,69 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const
SDL_DisableScreenSaver();
else
SDL_EnableScreenSaver();
arg1 = new Variant(e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED);
msg = new Message("focus", arg1);
arg1->release();
vargs.push_back(new Variant(e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED));
msg = new Message("focus", vargs);
break;
case SDL_WINDOWEVENT_ENTER:
case SDL_WINDOWEVENT_LEAVE:
arg1 = new Variant(e.window.event == SDL_WINDOWEVENT_ENTER);
msg = new Message("mousefocus", arg1);
arg1->release();
vargs.push_back(new Variant(e.window.event == SDL_WINDOWEVENT_ENTER));
msg = new Message("mousefocus", vargs);
break;
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_HIDDEN:
arg1 = new Variant(e.window.event == SDL_WINDOWEVENT_SHOWN);
msg = new Message("visible", arg1);
arg1->release();
vargs.push_back(new Variant(e.window.event == SDL_WINDOWEVENT_SHOWN));
msg = new Message("visible", vargs);
break;
case SDL_WINDOWEVENT_RESIZED:
win = (window::Window *) Module::findInstance("love.window.");
if (win)
{
int px_w = e.window.data1;
int px_h = e.window.data2;
#if SDL_VERSION_ATLEAST(2,0,1)
SDL_Window *sdlwin = SDL_GetWindowFromID(e.window.windowID);
if (sdlwin)
SDL_GL_GetDrawableSize(sdlwin, &px_w, &px_h);
#endif
win->onWindowResize(e.window.data1, e.window.data2);
graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
if (gfx)
gfx->setViewportSize(e.window.data1, e.window.data2);
gfx->setViewportSize(px_w, px_h);
vargs.push_back(new Variant((double) px_w));
vargs.push_back(new Variant((double) px_h));
vargs.push_back(new Variant((double) e.window.data1));
vargs.push_back(new Variant((double) e.window.data2));
msg = new Message("resize", vargs);
}
break;
#ifdef LOVE_ANDROID
case SDL_WINDOWEVENT_MINIMIZED:
{
audio::Audio *audio = (audio::Audio *) Module::findInstance("love.audio.");
if (audio)
audio->pause();
}
break;
case SDL_WINDOWEVENT_RESTORED:
{
audio::Audio *audio = (audio::Audio *) Module::findInstance("love.audio.");
if (audio)
audio->resume();
}
arg1 = new Variant((double) e.window.data1);
arg2 = new Variant((double) e.window.data2);
msg = new Message("resize", arg1, arg2);
arg1->release();
arg2->release();
break;
#ifdef __ANDROID__
case SDL_WINDOWEVENT_MINIMIZED:
{
audio::Audio *audio = (audio::Audio *) Module::findInstance("love.audio.");
if (audio)
audio->pause();
}
break;
case SDL_WINDOWEVENT_RESTORED:
{
audio::Audio *audio = (audio::Audio *) Module::findInstance("love.audio.");
if (audio)
audio->resume();
}
break;
#endif
}
for (auto it = vargs.begin(); it != vargs.end(); ++it)
{
if ((*it) != nullptr)
(*it)->release();
}
return msg;
}
@@ -601,6 +627,7 @@ std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::createKeyMap()
k[SDLK_EXECUTE] = Keyboard::KEY_EXECUTE;
k[SDLK_HELP] = Keyboard::KEY_HELP;
k[SDLK_MENU] = Keyboard::KEY_MENU;
k[SDLK_AC_SEARCH] = Keyboard::KEY_SEARCH;
k[SDLK_SELECT] = Keyboard::KEY_SELECT;
k[SDLK_STOP] = Keyboard::KEY_STOP;
k[SDLK_AGAIN] = Keyboard::KEY_AGAIN;
@@ -656,7 +683,7 @@ std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::createKeyMap()
k[SDLK_EJECT] = Keyboard::KEY_EJECT;
k[SDLK_SLEEP] = Keyboard::KEY_SLEEP;
#ifdef __ANDROID__
#ifdef LOVE_ANDROID
k[SDLK_AC_BACK] = Keyboard::KEY_ESCAPE;
#endif
@@ -33,11 +33,11 @@ namespace event
namespace sdl
{
static Event *instance = 0;
static Event *instance = nullptr;
static int poll_i(lua_State *L)
{
Message *m;
Message *m = nullptr;
while (instance->poll(m))
{
@@ -58,13 +58,13 @@ int w_pump(lua_State *)
int w_poll(lua_State *L)
{
lua_pushcclosure(L, &poll_i, 0);
lua_pushcclosure(L, poll_i, 0);
return 1;
}
int w_wait(lua_State *L)
{
Message *m;
Message *m = nullptr;
if ((m = instance->wait()))
{
@@ -78,7 +78,7 @@ int w_wait(lua_State *L)
int w_push(lua_State *L)
{
Message *m;
Message *m = nullptr;
bool success = (m = Message::fromLua(L, 1)) != NULL;
luax_pushboolean(L, success);
@@ -133,7 +133,7 @@ extern "C" int luaopen_love_event(lua_State *L)
w.name = "event";
w.flags = MODULE_T;
w.functions = functions;
w.types = 0;
w.types = nullptr;
return luax_register_module(L, w);
}
@@ -30,7 +30,7 @@
#include "SDL.h"
#include <string>
#ifdef __ANDROID__
#ifdef LOVE_ANDROID
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -58,7 +58,7 @@ namespace
return input.substr(getDriveDelim(input)+1);
}
#ifdef __ANDROID__
#ifdef LOVE_ANDROID
bool androidDirectoryExists(const char* path) {
SDL_Log ("Checking directory exists for %s", path);
struct stat s;
@@ -239,7 +239,7 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath)
else
save_path_full += save_path_relative;
#ifdef __ANDROID__
#ifdef LOVE_ANDROID
std::string internal_storage_path = SDL_AndroidGetInternalStoragePath();
std::string save_directory = internal_storage_path + "/save";
@@ -297,7 +297,7 @@ bool Filesystem::setSource(const char *source)
std::string new_search_path = source;
#ifdef __ANDROID__
#ifdef LOVE_ANDROID
if (!androidCreateStorageDirectories ()) {
SDL_Log ("Error creating storage directories!");
}
-1
View File
@@ -46,7 +46,6 @@ struct GlyphMetrics
int advance;
int bearingX;
int bearingY;
int spacing;
};
/**
+63 -78
View File
@@ -42,14 +42,11 @@ struct FramebufferStrategy
/// create a new framebuffer and texture
/**
* @param[out] framebuffer Framebuffer name
* @param[out] img Texture name
* @param[in] width Width of framebuffer
* @param[in] height Height of framebuffer
* @param[in] texture_type Type of the canvas texture.
* @param[out] framebuffer Framebuffer name
* @param[in] texture Texture name
* @return Creation status
*/
virtual GLenum createFBO(GLuint &, GLuint &, int, int, Canvas::TextureType)
virtual GLenum createFBO(GLuint &, GLuint)
{
return GL_FRAMEBUFFER_UNSUPPORTED;
}
@@ -70,9 +67,8 @@ struct FramebufferStrategy
/**
* @param[in] framebuffer Framebuffer name
* @param[in] depth_stencil Name for packed depth and stencil buffer
* @param[in] img Texture name
*/
virtual void deleteFBO(GLuint, GLuint, GLuint) {}
virtual void deleteFBO(GLuint, GLuint) {}
virtual void bindFBO(GLuint) {}
/// attach additional canvases to the active framebuffer for rendering
@@ -87,7 +83,7 @@ struct FramebufferStrategy
struct FramebufferStrategyCore : public FramebufferStrategy
{
virtual GLenum createFBO(GLuint &framebuffer, GLuint &img, int width, int height, Canvas::TextureType texture_type)
virtual GLenum createFBO(GLuint &framebuffer, GLuint texture)
{
// get currently bound fbo to reset to it later
GLint current_fbo;
@@ -97,32 +93,8 @@ struct FramebufferStrategyCore : public FramebufferStrategy
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// generate texture save target
GLint internalFormat;
GLenum format;
switch (texture_type)
{
case Canvas::TYPE_HDR:
internalFormat = GL_RGBA16F;
format = GL_FLOAT;
break;
case Canvas::TYPE_NORMAL:
default:
internalFormat = GL_RGBA;
format = GL_UNSIGNED_BYTE;
}
glGenTextures(1, &img);
gl.bindTexture(img);
Texture::Filter filter = Texture::getDefaultFilter();
gl.setTextureFilter(filter);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
0, GL_RGBA, format, NULL);
gl.bindTexture(0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, img, 0);
GL_TEXTURE_2D, texture, 0);
// check status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -149,9 +121,8 @@ struct FramebufferStrategyCore : public FramebufferStrategy
return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
}
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint img)
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil)
{
gl.deleteTexture(img);
if (depth_stencil != 0)
glDeleteRenderbuffers(1, &depth_stencil);
if (framebuffer != 0)
@@ -218,7 +189,7 @@ struct FramebufferStrategyCorePacked : public FramebufferStrategyCore
struct FramebufferStrategyPackedEXT : public FramebufferStrategy
{
virtual GLenum createFBO(GLuint &framebuffer, GLuint &img, int width, int height, Canvas::TextureType texture_type)
virtual GLenum createFBO(GLuint &framebuffer, GLuint texture)
{
GLint current_fbo;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &current_fbo);
@@ -227,32 +198,8 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
glGenFramebuffersEXT(1, &framebuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
// generate texture save target
GLint internalFormat;
GLenum format;
switch (texture_type)
{
case Canvas::TYPE_HDR:
internalFormat = GL_RGBA16F;
format = GL_FLOAT;
break;
case Canvas::TYPE_NORMAL:
default:
internalFormat = GL_RGBA;
format = GL_UNSIGNED_BYTE;
}
glGenTextures(1, &img);
gl.bindTexture(img);
Texture::Filter filter = Texture::getDefaultFilter();
gl.setTextureFilter(filter);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
0, GL_RGBA, format, NULL);
gl.bindTexture(0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, img, 0);
GL_TEXTURE_2D, texture, 0);
// check status
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
@@ -279,9 +226,8 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT;
}
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint img)
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil)
{
gl.deleteTexture(img);
if (depth_stencil != 0)
glDeleteRenderbuffersEXT(1, &depth_stencil);
if (framebuffer != 0)
@@ -347,9 +293,9 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
bool isSupported()
{
GLuint fb = 0, stencil = 0, img = 0;
GLenum status = createFBO(fb, img, 2, 2, Canvas::TYPE_NORMAL);
deleteFBO(fb, stencil, img);
GLuint fb = 0, stencil = 0;
GLenum status = createFBO(fb, 0);
deleteFBO(fb, stencil);
return status == GL_FRAMEBUFFER_COMPLETE;
}
};
@@ -391,8 +337,8 @@ static int maxDrawBuffers = 0;
Canvas::Canvas(int width, int height, TextureType texture_type)
: fbo(0)
, texture(0)
, depth_stencil(0)
, img(0)
, texture_type(texture_type)
{
this->width = width;
@@ -437,7 +383,7 @@ Canvas::~Canvas()
bool Canvas::loadVolatile()
{
fbo = depth_stencil = img = 0;
fbo = depth_stencil = texture = 0;
// glTexImage2D is guaranteed to error in this case.
if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize())
@@ -446,20 +392,59 @@ bool Canvas::loadVolatile()
return false;
}
status = strategy->createFBO(fbo, img, width, height, texture_type);
if (status != GL_FRAMEBUFFER_COMPLETE)
return false;
glGenTextures(1, &texture);
gl.bindTexture(texture);
setFilter(filter);
setWrap(wrap);
GLint internalformat;
GLenum textype;
switch (texture_type)
{
case TYPE_HDR:
internalformat = GL_RGBA16F;
textype = GL_FLOAT;
break;
case TYPE_NORMAL:
default:
internalformat = GL_RGBA8;
textype = GL_UNSIGNED_BYTE;
}
while (glGetError() != GL_NO_ERROR)
/* Clear the error buffer. */;
glTexImage2D(GL_TEXTURE_2D,
0,
internalformat,
width, height,
0,
GL_RGBA,
textype,
nullptr);
if (glGetError() != GL_NO_ERROR)
{
status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return false;
}
status = strategy->createFBO(fbo, texture);
if (status != GL_FRAMEBUFFER_COMPLETE)
return false;
clear(Color(0, 0, 0, 0));
return true;
}
void Canvas::unloadVolatile()
{
strategy->deleteFBO(fbo, depth_stencil, img);
fbo = depth_stencil = img = 0;
strategy->deleteFBO(fbo, depth_stencil);
gl.deleteTexture(texture);
fbo = depth_stencil = texture = 0;
for (size_t i = 0; i < attachedCanvases.size(); i++)
attachedCanvases[i]->release();
@@ -513,25 +498,25 @@ void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy
void Canvas::setFilter(const Texture::Filter &f)
{
filter = f;
gl.bindTexture(img);
gl.bindTexture(texture);
gl.setTextureFilter(filter);
}
void Canvas::setWrap(const Texture::Wrap &w)
{
wrap = w;
gl.bindTexture(img);
gl.bindTexture(texture);
gl.setTextureWrap(wrap);
}
GLuint Canvas::getGLTexture() const
{
return img;
return texture;
}
void Canvas::predraw() const
{
gl.bindTexture(img);
gl.bindTexture(texture);
}
void Canvas::setupGrab()
@@ -113,8 +113,8 @@ public:
private:
GLuint fbo;
GLuint texture;
GLuint depth_stencil;
GLuint img;
TextureType texture_type;
+35 -4
View File
@@ -46,6 +46,7 @@ Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter)
, lineHeight(1)
, mSpacing(1)
, filter(filter)
, useSpacesAsTab(false)
{
this->filter.mipmap = Texture::FILTER_NONE;
@@ -67,13 +68,16 @@ Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter)
textureWidth = TEXTURE_WIDTHS[textureSizeIndex];
textureHeight = TEXTURE_HEIGHTS[textureSizeIndex];
love::font::GlyphData *gd = 0;
love::font::GlyphData *gd = nullptr;
try
{
gd = r->getGlyphData(32);
gd = r->getGlyphData(32); // Space character.
type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA) ? FONT_TRUETYPE : FONT_IMAGE;
if (!r->hasGlyph(9)) // No tab character in the Rasterizer.
useSpacesAsTab = true;
loadVolatile();
}
catch (love::Exception &)
@@ -172,7 +176,26 @@ void Font::createTexture()
Font::Glyph *Font::addGlyph(uint32 glyph)
{
love::font::GlyphData *gd = rasterizer->getGlyphData(glyph);
love::font::GlyphData *gd = nullptr;
// Use spaces for the tab 'glyph'.
if (glyph == 9 && useSpacesAsTab)
{
love::font::GlyphData *spacegd = rasterizer->getGlyphData(32);
love::font::GlyphMetrics gm = {};
gm.advance = spacegd->getAdvance() * SPACES_PER_TAB;
gm.bearingX = spacegd->getBearingX();
gm.bearingY = spacegd->getBearingY();
love::font::GlyphData::Format f = spacegd->getFormat();
spacegd->release();
gd = new love::font::GlyphData(glyph, gm, f);
}
else
gd = rasterizer->getGlyphData(glyph);
int w = gd->getWidth();
int h = gd->getHeight();
@@ -186,7 +209,15 @@ Font::Glyph *Font::addGlyph(uint32 glyph)
if (textureY + h + TEXTURE_PADDING > textureHeight)
{
// totally out of space - new texture!
createTexture();
try
{
createTexture();
}
catch (love::Exception &)
{
gd->release();
throw;
}
}
Glyph *g = new Glyph;
+7 -2
View File
@@ -202,14 +202,19 @@ private:
FontType type;
Texture::Filter filter;
int textureX, textureY;
int rowHeight;
bool useSpacesAsTab;
static const int NUM_TEXTURE_SIZES = 7;
static const int TEXTURE_WIDTHS[NUM_TEXTURE_SIZES];
static const int TEXTURE_HEIGHTS[NUM_TEXTURE_SIZES];
static const int TEXTURE_PADDING = 1;
int textureX, textureY;
int rowHeight;
// This will be used if the Rasterizer doesn't have a tab character itself.
static const int SPACES_PER_TAB = 4;
}; // Font
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -119,6 +119,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p)
, emissionRate(p.emissionRate)
, emitCounter(0.0f)
, position(p.position)
, prevPosition(p.prevPosition)
, areaSpreadDistribution(p.areaSpreadDistribution)
, areaSpread(p.areaSpread)
, lifetime(p.lifetime)
@@ -215,14 +216,14 @@ uint32 ParticleSystem::getBufferSize() const
return maxParticles;
}
void ParticleSystem::addParticle()
void ParticleSystem::addParticle(float t)
{
if (isFull())
return;
// Gets a free particle and updates the allocation pointer.
particle *p = pFree++;
initParticle(p);
initParticle(p, t);
switch (insertMode)
{
@@ -241,10 +242,13 @@ void ParticleSystem::addParticle()
activeParticles++;
}
void ParticleSystem::initParticle(particle *p)
void ParticleSystem::initParticle(particle *p, float t)
{
float min,max;
// Linearly interpolate between the previous and current emitter position.
love::Vector pos = prevPosition + (position - prevPosition) * t;
min = particleLifeMin;
max = particleLifeMax;
if (min == max)
@@ -253,8 +257,8 @@ void ParticleSystem::initParticle(particle *p)
p->life = (float) rng.random(min, max);
p->lifetime = p->life;
p->position[0] = position.getX();
p->position[1] = position.getY();
p->position[0] = pos.x;
p->position[1] = pos.y;
switch (areaSpreadDistribution)
{
@@ -275,7 +279,7 @@ void ParticleSystem::initParticle(particle *p)
max = direction + spread/2.0f;
p->direction = (float) rng.random(min, max);
p->origin = position;
p->origin = pos;
min = speedMin;
max = speedMax;
@@ -758,7 +762,7 @@ void ParticleSystem::emit(uint32 num)
num = std::min(num, maxParticles - activeParticles);
while(num--)
addParticle();
addParticle(1.0f);
}
bool ParticleSystem::isActive() const
@@ -860,25 +864,6 @@ void ParticleSystem::update(float dt)
if (pMem == nullptr || dt == 0.0f)
return;
// Make some more particles.
if (active)
{
float rate = 1.0f / emissionRate; // the amount of time between each particle emit
emitCounter += dt;
while (emitCounter > rate)
{
addParticle();
emitCounter -= rate;
}
/*int particles = (int)(emissionRate * dt);
for (int i = 0; i != particles; i++)
add();*/
life -= dt;
if (lifetime != -1 && life < 0)
stop();
}
// Traverse all particles and update.
particle *p = pHead;
@@ -953,6 +938,28 @@ void ParticleSystem::update(float dt)
p = p->next;
}
}
// Make some more particles.
if (active)
{
float rate = 1.0f / emissionRate; // the amount of time between each particle emit
emitCounter += dt;
float total = emitCounter - rate;
while (emitCounter > rate)
{
addParticle(1.0f - (emitCounter - rate) / total);
emitCounter -= rate;
}
/*int particles = (int)(emissionRate * dt);
for (int i = 0; i != particles; i++)
add();*/
life -= dt;
if (lifetime != -1 && life < 0)
stop();
}
prevPosition = position;
}
bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
@@ -558,6 +558,7 @@ protected:
// The relative position of the particle emitter.
love::Vector position;
love::Vector prevPosition;
// Emission area spread.
AreaSpreadDistribution areaSpreadDistribution;
@@ -614,11 +615,11 @@ protected:
void createBuffers(size_t size);
void deleteBuffers();
void addParticle();
void addParticle(float t);
particle *removeParticle(particle *p);
// Called by addParticle.
void initParticle(particle *p);
void initParticle(particle *p, float t);
void insertTop(particle *p);
void insertBottom(particle *p);
void insertRandom(particle *p);
@@ -127,6 +127,11 @@ VBO::VBO(size_t size, GLenum target, GLenum usage, MemoryBacking backing)
if (!(GLAD_ARB_vertex_buffer_object || GLAD_VERSION_1_5 || GLAD_ES_VERSION_2_0))
throw love::Exception("Not supported");
// FIXME:
// ES2 can't do glGetBufferSubData.
if (GLAD_ES_VERSION_2_0)
backing = BACKING_FULL;
if (getMemoryBacking() == BACKING_FULL)
memory_map = malloc(getSize());
@@ -34,22 +34,21 @@ Canvas *luax_checkcanvas(lua_State *L, int idx)
int w_Canvas_renderTo(lua_State *L)
{
// As startGrab() clears the framebuffer, better not allow
// grabbing inside another grabbing
if (Canvas::current != NULL)
{
Canvas::bindDefaultCanvas();
return luaL_error(L, "Current render target not the default canvas!");
}
Canvas *canvas = luax_checkcanvas(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION);
// Save the current Canvas so we can restore it when we're done.
Canvas *oldcanvas = Canvas::current;
EXCEPT_GUARD(canvas->startGrab();)
lua_settop(L, 2); // make sure the function is on top of the stack
lua_call(L, 0, 0);
canvas->stopGrab();
if (oldcanvas != nullptr)
oldcanvas->startGrab(oldcanvas->getAttachedCanvases());
else
Canvas::bindDefaultCanvas();
return 0;
}
@@ -1152,8 +1152,9 @@ int w_line(lua_State *L)
args = lua_objlen(L, 1);
is_table = true;
}
if (args % 2 != 0)
return luaL_error(L, "Number of vertices must be a multiple of two");
return luaL_error(L, "Number of vertex components must be a multiple of two");
else if (args < 4)
return luaL_error(L, "Need at least two vertices to draw a line");
@@ -1254,7 +1255,7 @@ int w_polygon(lua_State *L)
}
if (args % 2 != 0)
return luaL_error(L, "Number of vertices must be a multiple of two");
return luaL_error(L, "Number of vertex components must be a multiple of two");
else if (args < 6)
return luaL_error(L, "Need at least three vertices to draw a polygon");
@@ -175,6 +175,7 @@ StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM>::Entry Keyboard::keyEntries[] =
{"execute", Keyboard::KEY_EXECUTE},
{"help", Keyboard::KEY_HELP},
{"menu", Keyboard::KEY_MENU},
{"search", Keyboard::KEY_SEARCH},
{"select", Keyboard::KEY_SELECT},
{"stop", Keyboard::KEY_STOP},
{"again", Keyboard::KEY_AGAIN},
+1
View File
@@ -175,6 +175,7 @@ public:
KEY_EXECUTE,
KEY_HELP,
KEY_MENU,
KEY_SEARCH,
KEY_SELECT,
KEY_STOP,
KEY_AGAIN,
@@ -219,6 +219,7 @@ std::map<Keyboard::Key, SDL_Keycode> Keyboard::createKeyMap()
k[Keyboard::KEY_EXECUTE] = SDLK_EXECUTE;
k[Keyboard::KEY_HELP] = SDLK_HELP;
k[Keyboard::KEY_MENU] = SDLK_MENU;
k[Keyboard::KEY_SEARCH] = SDLK_AC_SEARCH;
k[Keyboard::KEY_SELECT] = SDLK_SELECT;
k[Keyboard::KEY_STOP] = SDLK_STOP;
k[Keyboard::KEY_AGAIN] = SDLK_AGAIN;
+8
View File
@@ -97,6 +97,9 @@ extern "C"
#if defined(LOVE_ENABLE_THREAD)
extern int luaopen_love_thread(lua_State*);
#endif
#if defined(LOVE_ENABLE_TOUCH)
extern int luaopen_love_touch(lua_State*);
#endif
#if defined(LOVE_ENABLE_WINDOW)
extern int luaopen_love_window(lua_State*);
#endif
@@ -149,6 +152,9 @@ static const luaL_Reg modules[] = {
#if defined(LOVE_ENABLE_THREAD)
{ "love.thread", luaopen_love_thread },
#endif
#if defined(LOVE_ENABLE_TOUCH)
{ "love.touch", luaopen_love_touch },
#endif
#if defined(LOVE_ENABLE_WINDOW)
{ "love.window", luaopen_love_window },
#endif
@@ -207,6 +213,8 @@ int luaopen_love(lua_State * L)
lua_pushstring(L, "Windows");
#elif defined(LOVE_MACOSX)
lua_pushstring(L, "OS X");
#elif defined(LOVE_ANDROID)
lua_pushstring(L, "Android");
#elif defined(LOVE_LINUX)
lua_pushstring(L, "Linux");
#else
+47 -4
View File
@@ -32,6 +32,39 @@ namespace mouse
namespace sdl
{
// SDL reports mouse coordinates in the window coordinate system in OS X, but
// we want them in pixel coordinates (may be different with high-DPI enabled.)
static void windowToPixelCoords(int *x, int *y)
{
double scale = 1.0;
love::window::Window *window = love::window::sdl::Window::getSingleton();
if (window != nullptr)
scale = window->getPixelScale();
if (x != nullptr)
*x = int(double(*x) * scale);
if (y != nullptr)
*y = int(double(*y) * scale);
}
// And vice versa for setting mouse coordinates.
static void pixelToWindowCoords(int *x, int *y)
{
double scale = 1.0;
love::window::Window *window = love::window::sdl::Window::getSingleton();
if (window != nullptr)
scale = window->getPixelScale();
if (x != nullptr)
*x = int(double(*x) / scale);
if (y != nullptr)
*y = int(double(*y) / scale);
}
const char *Mouse::getName() const
{
return "love.mouse.sdl";
@@ -98,30 +131,40 @@ love::mouse::Cursor *Mouse::getCursor() const
int Mouse::getX() const
{
int x;
SDL_GetMouseState(&x, 0);
SDL_GetMouseState(&x, nullptr);
windowToPixelCoords(&x, nullptr);
return x;
}
int Mouse::getY() const
{
int y;
SDL_GetMouseState(0, &y);
SDL_GetMouseState(nullptr, &y);
windowToPixelCoords(nullptr, &y);
return y;
}
void Mouse::getPosition(int &x, int &y) const
{
SDL_GetMouseState(&x, &y);
int mx, my;
SDL_GetMouseState(&mx, &my);
windowToPixelCoords(&mx, &my);
x = mx;
y = my;
}
void Mouse::setPosition(int x, int y)
{
love::window::Window *window = love::window::sdl::Window::getSingleton();
SDL_Window *handle = NULL;
SDL_Window *handle = nullptr;
if (window)
handle = (SDL_Window *) window->getHandle();
pixelToWindowCoords(&x, &y);
SDL_WarpMouseInWindow(handle, x, y);
}
@@ -93,8 +93,9 @@ EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2)
int Physics::newPolygonShape(lua_State *L)
{
int argc = lua_gettop(L);
if (argc%2 != 0)
return luaL_error(L, "Number of vertices must be a multiple of two.");
if (argc % 2 != 0)
return luaL_error(L, "Number of vertex components must be a multiple of two.");
// 3 to 8 (b2_maxPolygonVertices) vertices
int vcount = argc / 2;
if (vcount < 3)
+2
View File
@@ -31,6 +31,8 @@ std::string System::getOS() const
return "OS X";
#elif LOVE_WINDOWS
return "Windows";
#elif LOVE_ANDROID
return "Android";
#elif LOVE_LINUX
return "Linux";
#else
+10 -5
View File
@@ -110,15 +110,20 @@ void LuaThread::onError()
if (!event)
return;
std::vector<Variant *> vargs;
Proxy p;
p.flags = THREAD_THREAD_T;
p.data = this;
Variant *arg1 = new Variant(THREAD_THREAD_ID, &p);
Variant *arg2 = new Variant(error.c_str(), error.length());
event::Message *msg = new event::Message("threaderror", arg1, arg2);
arg1->release();
arg2->release();
vargs.push_back(new Variant(THREAD_THREAD_ID, &p));
vargs.push_back(new Variant(error.c_str(), error.length()));
event::Message *msg = new event::Message("threaderror", vargs);
for (auto it = vargs.begin(); it != vargs.end(); ++it)
(*it)->release();
event->push(msg);
msg->release();
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2006-2014 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.
**/
#ifndef LOVE_TOUCH_TOUCH_H
#define LOVE_TOUCH_TOUCH_H
// LOVE
#include "common/int.h"
#include "common/Object.h"
#include "common/Module.h"
// C++
#include <vector>
#include <limits>
namespace love
{
namespace touch
{
class Touch : public Module
{
public:
struct TouchInfo
{
int64 id; // Only unique for the duration of the touch-press.
float x; // Normalized to [0, 1].
float y; // Normalized to [0, 1].
float pressure; // Normalized to [0, 1].
};
virtual ~Touch() {}
/**
* Gets the number of current touch presses.
**/
virtual int getTouchCount() const = 0;
/**
* Gets information about a touch press. The index is unstable and should
* not be relied on being the same in between calls.
**/
virtual TouchInfo getTouch(int index) const = 0;
}; // Touch
} // touch
} // love
#endif // LOVE_TOUCH_TOUCH_H
+93
View File
@@ -0,0 +1,93 @@
/**
* Copyright (c) 2006-2014 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
// LOVE
#include "common/config.h"
#include "common/Exception.h"
#include "Touch.h"
// SDL
#include <SDL_touch.h>
namespace love
{
namespace touch
{
namespace sdl
{
int Touch::getTouchCount() const
{
int count = 0;
for (int i = 0; i < SDL_GetNumTouchDevices(); i++)
count += SDL_GetNumTouchFingers(SDL_GetTouchDevice(i));
return count;
}
Touch::TouchInfo Touch::getTouch(int index) const
{
SDL_TouchID deviceID = 0;
int touchcount = 0;
int fingerindex = -1;
// Find the device and finger index from the given external index.
for (int i = 0; i < SDL_GetNumTouchDevices(); i++)
{
deviceID = SDL_GetTouchDevice(i);
int fingercount = SDL_GetNumTouchFingers(deviceID);
if (index < touchcount + fingercount)
{
fingerindex = index - touchcount;
break;
}
touchcount += fingercount;
}
if (fingerindex < 0)
throw love::Exception("Invalid touch index.");
SDL_Finger *finger = SDL_GetTouchFinger(deviceID, fingerindex);
if (finger == nullptr)
throw love::Exception("Cannot get touch info.");
TouchInfo info = {};
info.id = (int64) finger->id;
info.x = finger->x;
info.y = finger->y;
info.pressure = finger->pressure;
return info;
}
const char *Touch::getName() const
{
return "love.touch.sdl";
}
} // sdl
} // touch
} // love
+52
View File
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2006-2014 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.
**/
#ifndef LOVE_TOUCH_SDL_TOUCH_H
#define LOVE_TOUCH_SDL_TOUCH_H
// LOVE
#include "touch/Touch.h"
namespace love
{
namespace touch
{
namespace sdl
{
class Touch : public love::touch::Touch
{
public:
virtual ~Touch() {}
virtual int getTouchCount() const;
virtual TouchInfo getTouch(int index) const;
// Implements Module.
virtual const char *getName() const;
}; // Touch
} // sdl
} // touch
} // love
#endif // LOVE_TOUCH_SDL_TOUCH_H
+84
View File
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2006-2014 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.
**/
#include "common/config.h"
// LOVE
#include "wrap_Touch.h"
#include "sdl/Touch.h"
namespace love
{
namespace touch
{
static Touch *instance = nullptr;
int w_getTouchCount(lua_State *L)
{
lua_pushinteger(L, instance->getTouchCount());
return 1;
}
int w_getTouch(lua_State *L)
{
int index = luaL_checkint(L, 1) - 1;
Touch::TouchInfo info;
EXCEPT_GUARD(info = instance->getTouch(index);)
// Lets hope the ID can be accurately represented in a Lua number...
lua_pushnumber(L, (lua_Number) info.id);
lua_pushnumber(L, info.x);
lua_pushnumber(L, info.y);
lua_pushnumber(L, info.pressure);
return 4;
}
static const luaL_Reg functions[] =
{
{ "getTouchCount", w_getTouchCount },
{ "getTouch", w_getTouch },
{ 0, 0 }
};
extern "C" int luaopen_love_touch(lua_State *L)
{
if (instance == nullptr)
{
EXCEPT_GUARD(instance = new love::touch::sdl::Touch();)
}
else
instance->retain();
WrappedModule w;
w.module = instance;
w.name = "touch";
w.flags = MODULE_T;
w.functions = functions;
w.types = nullptr;
return luax_register_module(L, w);
}
} // touch
} // love
+40
View File
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2006-2014 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.
**/
#ifndef LOVE_TOUCH_WRAP_TOUCH_H
#define LOVE_TOUCH_WRAP_TOUCH_H
// LOVE
#include "Touch.h"
#include "common/runtime.h"
namespace love
{
namespace touch
{
int w_getTouchCount(lua_State *L);
int w_getTouch(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_touch(lua_State *L);
} // touch
} // love
#endif // LOVE_TOUCH_WRAP_TOUCH_H
+21 -19
View File
@@ -26,19 +26,19 @@ namespace love
namespace window
{
Window *Window::singleton = NULL;
Window *Window::singleton = nullptr;
Window::~Window()
{
if (singleton == this)
singleton = NULL;
singleton = nullptr;
}
void Window::swapBuffers()
{
}
WindowAttributes::WindowAttributes()
WindowSettings::WindowSettings()
: fullscreen(false)
, fstype(Window::FULLSCREEN_TYPE_NORMAL)
, vsync(true)
@@ -49,6 +49,7 @@ WindowAttributes::WindowAttributes()
, borderless(false)
, centered(true)
, display(0)
, highdpi(false)
{
}
@@ -62,31 +63,32 @@ bool Window::getConstant(Window::FullscreenType in, const char *&out)
return fullscreenTypes.find(in, out);
}
bool Window::getConstant(const char *in, Window::Attribute &out)
bool Window::getConstant(const char *in, Window::Setting &out)
{
return attributes.find(in, out);
return settings.find(in, out);
}
bool Window::getConstant(Window::Attribute in, const char *&out)
bool Window::getConstant(Window::Setting in, const char *&out)
{
return attributes.find(in, out);
return settings.find(in, out);
}
StringMap<Window::Attribute, Window::ATTRIB_MAX_ENUM>::Entry Window::attributeEntries[] =
StringMap<Window::Setting, Window::SETTING_MAX_ENUM>::Entry Window::settingEntries[] =
{
{"fullscreen", ATTRIB_FULLSCREEN},
{"fullscreentype", ATTRIB_FULLSCREEN_TYPE},
{"vsync", ATTRIB_VSYNC},
{"fsaa", ATTRIB_FSAA},
{"resizable", ATTRIB_RESIZABLE},
{"minwidth", ATTRIB_MIN_WIDTH},
{"minheight", ATTRIB_MIN_HEIGHT},
{"borderless", ATTRIB_BORDERLESS},
{"centered", ATTRIB_CENTERED},
{"display", ATTRIB_DISPLAY}
{"fullscreen", SETTING_FULLSCREEN},
{"fullscreentype", SETTING_FULLSCREEN_TYPE},
{"vsync", SETTING_VSYNC},
{"fsaa", SETTING_FSAA},
{"resizable", SETTING_RESIZABLE},
{"minwidth", SETTING_MIN_WIDTH},
{"minheight", SETTING_MIN_HEIGHT},
{"borderless", SETTING_BORDERLESS},
{"centered", SETTING_CENTERED},
{"display", SETTING_DISPLAY},
{"highdpi", SETTING_HIGHDPI},
};
StringMap<Window::Attribute, Window::ATTRIB_MAX_ENUM> Window::attributes(Window::attributeEntries, sizeof(Window::attributeEntries));
StringMap<Window::Setting, Window::SETTING_MAX_ENUM> Window::settings(Window::settingEntries, sizeof(Window::settingEntries));
StringMap<Window::FullscreenType, Window::FULLSCREEN_TYPE_MAX_ENUM>::Entry Window::fullscreenTypeEntries[] =
{
+29 -23
View File
@@ -37,26 +37,27 @@ namespace window
// Forward-declared so it can be used in the class methods. We can't define the
// whole thing here because it uses the Window::Type enum.
struct WindowAttributes;
struct WindowSettings;
class Window : public Module
{
public:
// Types of window attributes.
enum Attribute
// Different window settings.
enum Setting
{
ATTRIB_FULLSCREEN,
ATTRIB_FULLSCREEN_TYPE,
ATTRIB_VSYNC,
ATTRIB_FSAA,
ATTRIB_RESIZABLE,
ATTRIB_MIN_WIDTH,
ATTRIB_MIN_HEIGHT,
ATTRIB_BORDERLESS,
ATTRIB_CENTERED,
ATTRIB_DISPLAY,
ATTRIB_MAX_ENUM
SETTING_FULLSCREEN,
SETTING_FULLSCREEN_TYPE,
SETTING_VSYNC,
SETTING_FSAA,
SETTING_RESIZABLE,
SETTING_MIN_WIDTH,
SETTING_MIN_HEIGHT,
SETTING_BORDERLESS,
SETTING_CENTERED,
SETTING_DISPLAY,
SETTING_HIGHDPI,
SETTING_MAX_ENUM
};
enum FullscreenType
@@ -74,8 +75,8 @@ public:
virtual ~Window();
virtual bool setWindow(int width = 800, int height = 600, WindowAttributes *attribs = 0) = 0;
virtual void getWindow(int &width, int &height, WindowAttributes &attribs) = 0;
virtual bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr) = 0;
virtual void getWindow(int &width, int &height, WindowSettings &settings) = 0;
virtual bool setFullscreen(bool fullscreen, FullscreenType fstype) = 0;
virtual bool setFullscreen(bool fullscreen) = 0;
@@ -113,14 +114,16 @@ public:
virtual void setMouseGrab(bool grab) = 0;
virtual bool isMouseGrabbed() const = 0;
virtual double getPixelScale() const = 0;
virtual const void *getHandle() const = 0;
//virtual static Window *createSingleton() = 0;
//virtual static Window *getSingleton() = 0;
// No virtual statics, of course, but you are supposed to implement these statics.
static bool getConstant(const char *in, Attribute &out);
static bool getConstant(Attribute in, const char *&out);
static bool getConstant(const char *in, Setting &out);
static bool getConstant(Setting in, const char *&out);
static bool getConstant(const char *in, FullscreenType &out);
static bool getConstant(FullscreenType in, const char *&out);
@@ -131,17 +134,18 @@ protected:
private:
static StringMap<Attribute, ATTRIB_MAX_ENUM>::Entry attributeEntries[];
static StringMap<Attribute, ATTRIB_MAX_ENUM> attributes;
static StringMap<Setting, SETTING_MAX_ENUM>::Entry settingEntries[];
static StringMap<Setting, SETTING_MAX_ENUM> settings;
static StringMap<FullscreenType, FULLSCREEN_TYPE_MAX_ENUM>::Entry fullscreenTypeEntries[];
static StringMap<FullscreenType, FULLSCREEN_TYPE_MAX_ENUM> fullscreenTypes;
}; // Window
struct WindowAttributes
struct WindowSettings
{
WindowAttributes();
WindowSettings();
bool fullscreen; // = false
Window::FullscreenType fstype; // = FULLSCREEN_TYPE_NORMAL
bool vsync; // = true
@@ -152,7 +156,9 @@ struct WindowAttributes
bool borderless; // = false
bool centered; // = true
int display; // = 0
}; // WindowFlags
bool highdpi; // false
}; // WindowSettings
} // window
} // love
+110 -41
View File
@@ -28,6 +28,9 @@
#include <vector>
#include <algorithm>
// C
#include <cstring>
namespace love
{
namespace window
@@ -63,21 +66,21 @@ Window::~Window()
Window::_currentMode::_currentMode()
: width(800)
, height(600)
, attribs()
, settings()
, icon(0)
{
}
bool Window::setWindow(int width, int height, WindowAttributes *attribs)
bool Window::setWindow(int width, int height, WindowSettings *settings)
{
graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
if (gfx)
if (gfx != nullptr)
gfx->unSetMode();
WindowAttributes f;
WindowSettings f;
if (attribs)
f = *attribs;
if (settings)
f = *settings;
f.minwidth = std::max(f.minwidth, 1);
f.minheight = std::max(f.minheight, 1);
@@ -116,15 +119,28 @@ bool Window::setWindow(int width, int height, WindowAttributes *attribs)
if (f.borderless)
sdlflags |= SDL_WINDOW_BORDERLESS;
#if SDL_VERSION_ATLEAST(2,0,1)
if (f.highdpi)
sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI;
#endif
// Destroy and recreate the window if the dimensions or flags have changed.
if (window)
{
int curdisplay = SDL_GetWindowDisplayIndex(window);
Uint32 wflags = SDL_GetWindowFlags(window);
wflags &= (SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS);
Uint32 testflags = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP
| SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS;
#if SDL_VERSION_ATLEAST(2,0,1)
testflags |= SDL_WINDOW_ALLOW_HIGHDPI;
#endif
wflags &= testflags;
if (sdlflags != wflags || width != curMode.width || height != curMode.height
|| f.display != curdisplay || f.fsaa != curMode.attribs.fsaa)
|| f.display != curdisplay || f.fsaa != curMode.settings.fsaa)
{
SDL_DestroyWindow(window);
window = 0;
@@ -185,11 +201,18 @@ bool Window::setWindow(int width, int height, WindowAttributes *attribs)
created = true;
updateAttributes(f);
updateSettings(f);
if (gfx)
if (gfx != nullptr)
{
if (!gfx->setMode(curMode.width, curMode.height))
int width = curMode.width;
int height = curMode.height;
#if SDL_VERSION_ATLEAST(2,0,1)
SDL_GL_GetDrawableSize(window, &width, &height);
#endif
if (!gfx->setMode(width, height))
displayError("Could not set graphics mode", "Unsupported OpenGL version?");
}
@@ -256,8 +279,8 @@ bool Window::setContext(int fsaa, bool vsync)
fsaa = (buffers > 0) ? samples : 0;
}
curMode.attribs.fsaa = fsaa;
curMode.attribs.vsync = SDL_GL_GetSwapInterval() != 0;
curMode.settings.fsaa = fsaa;
curMode.settings.vsync = SDL_GL_GetSwapInterval() != 0;
return true;
}
@@ -276,8 +299,19 @@ void Window::setWindowGLAttributes(int fsaa) const
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0);
const char *glesHint = SDL_GetHint("LOVE_GRAPHICS_USE_OPENGLES");
if (glesHint && *glesHint == '1')
bool tryES2 = false;
const char *driver = SDL_GetCurrentVideoDriver();
// We always want to use OpenGL ES on certain video backends.
if (driver && (strstr(driver, "RPI") || strstr(driver, "Android") || strstr(driver, "uikit")))
tryES2 = true;
const char *hint = SDL_GetHint("LOVE_GRAPHICS_USE_OPENGLES");
if (hint)
tryES2 = (*hint) != '0';
if (tryES2)
{
// Use OpenGL ES 2+.
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
@@ -293,7 +327,7 @@ void Window::setWindowGLAttributes(int fsaa) const
}
}
void Window::updateAttributes(const WindowAttributes &newattribs)
void Window::updateSettings(const WindowSettings &newsettings)
{
Uint32 wflags = SDL_GetWindowFlags(window);
@@ -302,39 +336,45 @@ void Window::updateAttributes(const WindowAttributes &newattribs)
if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
{
curMode.attribs.fullscreen = true;
curMode.attribs.fstype = FULLSCREEN_TYPE_DESKTOP;
curMode.settings.fullscreen = true;
curMode.settings.fstype = FULLSCREEN_TYPE_DESKTOP;
}
else if ((wflags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN)
{
curMode.attribs.fullscreen = true;
curMode.attribs.fstype = FULLSCREEN_TYPE_NORMAL;
curMode.settings.fullscreen = true;
curMode.settings.fstype = FULLSCREEN_TYPE_NORMAL;
}
else
{
curMode.attribs.fullscreen = false;
curMode.attribs.fstype = newattribs.fstype;
curMode.settings.fullscreen = false;
curMode.settings.fstype = newsettings.fstype;
}
// The min width/height is set to 0 internally in SDL when in fullscreen.
if (curMode.attribs.fullscreen)
if (curMode.settings.fullscreen)
{
curMode.attribs.minwidth = newattribs.minwidth;
curMode.attribs.minheight = newattribs.minheight;
curMode.settings.minwidth = newsettings.minwidth;
curMode.settings.minheight = newsettings.minheight;
}
else
SDL_GetWindowMinimumSize(window, &curMode.attribs.minwidth, &curMode.attribs.minheight);
SDL_GetWindowMinimumSize(window, &curMode.settings.minwidth, &curMode.settings.minheight);
curMode.attribs.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0;
curMode.attribs.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0;
curMode.attribs.centered = newattribs.centered;
curMode.attribs.display = std::max(SDL_GetWindowDisplayIndex(window), 0);
curMode.settings.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0;
curMode.settings.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0;
curMode.settings.centered = newsettings.centered;
curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0);
#if SDL_VERSION_ATLEAST(2,0,1)
curMode.settings.highdpi = (wflags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
#else
curMode.settings.highdpi = false;
#endif
// Only minimize on focus loss if the window is in exclusive-fullscreen
// mode (mimics behaviour of SDL 2.0.2+).
// In OS X we always disable this to prevent dock minimization weirdness.
#ifndef LOVE_MACOSX
if (curMode.attribs.fullscreen && curMode.attribs.fstype == FULLSCREEN_TYPE_NORMAL)
if (curMode.settings.fullscreen && curMode.settings.fstype == FULLSCREEN_TYPE_NORMAL)
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1");
else
#endif
@@ -351,15 +391,15 @@ void Window::displayError(const std::string &title, const std::string &text) con
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title.c_str(), text.c_str(), window);
}
void Window::getWindow(int &width, int &height, WindowAttributes &attribs)
void Window::getWindow(int &width, int &height, WindowSettings &settings)
{
// Window position may be different from creation - update display index.
if (window)
curMode.attribs.display = std::max(SDL_GetWindowDisplayIndex(window), 0);
curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0);
width = curMode.width;
height = curMode.height;
attribs = curMode.attribs;
settings = curMode.settings;
}
bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
@@ -367,9 +407,9 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
if (!window)
return false;
WindowAttributes newattribs = curMode.attribs;
newattribs.fullscreen = fullscreen;
newattribs.fstype = fstype;
WindowSettings newsettings = curMode.settings;
newsettings.fullscreen = fullscreen;
newsettings.fstype = fstype;
Uint32 sdlflags = 0;
@@ -393,12 +433,21 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
if (SDL_SetWindowFullscreen(window, sdlflags) == 0)
{
SDL_GL_MakeCurrent(window, context);
updateAttributes(newattribs);
updateSettings(newsettings);
// Update the viewport size now instead of waiting for event polling.
graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics.");
if (gfx)
gfx->setViewportSize(curMode.width, curMode.height);
if (gfx != nullptr)
{
int width = curMode.width;
int height = curMode.height;
#if SDL_VERSION_ATLEAST(2,0,1)
SDL_GL_GetDrawableSize(window, &width, &height);
#endif
gfx->setViewportSize(width, height);
}
return true;
}
@@ -408,7 +457,7 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
bool Window::setFullscreen(bool fullscreen)
{
return setFullscreen(fullscreen, curMode.attribs.fstype);
return setFullscreen(fullscreen, curMode.settings.fstype);
}
int Window::getDisplayCount() const
@@ -591,6 +640,26 @@ bool Window::isMouseGrabbed() const
return mouseGrabbed;
}
double Window::getPixelScale() const
{
double scale = 1.0;
#if SDL_VERSION_ATLEAST(2,0,1)
if (window)
{
int wheight;
SDL_GetWindowSize(window, nullptr, &wheight);
int dheight = wheight;
SDL_GL_GetDrawableSize(window, nullptr, &dheight);
scale = (double) dheight / wheight;
}
#endif
return scale;
}
const void *Window::getHandle() const
{
return window;
+7 -5
View File
@@ -41,8 +41,8 @@ public:
Window();
~Window();
bool setWindow(int width = 800, int height = 600, WindowAttributes *attribs = 0);
void getWindow(int &width, int &height, WindowAttributes &attribs);
bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr);
void getWindow(int &width, int &height, WindowSettings &settings);
bool setFullscreen(bool fullscreen, FullscreenType fstype);
bool setFullscreen(bool fullscreen);
@@ -79,6 +79,8 @@ public:
void setMouseGrab(bool grab);
bool isMouseGrabbed() const;
double getPixelScale() const;
const void *getHandle() const;
static love::window::Window *createSingleton();
@@ -91,8 +93,8 @@ private:
bool setContext(int fsaa, bool vsync);
void setWindowGLAttributes(int fsaa) const;
// Update the saved window attribs based on the window's actual state.
void updateAttributes(const WindowAttributes &newattribs);
// Update the saved window settings based on the window's actual state.
void updateSettings(const WindowSettings &newsettings);
// Shows a warning/error message box.
void displayError(const std::string &title, const std::string &text) const;
@@ -105,7 +107,7 @@ private:
int width;
int height;
WindowAttributes attribs;
WindowSettings settings;
love::image::ImageData *icon;
} curMode;
+58 -48
View File
@@ -26,7 +26,7 @@ namespace love
namespace window
{
static Window *instance = 0;
static Window *instance = nullptr;
int w_getDisplayCount(lua_State *L)
{
@@ -34,10 +34,10 @@ int w_getDisplayCount(lua_State *L)
return 1;
}
static const char *attribName(Window::Attribute attrib)
static const char *settingName(Window::Setting setting)
{
const char *name = nullptr;
Window::getConstant(attrib, name);
Window::getConstant(setting, name);
return name;
}
@@ -62,91 +62,94 @@ int w_setMode(lua_State *L)
return luax_typerror(L, -2, "string");
const char *key = luaL_checkstring(L, -2);
Window::Attribute attrib;
Window::Setting setting;
if (!Window::getConstant(key, attrib))
return luaL_error(L, "Invalid window attribute: %s", key);
if (!Window::getConstant(key, setting))
return luaL_error(L, "Invalid window setting: %s", key);
lua_pop(L, 1);
}
WindowAttributes attribs;
WindowSettings settings;
lua_getfield(L, 3, attribName(Window::ATTRIB_FULLSCREEN_TYPE));
lua_getfield(L, 3, settingName(Window::SETTING_FULLSCREEN_TYPE));
if (!lua_isnoneornil(L, -1))
{
const char *typestr = luaL_checkstring(L, -1);
if (!Window::getConstant(typestr, attribs.fstype))
if (!Window::getConstant(typestr, settings.fstype))
return luaL_error(L, "Invalid fullscreen type: %s", typestr);
}
else
{
// Default to "normal" fullscreen.
attribs.fstype = Window::FULLSCREEN_TYPE_NORMAL;
settings.fstype = Window::FULLSCREEN_TYPE_NORMAL;
}
lua_pop(L, 1);
attribs.fullscreen = luax_boolflag(L, 3, attribName(Window::ATTRIB_FULLSCREEN), false);
attribs.vsync = luax_boolflag(L, 3, attribName(Window::ATTRIB_VSYNC), true);
attribs.fsaa = luax_intflag(L, 3, attribName(Window::ATTRIB_FSAA), 0);
attribs.resizable = luax_boolflag(L, 3, attribName(Window::ATTRIB_RESIZABLE), false);
attribs.minwidth = luax_intflag(L, 3, attribName(Window::ATTRIB_MIN_WIDTH), 1);
attribs.minheight = luax_intflag(L, 3, attribName(Window::ATTRIB_MIN_HEIGHT), 1);
attribs.borderless = luax_boolflag(L, 3, attribName(Window::ATTRIB_BORDERLESS), false);
attribs.centered = luax_boolflag(L, 3, attribName(Window::ATTRIB_CENTERED), true);
attribs.display = luax_intflag(L, 3, attribName(Window::ATTRIB_DISPLAY), 1);
settings.fullscreen = luax_boolflag(L, 3, settingName(Window::SETTING_FULLSCREEN), false);
settings.vsync = luax_boolflag(L, 3, settingName(Window::SETTING_VSYNC), true);
settings.fsaa = luax_intflag(L, 3, settingName(Window::SETTING_FSAA), 0);
settings.resizable = luax_boolflag(L, 3, settingName(Window::SETTING_RESIZABLE), false);
settings.minwidth = luax_intflag(L, 3, settingName(Window::SETTING_MIN_WIDTH), 1);
settings.minheight = luax_intflag(L, 3, settingName(Window::SETTING_MIN_HEIGHT), 1);
settings.borderless = luax_boolflag(L, 3, settingName(Window::SETTING_BORDERLESS), false);
settings.centered = luax_boolflag(L, 3, settingName(Window::SETTING_CENTERED), true);
settings.display = luax_intflag(L, 3, settingName(Window::SETTING_DISPLAY), 1);
settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false);
// Display index is 1-based in Lua and 0-based internally.
attribs.display--;
settings.display--;
EXCEPT_GUARD(luax_pushboolean(L, instance->setWindow(w, h, &attribs));)
EXCEPT_GUARD(luax_pushboolean(L, instance->setWindow(w, h, &settings));)
return 1;
}
int w_getMode(lua_State *L)
{
int w, h;
WindowAttributes attribs;
instance->getWindow(w, h, attribs);
WindowSettings settings;
instance->getWindow(w, h, settings);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
lua_newtable(L);
const char *fstypestr = "normal";
Window::getConstant(attribs.fstype, fstypestr);
Window::getConstant(settings.fstype, fstypestr);
lua_pushstring(L, fstypestr);
lua_setfield(L, -2, attribName(Window::ATTRIB_FULLSCREEN_TYPE));
lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN_TYPE));
luax_pushboolean(L, attribs.fullscreen);
lua_setfield(L, -2, attribName(Window::ATTRIB_FULLSCREEN));
luax_pushboolean(L, settings.fullscreen);
lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN));
luax_pushboolean(L, attribs.vsync);
lua_setfield(L, -2, attribName(Window::ATTRIB_VSYNC));
luax_pushboolean(L, settings.vsync);
lua_setfield(L, -2, settingName(Window::SETTING_VSYNC));
lua_pushinteger(L, attribs.fsaa);
lua_setfield(L, -2, attribName(Window::ATTRIB_FSAA));
lua_pushinteger(L, settings.fsaa);
lua_setfield(L, -2, settingName(Window::SETTING_FSAA));
luax_pushboolean(L, attribs.resizable);
lua_setfield(L, -2, attribName(Window::ATTRIB_RESIZABLE));
luax_pushboolean(L, settings.resizable);
lua_setfield(L, -2, settingName(Window::SETTING_RESIZABLE));
lua_pushinteger(L, attribs.minwidth);
lua_setfield(L, -2, attribName(Window::ATTRIB_MIN_WIDTH));
lua_pushinteger(L, settings.minwidth);
lua_setfield(L, -2, settingName(Window::SETTING_MIN_WIDTH));
lua_pushinteger(L, attribs.minheight);
lua_setfield(L, -2, attribName(Window::ATTRIB_MIN_HEIGHT));
lua_pushinteger(L, settings.minheight);
lua_setfield(L, -2, settingName(Window::SETTING_MIN_HEIGHT));
luax_pushboolean(L, attribs.borderless);
lua_setfield(L, -2, attribName(Window::ATTRIB_BORDERLESS));
luax_pushboolean(L, settings.borderless);
lua_setfield(L, -2, settingName(Window::SETTING_BORDERLESS));
luax_pushboolean(L, attribs.centered);
lua_setfield(L, -2, attribName(Window::ATTRIB_CENTERED));
luax_pushboolean(L, settings.centered);
lua_setfield(L, -2, settingName(Window::SETTING_CENTERED));
// Display index is 0-based internally and 1-based in Lua.
lua_pushinteger(L, attribs.display + 1);
lua_setfield(L, -2, attribName(Window::ATTRIB_DISPLAY));
lua_pushinteger(L, settings.display + 1);
lua_setfield(L, -2, settingName(Window::SETTING_DISPLAY));
luax_pushboolean(L, settings.highdpi);
lua_setfield(L, -2, settingName(Window::SETTING_HIGHDPI));
return 3;
}
@@ -202,14 +205,14 @@ int w_setFullscreen(lua_State *L)
int w_getFullscreen(lua_State *L)
{
int w, h;
WindowAttributes attribs;
instance->getWindow(w, h, attribs);
WindowSettings settings;
instance->getWindow(w, h, settings);
const char *typestr;
if (!Window::getConstant(attribs.fstype, typestr))
if (!Window::getConstant(settings.fstype, typestr))
luaL_error(L, "Unknown fullscreen type.");
luax_pushboolean(L, attribs.fullscreen);
luax_pushboolean(L, settings.fullscreen);
lua_pushstring(L, typestr);
return 2;
}
@@ -300,6 +303,12 @@ int w_isVisible(lua_State *L)
return 1;
}
int w_getPixelScale(lua_State *L)
{
lua_pushnumber(L, instance->getPixelScale());
return 1;
}
static const luaL_Reg functions[] =
{
{ "getDisplayCount", w_getDisplayCount },
@@ -320,6 +329,7 @@ static const luaL_Reg functions[] =
{ "hasFocus", w_hasFocus },
{ "hasMouseFocus", w_hasMouseFocus },
{ "isVisible", w_isVisible },
{ "getPixelScale", w_getPixelScale },
{ 0, 0 }
};
@@ -47,6 +47,7 @@ int w_getTitle(lua_State *L);
int w_hasFocus(lua_State *L);
int w_hasMouseFocus(lua_State *L);
int w_isVisible(lua_State *L);
int w_getPixelScale(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_window(lua_State *L);
} // window
+29 -17
View File
@@ -164,20 +164,20 @@ function love.createhandlers()
textedit = function (t,s,l)
if love.textedit then return love.textedit(t,s,l) end
end,
mousepressed = function (x,y,b)
if love.mousepressed then return love.mousepressed(x,y,b) end
mousepressed = function (x,y,b,t)
if love.mousepressed then return love.mousepressed(x,y,b,t) end
end,
mousereleased = function (x,y,b)
if love.mousereleased then return love.mousereleased(x,y,b) end
mousereleased = function (x,y,b,t)
if love.mousereleased then return love.mousereleased(x,y,b,t) end
end,
fingerpressed = function (x,y,b)
if love.fingerpressed then return love.fingerpressed(x,y,b) end
touchpressed = function (id,x,y,p)
if love.touchpressed then return love.touchpressed(id,x,y,p) end
end,
fingerreleased = function (x,y,b)
if love.fingerreleased then return love.fingerreleased(x,y,b) end
touchreleased = function (id,x,y,p)
if love.touchreleased then return love.touchreleased(id,x,y,p) end
end,
fingermotion = function (x,y,b)
if love.fingermotion then return love.fingermotion(x,y,b) end
touchmoved = function (id,x,y,p)
if love.touchmoved then return love.touchmoved(id,x,y,p) end
end,
joystickpressed = function (j,b)
if love.joystickpressed then return love.joystickpressed(j,b) end
@@ -309,6 +309,7 @@ function love.init()
borderless = false,
resizable = false,
centered = true,
highdpi = false,
},
modules = {
event = true,
@@ -325,6 +326,7 @@ function love.init()
system = true,
font = true,
thread = true,
touch = true,
window = true,
},
console = false, -- Only relevant for windows.
@@ -359,6 +361,7 @@ function love.init()
"keyboard",
"joystick",
"mouse",
"touch",
"sound",
"system",
"audio",
@@ -397,6 +400,7 @@ function love.init()
borderless = c.window.borderless,
centered = c.window.centered,
display = c.window.display,
highdpi = c.window.highdpi,
}), "Could not set window mode")
love.window.setTitle(c.window.title or c.title)
if c.window.icon then
@@ -482,8 +486,8 @@ function love.run()
-- Process events.
if love.event then
love.event.pump()
for e,a,b,c,d in love.event.poll() do
if e == "quit" then
for n,a,b,c,d in love.event.poll() do
if n == "quit" then
if not love.quit or not love.quit() then
if love.audio then
love.audio.stop()
@@ -491,7 +495,7 @@ function love.run()
return
end
end
love.handlers[e](a,b,c,d)
love.handlers[n](a,b,c,d)
end
end
@@ -1382,8 +1386,9 @@ function love.nogame()
local ox = rain.ox
local oy = rain.oy
local batch_w = 2 * math.ceil(love.graphics.getWidth() / sx) + 2
local batch_h = 2 * math.ceil(love.graphics.getHeight() / sy) + 2
local m = 1 / love.window.getPixelScale()
local batch_w = 2 * math.ceil(m * love.graphics.getWidth() / sx) + 2
local batch_h = 2 * math.ceil(m * love.graphics.getHeight() / sy) + 2
batch:clear()
@@ -1418,8 +1423,9 @@ function love.nogame()
g_time = g_time + dt / 2
local int, frac = math.modf(g_time)
update_rain(frac)
inspector.x = love.graphics.getWidth() * 0.45
inspector.y = love.graphics.getHeight() * 0.55
local scale = love.window.getPixelScale()
inspector.x = love.graphics.getWidth() * 0.45 / scale
inspector.y = love.graphics.getHeight() * 0.55 / scale
end
local function draw_grid()
@@ -1490,8 +1496,13 @@ function love.nogame()
function love.draw()
love.graphics.setColor(255, 255, 255)
love.graphics.push()
love.graphics.scale(love.window.getPixelScale())
draw_grid()
draw_inspector()
love.graphics.pop()
end
function love.keyreleased(key)
@@ -1507,6 +1518,7 @@ function love.nogame()
t.modules.physics = false
t.modules.joystick = false
t.window.resizable = true
t.window.highdpi = true
end
end
+57 -33
View File
@@ -284,39 +284,40 @@ const unsigned char boot_lua[] =
0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72,
0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28,
0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x2c, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70,
0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65,
0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x70, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x70, 0x72,
0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28,
0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d,
0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x72,
0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61,
0x73, 0x65, 0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x70,
0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x72, 0x65,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
0x64, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x6d,
0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x28,
0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x70, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f,
0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x69, 0x64, 0x2c, 0x78,
0x2c, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20,
0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a,
@@ -558,6 +559,8 @@ const unsigned char boot_lua[] =
0x73, 0x65, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65,
0x2c, 0x0a,
0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65,
0x2c, 0x0a,
0x09, 0x09, 0x7d, 0x2c, 0x0a,
0x09, 0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
0x09, 0x09, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
@@ -577,6 +580,7 @@ const unsigned char boot_lua[] =
0x09, 0x09, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
0x09, 0x09, 0x7d, 0x2c, 0x0a,
0x09, 0x09, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c,
@@ -630,6 +634,7 @@ const unsigned char boot_lua[] =
0x09, 0x09, 0x22, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x22, 0x2c, 0x0a,
0x09, 0x09, 0x22, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x22, 0x2c, 0x0a,
0x09, 0x09, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x22, 0x2c, 0x0a,
0x09, 0x09, 0x22, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x22, 0x2c, 0x0a,
0x09, 0x09, 0x22, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x2c, 0x0a,
0x09, 0x09, 0x22, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22, 0x2c, 0x0a,
0x09, 0x09, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x2c, 0x0a,
@@ -689,6 +694,8 @@ const unsigned char boot_lua[] =
0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e,
0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e,
0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x2c, 0x0a,
0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73,
0x65, 0x74, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x54,
@@ -854,10 +861,10 @@ const unsigned char boot_lua[] =
0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70,
0x28, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x2c, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x20, 0x69,
0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x2c, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x20, 0x69,
0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28,
0x29, 0x20, 0x64, 0x6f, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22,
0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71,
0x75, 0x69, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71, 0x75,
@@ -871,7 +878,7 @@ const unsigned char boot_lua[] =
0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b,
0x65, 0x5d, 0x28, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x29, 0x0a,
0x6e, 0x5d, 0x28, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x64, 0x74, 0x2c, 0x20, 0x61, 0x73,
@@ -4945,14 +4952,17 @@ const unsigned char boot_lua[] =
0x6f, 0x78, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x79, 0x20, 0x3d, 0x20, 0x72, 0x61, 0x69, 0x6e, 0x2e,
0x6f, 0x79, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, 0x31, 0x20, 0x2f, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78, 0x65, 0x6c,
0x53, 0x63, 0x61, 0x6c, 0x65, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x77, 0x20, 0x3d, 0x20,
0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68,
0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x78, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a,
0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6d, 0x20, 0x2a, 0x20,
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57,
0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x78, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x68, 0x20, 0x3d, 0x20,
0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68,
0x74, 0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x79, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a,
0x32, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6d, 0x20, 0x2a, 0x20,
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x48,
0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2f, 0x20, 0x73, 0x79, 0x29, 0x20, 0x2b, 0x20, 0x32, 0x0a,
0x09, 0x09, 0x62, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x66, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x67, 0x65, 0x74, 0x42, 0x75, 0x66, 0x66,
0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x28, 0x29, 0x20, 0x3c, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x77,
@@ -4998,12 +5008,17 @@ const unsigned char boot_lua[] =
0x29, 0x0a,
0x09, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x61, 0x69, 0x6e, 0x28, 0x66, 0x72, 0x61, 0x63,
0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78, 0x65, 0x6c,
0x53, 0x63, 0x61, 0x6c, 0x65, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x78, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64,
0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x34, 0x35, 0x0a,
0x74, 0x68, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x34, 0x35, 0x20, 0x2f, 0x20, 0x73, 0x63, 0x61, 0x6c,
0x65, 0x0a,
0x09, 0x09, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x48, 0x65, 0x69,
0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x35, 0x35, 0x0a,
0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x35, 0x35, 0x20, 0x2f, 0x20, 0x73, 0x63, 0x61,
0x6c, 0x65, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x72,
0x61, 0x77, 0x5f, 0x67, 0x72, 0x69, 0x64, 0x28, 0x29, 0x0a,
@@ -5147,8 +5162,15 @@ const unsigned char boot_lua[] =
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65,
0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32,
0x35, 0x35, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x75,
0x73, 0x68, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x63,
0x61, 0x6c, 0x65, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x67, 0x65,
0x74, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x28, 0x29, 0x29, 0x0a,
0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x67, 0x72, 0x69, 0x64, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x6f,
0x70, 0x28, 0x29, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x0a,
0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79,
@@ -5176,6 +5198,8 @@ const unsigned char boot_lua[] =
0x63, 0x6b, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a,
0x09, 0x09, 0x74, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62,
0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a,
0x09, 0x09, 0x74, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69,
0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,
0x65, 0x6e, 0x64, 0x0a,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,