This commit is contained in:
bjorn 2017-04-16 16:56:49 -07:00
parent fa339c4b24
commit 0f1acae42a
22 changed files with 3262 additions and 355 deletions

View File

@ -13,13 +13,88 @@ if(UNIX)
endif() endif()
project(lovr) project(lovr)
file(GLOB_RECURSE LOVR_SRC src/*.c) set(LOVR_SRC
add_executable(lovr ${LOVR_SRC}) src/api/audio.c
src/api/event.c
src/api/filesystem.c
src/api/graphics.c
src/api/headset.c
src/api/math.c
src/api/timer.c
src/api/types/blob.c
src/api/types/controller.c
src/api/types/font.c
src/api/types/mesh.c
src/api/types/model.c
src/api/types/shader.c
src/api/types/skybox.c
src/api/types/source.c
src/api/types/texture.c
src/api/types/transform.c
src/audio/audio.c
src/audio/source.c
src/event/event.c
src/filesystem/blob.c
src/filesystem/filesystem.c
src/graphics/font.c
src/graphics/graphics.c
src/graphics/mesh.c
src/graphics/model.c
src/graphics/shader.c
src/graphics/skybox.c
src/graphics/texture.c
src/headset/headset.c
src/lib/glad/glad.c
src/lib/lua-cjson/fpconv.c
src/lib/lua-cjson/lua_cjson.c
src/lib/lua-cjson/strbuf.c
src/lib/map/map.c
src/lib/stb/stb_image.c
src/lib/stb/stb_vorbis.c
src/lib/vec/vec.c
src/loaders/font.c
src/loaders/model.c
src/loaders/source.c
src/loaders/texture.c
src/lovr.c
src/luax.c
src/main.c
src/math/mat4.c
src/math/quat.c
src/math/transform.c
src/math/vec3.c
src/timer/timer.c
src/util.c
)
# Headset backends
if(EMSCRIPTEN)
set(LOVR_HEADSET src/headset/webvr.c)
else()
set(LOVR_HEADSET src/headset/openvr.c)
endif()
add_executable(lovr ${LOVR_SRC} ${LOVR_HEADSET})
if(EMSCRIPTEN)
set(CMAKE_EXECUTABLE_SUFFIX ".html")
add_definitions(-s USE_ZLIB=1 -s ASSERTIONS=2 -s FULL_ES2=1)
set(ZLIB_FOUND 1)
set(ZLIB_LIBRARIES "-s USE_ZLIB=1")
set(ZLIB_INCLUDE_DIR .)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
# LuaJIT # Lua
if(WIN32) if(EMSCRIPTEN)
option(LUA_USE_RELATIVE_LOADLIB OFF)
option(LUA_USE_ULONGJMP OFF)
add_subdirectory(deps/lua lua)
set_target_properties(lua luac liblua_static PROPERTIES EXCLUDE_FROM_ALL 1)
include_directories(deps/lua/src ${CMAKE_BINARY_DIR}/lua)
set(LOVR_LUA liblua)
elseif(WIN32)
add_subdirectory(deps/luajit luajit) add_subdirectory(deps/luajit luajit)
include_directories(deps/luajit/src ${CMAKE_BINARY_DIR}/luajit) include_directories(deps/luajit/src ${CMAKE_BINARY_DIR}/luajit)
set(LOVR_LUA liblua) set(LOVR_LUA liblua)
@ -44,7 +119,9 @@ endif()
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "") set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "")
set(GLFW_BUILD_TESTS OFF CACHE BOOL "") set(GLFW_BUILD_TESTS OFF CACHE BOOL "")
set(GLFW_BUILD_DOCS OFF CACHE BOOL "") set(GLFW_BUILD_DOCS OFF CACHE BOOL "")
if(WIN32) if(EMSCRIPTEN)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3")
elseif(WIN32)
add_subdirectory(deps/glfw glfw) add_subdirectory(deps/glfw glfw)
include_directories(deps/glfw/include) include_directories(deps/glfw/include)
set(LOVR_GLFW glfw ${GLFW_LIBRARIES}) set(LOVR_GLFW glfw ${GLFW_LIBRARIES})
@ -65,7 +142,12 @@ set(PHYSFS_ARCHIVE_QPAK OFF CACHE BOOL "")
set(PHYSFS_BUILD_TEST OFF CACHE BOOL "") set(PHYSFS_BUILD_TEST OFF CACHE BOOL "")
set(PHYSFS_BUILD_WX_TEST FALSE CACHE BOOL "") set(PHYSFS_BUILD_WX_TEST FALSE CACHE BOOL "")
if(WIN32) if(EMSCRIPTEN)
option(PHYSFS_ARCHIVE_ZIP OFF)
add_subdirectory(deps/physfs physfs)
include_directories(deps/physfs)
set(LOVR_PHYSFS physfs)
elseif(WIN32)
add_subdirectory(deps/physfs physfs) add_subdirectory(deps/physfs physfs)
include_directories(deps/physfs) include_directories(deps/physfs)
set(LOVR_PHYSFS physfs) set(LOVR_PHYSFS physfs)
@ -85,7 +167,11 @@ set(ASSIMP_BUILD_COLLADA_IMPORTER ON CACHE BOOL "")
set(ASSIMP_BUILD_OBJ_IMPORTER ON CACHE BOOL "") set(ASSIMP_BUILD_OBJ_IMPORTER ON CACHE BOOL "")
set(ASSIMP_BUILD_FBX_IMPORTER ON CACHE BOOL "") set(ASSIMP_BUILD_FBX_IMPORTER ON CACHE BOOL "")
if(WIN32) if(EMSCRIPTEN)
add_subdirectory(deps/assimp assimp)
include_directories(deps/assimp/include)
set(LOVR_ASSIMP assimp)
elseif(WIN32)
add_subdirectory(deps/assimp assimp) add_subdirectory(deps/assimp assimp)
include_directories(deps/assimp/include) include_directories(deps/assimp/include)
set(LOVR_ASSIMP assimp) set(LOVR_ASSIMP assimp)
@ -103,7 +189,7 @@ if (WIN32)
add_subdirectory(deps/openal-soft openal) add_subdirectory(deps/openal-soft openal)
include_directories(deps/openal-soft/include) include_directories(deps/openal-soft/include)
set(LOVR_OPENAL OpenAL32) set(LOVR_OPENAL OpenAL32)
else() elseif(NOT EMSCRIPTEN)
pkg_search_module(OPENAL REQUIRED openal) pkg_search_module(OPENAL REQUIRED openal)
include_directories(${OPENAL_INCLUDE_DIRS}) include_directories(${OPENAL_INCLUDE_DIRS})
string(REPLACE ";" " " OPENAL_LDFLAGS_STR "${OPENAL_LDFLAGS}") string(REPLACE ";" " " OPENAL_LDFLAGS_STR "${OPENAL_LDFLAGS}")
@ -112,8 +198,9 @@ else()
endif() endif()
# FreeType # FreeType
if (WIN32) if (WIN32 OR EMSCRIPTEN)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
set(FREETYPE_NO_DIST TRUE CACHE BOOL "")
add_subdirectory(deps/freetype freetype) add_subdirectory(deps/freetype freetype)
include_directories(deps/freetype/include) include_directories(deps/freetype/include)
set(LOVR_FREETYPE freetype) set(LOVR_FREETYPE freetype)
@ -124,26 +211,28 @@ else()
endif() endif()
# openvr # openvr
if(NOT DEFINED OPENVR_DIR AND IS_DIRECTORY "${PROJECT_SOURCE_DIR}/deps/openvr") if(NOT EMSCRIPTEN)
SET(OPENVR_DIR deps/openvr) if(NOT DEFINED OPENVR_DIR AND IS_DIRECTORY "${PROJECT_SOURCE_DIR}/deps/openvr")
else() SET(OPENVR_DIR deps/openvr)
message(FATAL_ERROR "Please specify the location of OpenVR (-DOPENVR_DIR=/path/to/openvr)") else()
endif() message(FATAL_ERROR "Please specify the location of OpenVR (-DOPENVR_DIR=/path/to/openvr)")
endif()
if(APPLE) if(APPLE)
add_definitions(-DOSX -DPOSIX) add_definitions(-DOSX -DPOSIX)
elseif(UNIX) elseif(UNIX)
add_definitions(-DLINUX -DPOSIX) add_definitions(-DLINUX -DPOSIX)
endif() endif()
set(BUILD_SHARED ON CACHE BOOL "") set(BUILD_SHARED ON CACHE BOOL "")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -fvisibility=hidden") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -fvisibility=hidden")
add_definitions(-DVR_API_PUBLIC) add_definitions(-DVR_API_PUBLIC)
include_directories(${OPENVR_DIR}/headers) include_directories(${OPENVR_DIR}/headers)
include_directories(${OPENVR_DIR}/src) include_directories(${OPENVR_DIR}/src)
include_directories(${OPENVR_DIR}/src/vrcommon) include_directories(${OPENVR_DIR}/src/vrcommon)
add_subdirectory(${OPENVR_DIR}/src openvr_api) add_subdirectory(${OPENVR_DIR}/src openvr_api)
set(LOVR_OPENVR openvr_api) set(LOVR_OPENVR openvr_api)
endif()
set(LOVR_LIB set(LOVR_LIB
${LOVR_LUA} ${LOVR_LUA}

9
build.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
rm -rf build
mkdir build
cd build
emcmake cmake .. && emmake make
mkdir game
echo "function lovr.load()\n print('hi')\nend" > game/main.lua
../package.sh game

3
package.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
python "$EMSCRIPTEN/tools/file_packager.py" game.data --preload "$1"@/ --js-output=game.js

View File

@ -5,10 +5,17 @@ map_int_t ControllerAxes;
map_int_t ControllerButtons; map_int_t ControllerButtons;
map_int_t HeadsetEyes; map_int_t HeadsetEyes;
typedef struct {
lua_State* L;
int ref;
} HeadsetRenderData;
static HeadsetRenderData headsetRenderData;
static void renderHelper(HeadsetEye eye, void* userdata) { static void renderHelper(HeadsetEye eye, void* userdata) {
lua_State* L = (lua_State*)userdata; HeadsetRenderData* renderData = userdata;
luaL_checktype(L, 1, LUA_TFUNCTION); lua_State* L = renderData->L;
lua_pushvalue(L, 1); lua_rawgeti(L, LUA_REGISTRYINDEX, renderData->ref);
luax_pushenum(L, &HeadsetEyes, eye); luax_pushenum(L, &HeadsetEyes, eye);
lua_call(L, 1, 0); lua_call(L, 1, 0);
} }
@ -212,8 +219,11 @@ int l_lovrHeadsetGetControllerCount(lua_State* L) {
} }
int l_lovrHeadsetRenderTo(lua_State* L) { int l_lovrHeadsetRenderTo(lua_State* L) {
lua_settop(L, 1);
luaL_checktype(L, 1, LUA_TFUNCTION); luaL_checktype(L, 1, LUA_TFUNCTION);
lovrHeadsetRenderTo(renderHelper, L); headsetRenderData.ref = luaL_ref(L, LUA_REGISTRYINDEX);
headsetRenderData.L = L;
lovrHeadsetRenderTo(renderHelper, &headsetRenderData);
return 0; return 0;
} }

View File

@ -8,8 +8,6 @@
static AudioState state; static AudioState state;
static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
void lovrAudioInit() { void lovrAudioInit() {
ALCdevice* device = alcOpenDevice(NULL); ALCdevice* device = alcOpenDevice(NULL);
if (!device) { if (!device) {
@ -21,6 +19,8 @@ void lovrAudioInit() {
error("Unable to create OpenAL context"); error("Unable to create OpenAL context");
} }
#ifndef EMSCRIPTEN
static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
alcResetDeviceSOFT = (LPALCRESETDEVICESOFT) alcGetProcAddress(device, "alcResetDeviceSOFT"); alcResetDeviceSOFT = (LPALCRESETDEVICESOFT) alcGetProcAddress(device, "alcResetDeviceSOFT");
state.isSpatialized = alcIsExtensionPresent(device, "ALC_SOFT_HRTF"); state.isSpatialized = alcIsExtensionPresent(device, "ALC_SOFT_HRTF");
@ -28,6 +28,7 @@ void lovrAudioInit() {
ALCint attrs[3] = { ALC_HRTF_SOFT, ALC_TRUE, 0 }; ALCint attrs[3] = { ALC_HRTF_SOFT, ALC_TRUE, 0 };
alcResetDeviceSOFT(device, attrs); alcResetDeviceSOFT(device, attrs);
} }
#endif
state.device = device; state.device = device;
state.context = context; state.context = context;
@ -107,7 +108,7 @@ int lovrAudioHas(Source* source) {
return index >= 0; return index >= 0;
} }
int lovrAudioIsSpatialized(Source* source) { int lovrAudioIsSpatialized() {
return state.isSpatialized; return state.isSpatialized;
} }

View File

@ -2,7 +2,9 @@
#include "lib/vec/vec.h" #include "lib/vec/vec.h"
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
#ifndef EMSCRIPTEN
#include <AL/alext.h> #include <AL/alext.h>
#endif
#pragma once #pragma once

View File

@ -111,37 +111,42 @@ lovr.handlers = setmetatable({
end end
}) })
function lovr.step()
lovr.event.pump()
for name, a, b, c, d in lovr.event.poll() do
if name == 'quit' and (not lovr.quit or not lovr.quit()) then
return a
end
lovr.handlers[name](a, b, c, d)
end
local dt = lovr.timer.step()
if lovr.audio then
lovr.audio.update()
if lovr.headset and lovr.headset.isPresent() then
lovr.audio.setOrientation(lovr.headset.getOrientation())
lovr.audio.setPosition(lovr.headset.getPosition())
lovr.audio.setVelocity(lovr.headset.getVelocity())
end
end
if lovr.update then lovr.update(dt) end
lovr.graphics.clear()
lovr.graphics.origin()
if lovr.draw then
if lovr.headset and lovr.headset.isPresent() then
lovr.headset.renderTo(lovr.draw)
else
lovr.draw()
end
end
lovr.graphics.present()
lovr.timer.sleep(.001)
end
function lovr.run() function lovr.run()
if lovr.load then lovr.load() end if lovr.load then lovr.load() end
while true do while true do
lovr.event.pump() local exit = lovr.step()
for name, a, b, c, d in lovr.event.poll() do if exit then return exit end
if name == 'quit' and (not lovr.quit or not lovr.quit()) then
return a
end
lovr.handlers[name](a, b, c, d)
end
local dt = lovr.timer.step()
if lovr.audio then
lovr.audio.update()
if lovr.headset and lovr.headset.isPresent() then
lovr.audio.setOrientation(lovr.headset.getOrientation())
lovr.audio.setPosition(lovr.headset.getPosition())
lovr.audio.setVelocity(lovr.headset.getVelocity())
end
end
if lovr.update then lovr.update(dt) end
lovr.graphics.clear()
lovr.graphics.origin()
if lovr.draw then
if lovr.headset and lovr.headset.isPresent() then
lovr.headset.renderTo(lovr.draw)
else
lovr.draw()
end
end
lovr.graphics.present()
lovr.timer.sleep(.001)
end end
end end

View File

@ -272,169 +272,172 @@ unsigned char boot_lua[] = {
0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x65, 0x76, 0x65, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x65, 0x76, 0x65,
0x6e, 0x74, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x7d, 0x6e, 0x74, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x7d,
0x29, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x29, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a,
0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74,
0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x66, 0x6f,
0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62,
0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f,
0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, 0x29, 0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x71,
0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x75, 0x69, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x28, 0x6e, 0x6f,
0x64, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x71, 0x75, 0x69, 0x74, 0x20,
0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x71, 0x75, 0x69, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x28, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6e, 0x20, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x6f, 0x76, 0x72, 0x2e, 0x71, 0x75, 0x69, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x61, 0x6e,
0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x71, 0x75, 0x69, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x28,
0x74, 0x28, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 0x29, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x20, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x6c, 0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29,
0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e, 0x61, 0x6d, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61,
0x65, 0x5d, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f,
0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x74, 0x20, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20,
0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65,
0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f,
0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x69,
0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74,
0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74,
0x2e, 0x67, 0x65, 0x74, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e,
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74,
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x69, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74,
0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x56, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65,
0x73, 0x65, 0x74, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x74, 0x56, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29,
0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65,
0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x28, 0x64, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c,
0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x2e, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x6c,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20,
0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x56, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77,
0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x65, 0x6c, 0x6f, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65,
0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x69, 0x73, 0x50, 0x72, 0x65,
0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65,
0x65, 0x28, 0x64, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x72, 0x54, 0x6f, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61,
0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a,
0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f,
0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e,
0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64,
0x73, 0x65, 0x74, 0x2e, 0x69, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e,
0x74, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65,
0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72,
0x54, 0x6f, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77,
0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x65,
0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c,
0x65, 0x65, 0x70, 0x28, 0x2e, 0x30, 0x30, 0x31, 0x29, 0x0a, 0x20, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65,
0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x20, 0x3d, 0x20, 0x27, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x5c,
0x6e, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x5c, 0x6e, 0x5b, 0x5e,
0x5c, 0x6e, 0x5d, 0x2b, 0x24, 0x27, 0x2c, 0x20, 0x27, 0x27, 0x29, 0x3a,
0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x5c, 0x74, 0x27, 0x2c, 0x20, 0x27,
0x27, 0x29, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x73, 0x74, 0x61,
0x63, 0x6b, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b,
0x27, 0x2c, 0x20, 0x27, 0x5c, 0x6e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x27,
0x29, 0x0a, 0x20, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x72,
0x65, 0x73, 0x65, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73,
0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x32, 0x37, 0x2c, 0x20, 0x32, 0x35,
0x2c, 0x20, 0x33, 0x35, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65,
0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x32, 0x32, 0x30, 0x2c, 0x20,
0x32, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x32, 0x30, 0x29, 0x0a, 0x20, 0x20,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69,
0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x46, 0x6f, 0x6e, 0x74, 0x28, 0x29,
0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x69, 0x78,
0x65, 0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20,
0x66, 0x6f, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78, 0x65,
0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68,
0x20, 0x3d, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74, 0x57,
0x69, 0x64, 0x74, 0x68, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x2c, 0x20, 0x2e, 0x35, 0x35, 0x20, 0x2a, 0x20, 0x70, 0x69, 0x78, 0x65,
0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x29, 0x0a, 0x20, 0x20,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x69,
0x6e, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20,
0x2d, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x2f, 0x20, 0x32, 0x2c, 0x20,
0x30, 0x2c, 0x20, 0x2d, 0x32, 0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x30,
0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x2e,
0x35, 0x35, 0x20, 0x2a, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x44, 0x65,
0x6e, 0x73, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x27, 0x6c, 0x65, 0x66, 0x74,
0x27, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x77,
0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76,
0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20,
0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e,
0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d,
0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x71, 0x75, 0x69, 0x74, 0x27, 0x20,
0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28,
0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e,
0x64, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
0x65, 0x74, 0x2e, 0x69, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74,
0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
0x65, 0x74, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28,
0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72,
0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73,
0x6c, 0x65, 0x65, 0x70, 0x28, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x6c, 0x65, 0x65, 0x70, 0x28, 0x2e, 0x30, 0x30, 0x31, 0x29, 0x0a, 0x65,
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e, 0x28, 0x29, 0x0a,
0x69, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f,
0x20, 0x61, 0x6e, 0x64, 0x20, 0x2e, 0x30, 0x30, 0x31, 0x20, 0x6f, 0x72, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x20, 0x2e, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76,
0x6c, 0x75, 0x61, 0x27, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x6d, 0x61, 0x20, 0x69, 0x66, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65,
0x69, 0x6e, 0x27, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x78, 0x69,
0x74, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x72, 0x72, 0x68, 0x61,
0x6e, 0x64, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0a,
0x20, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20,
0x27, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x5c, 0x6e, 0x27, 0x20, 0x2e,
0x2e, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3a, 0x67, 0x73,
0x75, 0x62, 0x28, 0x27, 0x5c, 0x6e, 0x5b, 0x5e, 0x5c, 0x6e, 0x5d, 0x2b,
0x24, 0x27, 0x2c, 0x20, 0x27, 0x27, 0x29, 0x3a, 0x67, 0x73, 0x75, 0x62,
0x28, 0x27, 0x5c, 0x74, 0x27, 0x2c, 0x20, 0x27, 0x27, 0x29, 0x3a, 0x67,
0x73, 0x75, 0x62, 0x28, 0x27, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x20, 0x74,
0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x27, 0x2c, 0x20, 0x27,
0x5c, 0x6e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x27, 0x29, 0x0a, 0x20, 0x20,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x65, 0x74,
0x28, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x42, 0x61,
0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f,
0x72, 0x28, 0x32, 0x37, 0x2c, 0x20, 0x32, 0x35, 0x2c, 0x20, 0x33, 0x35,
0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c,
0x6f, 0x72, 0x28, 0x32, 0x32, 0x30, 0x2c, 0x20, 0x32, 0x32, 0x30, 0x2c,
0x20, 0x32, 0x32, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x67,
0x65, 0x74, 0x46, 0x6f, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x6c,
0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x44, 0x65,
0x6e, 0x73, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x66, 0x6f, 0x6e, 0x74,
0x3a, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x44, 0x65, 0x6e,
0x73, 0x69, 0x74, 0x79, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63,
0x61, 0x6c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x66,
0x6f, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74, 0x57, 0x69, 0x64, 0x74, 0x68,
0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x2e, 0x35,
0x35, 0x20, 0x2a, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x44, 0x65, 0x6e,
0x73, 0x69, 0x74, 0x79, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x73, 0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70,
0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x2d, 0x77, 0x69, 0x64,
0x74, 0x68, 0x20, 0x2f, 0x20, 0x32, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x2d,
0x32, 0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c,
0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x2e, 0x35, 0x35, 0x20, 0x2a,
0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74,
0x79, 0x2c, 0x20, 0x27, 0x6c, 0x65, 0x66, 0x74, 0x27, 0x29, 0x0a, 0x20,
0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65,
0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e,
0x70, 0x75, 0x6d, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f,
0x6c, 0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d,
0x20, 0x27, 0x71, 0x75, 0x69, 0x74, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x73, 0x2e, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65,
0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x69,
0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x72,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, 0x72, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65,
0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c, 0x65, 0x65, 0x70,
0x28, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x69, 0x73, 0x50, 0x72,
0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x29, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x2e, 0x30, 0x30, 0x31, 0x20, 0x6f, 0x72, 0x20, 0x2e, 0x31, 0x29,
0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c,
0x65, 0x28, 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x27,
0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x71,
0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x27, 0x29,
0x0a, 0x65, 0x6e, 0x64, 0x0a
}; };
unsigned int boot_lua_len = 5241; unsigned int boot_lua_len = 5273;

View File

@ -78,6 +78,8 @@ int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size) {
wcstombs(dest, appData, size); wcstombs(dest, appData, size);
CoTaskMemFree(appData); CoTaskMemFree(appData);
return 0; return 0;
#elif EMSCRIPTEN
return 0;
#else #else
#error "This platform is missing an implementation for lovrFilesystemGetAppdataDirectory" #error "This platform is missing an implementation for lovrFilesystemGetAppdataDirectory"
#endif #endif
@ -96,6 +98,8 @@ int lovrFilesystemGetExecutablePath(char* dest, unsigned int size) {
} }
#elif _WIN32 #elif _WIN32
return !GetModuleFileName(NULL, dest, size); return !GetModuleFileName(NULL, dest, size);
#elif EMSCRIPTEN
return 1;
#else #else
#error "This platform is missing an implementation for lovrFilesystemGetExecutablePath" #error "This platform is missing an implementation for lovrFilesystemGetExecutablePath"
#endif #endif
@ -213,7 +217,7 @@ int lovrFilesystemSetIdentity(const char* identity) {
snprintf(state.savePathFull, LOVR_PATH_MAX, "%s%s%s", state.savePathFull, sep, state.savePathRelative); snprintf(state.savePathFull, LOVR_PATH_MAX, "%s%s%s", state.savePathFull, sep, state.savePathRelative);
PHYSFS_mkdir(state.savePathRelative); PHYSFS_mkdir(state.savePathRelative);
if (!PHYSFS_setWriteDir(state.savePathFull)) { if (!PHYSFS_setWriteDir(state.savePathFull)) {
error("Could not set write directory"); //error("Could not set write directory");
} }
PHYSFS_mount(state.savePathFull, NULL, 0); PHYSFS_mount(state.savePathFull, NULL, 0);

View File

@ -51,8 +51,11 @@ Font* lovrFontCreate(FontData* fontData) {
TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RG); TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RG);
font->texture = lovrTextureCreate(textureData); font->texture = lovrTextureCreate(textureData);
lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP); lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP);
int swizzle[4] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle); if (GLAD_GL_VERSION_3_0) {
int swizzle[4] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
}
return font; return font;
} }
@ -289,7 +292,11 @@ void lovrFontAddGlyph(Font* font, Glyph* glyph) {
// Paste glyph into texture // Paste glyph into texture
lovrGraphicsBindTexture(font->texture); lovrGraphicsBindTexture(font->texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, atlas->x, atlas->y, glyph->w, glyph->h, GL_RG, GL_UNSIGNED_BYTE, glyph->data); if (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_texture_rg || GLAD_GL_EXT_texture_rg) {
glTexSubImage2D(GL_TEXTURE_2D, 0, atlas->x, atlas->y, glyph->w, glyph->h, GL_RG, GL_UNSIGNED_BYTE, glyph->data);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, atlas->x, atlas->y, glyph->w, glyph->h, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, glyph->data);
}
// Advance atlas cursor // Advance atlas cursor
atlas->x += glyph->w + atlas->padding; atlas->x += glyph->w + atlas->padding;

View File

@ -7,6 +7,7 @@
#include "util.h" #include "util.h"
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <math.h> #include <math.h>
static GraphicsState state; static GraphicsState state;
@ -23,11 +24,15 @@ static void onCloseWindow(GLFWwindow* window) {
// Base // Base
void lovrGraphicsInit() { void lovrGraphicsInit() {
#ifdef EMSCRIPTEN
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#else
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_SAMPLES, 4);
#endif
state.window = glfwCreateWindow(800, 600, "Window", NULL, NULL); state.window = glfwCreateWindow(800, 600, "Window", NULL, NULL);
@ -39,23 +44,32 @@ void lovrGraphicsInit() {
glfwMakeContextCurrent(state.window); glfwMakeContextCurrent(state.window);
glfwSetWindowCloseCallback(state.window, onCloseWindow); glfwSetWindowCloseCallback(state.window, onCloseWindow);
#ifdef EMSCRIPTEN
gladLoadGLES2Loader((GLADloadproc) glfwGetProcAddress);
#else
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
#endif
glfwSetTime(0); glfwSetTime(0);
glfwSwapInterval(0);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_MULTISAMPLE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 2); glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
if (GLAD_GL_VERSION_3_0) {
glfwSwapInterval(0);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_MULTISAMPLE);
}
// Allocations // Allocations
state.activeFont = NULL; state.activeFont = NULL;
state.defaultFont = NULL; state.defaultFont = NULL;
state.activeTexture = NULL; state.activeTexture = NULL;
glGenBuffers(1, &state.shapeBuffer); glGenBuffers(1, &state.shapeBuffer);
glGenBuffers(1, &state.shapeIndexBuffer); glGenBuffers(1, &state.shapeIndexBuffer);
glGenVertexArrays(1, &state.shapeArray); if (GLAD_GL_VERSION_3_0) {
glGenVertexArrays(1, &state.shapeArray);
}
vec_init(&state.shapeData); vec_init(&state.shapeData);
vec_init(&state.shapeIndices); vec_init(&state.shapeIndices);
for (int i = 0; i < MAX_CANVASES; i++) { for (int i = 0; i < MAX_CANVASES; i++) {
@ -71,11 +85,17 @@ void lovrGraphicsInit() {
state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA)); state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA));
// System Limits // System Limits
float pointSizes[2]; if (GLAD_GL_VERSION_2_0) {
glGetFloatv(GL_POINT_SIZE_RANGE, pointSizes); float pointSizes[2];
state.maxPointSize = pointSizes[1]; glGetFloatv(GL_POINT_SIZE_RANGE, pointSizes);
state.maxPointSize = pointSizes[1];
glGetIntegerv(GL_MAX_SAMPLES, &state.maxTextureMSAA);
} else {
state.maxPointSize = 1.f;
state.maxTextureMSAA = 1;
}
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.maxTextureSize); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.maxTextureSize);
glGetIntegerv(GL_MAX_SAMPLES, &state.maxTextureMSAA);
// State // State
state.depthTest = -1; state.depthTest = -1;
@ -99,7 +119,9 @@ void lovrGraphicsDestroy() {
lovrRelease(&state.defaultTexture->ref); lovrRelease(&state.defaultTexture->ref);
glDeleteBuffers(1, &state.shapeBuffer); glDeleteBuffers(1, &state.shapeBuffer);
glDeleteBuffers(1, &state.shapeIndexBuffer); glDeleteBuffers(1, &state.shapeIndexBuffer);
glDeleteVertexArrays(1, &state.shapeArray); if (GLAD_GL_VERSION_3_0) {
glDeleteVertexArrays(1, &state.shapeArray);
}
vec_deinit(&state.shapeData); vec_deinit(&state.shapeData);
vec_deinit(&state.shapeIndices); vec_deinit(&state.shapeIndices);
} }
@ -199,13 +221,21 @@ void lovrGraphicsSetBlendMode(BlendMode mode, BlendAlphaMode alphaMode) {
break; break;
case BLEND_LIGHTEN: case BLEND_LIGHTEN:
glBlendEquation(GL_MAX); if (GLAD_GL_VERSION_2_0 || GLAD_GL_EXT_blend_minmax) {
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO); glBlendEquation(GL_MAX);
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
} else {
error("The lighten blend mode is not supported on this platform.");
}
break; break;
case BLEND_DARKEN: case BLEND_DARKEN:
glBlendEquation(GL_MIN); if (GLAD_GL_VERSION_2_0 || GLAD_GL_EXT_blend_minmax) {
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO); glBlendEquation(GL_MIN);
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
} else {
error("The darken blend mode is not supported on this platform.");
}
break; break;
case BLEND_SCREEN: case BLEND_SCREEN:
@ -361,8 +391,10 @@ float lovrGraphicsGetPointSize() {
} }
void lovrGraphicsSetPointSize(float size) { void lovrGraphicsSetPointSize(float size) {
state.pointSize = size; if (GLAD_GL_VERSION_2_0) {
glPointSize(size); state.pointSize = size;
glPointSize(size);
}
} }
int lovrGraphicsIsCullingEnabled() { int lovrGraphicsIsCullingEnabled() {
@ -408,21 +440,21 @@ int lovrGraphicsIsWireframe() {
} }
void lovrGraphicsSetWireframe(int wireframe) { void lovrGraphicsSetWireframe(int wireframe) {
if (state.isWireframe != wireframe) { if (GLAD_GL_VERSION_3_0 && state.isWireframe != wireframe) {
state.isWireframe = wireframe; state.isWireframe = wireframe;
glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL);
} }
} }
int lovrGraphicsGetWidth() { int lovrGraphicsGetWidth() {
int width; int width, height;
glfwGetFramebufferSize(state.window, &width, NULL); glfwGetFramebufferSize(state.window, &width, &height);
return width; return width;
} }
int lovrGraphicsGetHeight() { int lovrGraphicsGetHeight() {
int height; int width, height;
glfwGetFramebufferSize(state.window, NULL, &height); glfwGetFramebufferSize(state.window, &width, &height);
return height; return height;
} }
@ -515,7 +547,9 @@ void lovrGraphicsDrawPrimitive(GLenum mode, int hasNormals, int hasTexCoords, in
int strideBytes = stride * sizeof(float); int strideBytes = stride * sizeof(float);
lovrGraphicsPrepare(); lovrGraphicsPrepare();
glBindVertexArray(state.shapeArray); if (GLAD_GL_VERSION_3_0) {
glBindVertexArray(state.shapeArray);
}
glBindBuffer(GL_ARRAY_BUFFER, state.shapeBuffer); glBindBuffer(GL_ARRAY_BUFFER, state.shapeBuffer);
glBufferData(GL_ARRAY_BUFFER, state.shapeData.length * sizeof(float), state.shapeData.data, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, state.shapeData.length * sizeof(float), state.shapeData.data, GL_STREAM_DRAW);
glEnableVertexAttribArray(LOVR_SHADER_POSITION); glEnableVertexAttribArray(LOVR_SHADER_POSITION);
@ -544,7 +578,9 @@ void lovrGraphicsDrawPrimitive(GLenum mode, int hasNormals, int hasTexCoords, in
glDrawArrays(mode, 0, state.shapeData.length / stride); glDrawArrays(mode, 0, state.shapeData.length / stride);
} }
glBindVertexArray(0); if (GLAD_GL_VERSION_3_0) {
glBindVertexArray(0);
}
} }
void lovrGraphicsPoints(float* points, int count) { void lovrGraphicsPoints(float* points, int count) {

View File

@ -4,7 +4,7 @@
static void lovrMeshBindAttributes(Mesh* mesh) { static void lovrMeshBindAttributes(Mesh* mesh) {
Shader* shader = lovrGraphicsGetShader(); Shader* shader = lovrGraphicsGetShader();
if (!shader || (shader == mesh->lastShader && !mesh->attributesDirty)) { if (!shader || (shader == mesh->lastShader && !mesh->attributesDirty && GLAD_GL_VERSION_3_0)) {
return; return;
} }
@ -20,8 +20,12 @@ static void lovrMeshBindAttributes(Mesh* mesh) {
if (location >= 0 && (mesh->enabledAttributes & (1 << i))) { if (location >= 0 && (mesh->enabledAttributes & (1 << i))) {
glEnableVertexAttribArray(location); glEnableVertexAttribArray(location);
if (attribute.type == MESH_INT) { if (attribute.type == MESH_INT ) {
glVertexAttribIPointer(location, attribute.count, attribute.type, mesh->stride, (void*) offset); if (GLAD_GL_ES_VERSION_2_0) {
error("Integer attributes are not supported on this platform.");
} else {
glVertexAttribIPointer(location, attribute.count, attribute.type, mesh->stride, (void*) offset);
}
} else { } else {
glVertexAttribPointer(location, attribute.count, attribute.type, GL_FALSE, mesh->stride, (void*) offset); glVertexAttribPointer(location, attribute.count, attribute.type, GL_FALSE, mesh->stride, (void*) offset);
} }
@ -65,6 +69,7 @@ Mesh* lovrMeshCreate(int count, MeshFormat* format, MeshDrawMode drawMode, MeshU
return NULL; return NULL;
} }
mesh->data = NULL;
mesh->count = count; mesh->count = count;
mesh->stride = stride; mesh->stride = stride;
mesh->enabledAttributes = ~0; mesh->enabledAttributes = ~0;
@ -83,9 +88,15 @@ Mesh* lovrMeshCreate(int count, MeshFormat* format, MeshDrawMode drawMode, MeshU
glGenBuffers(1, &mesh->vbo); glGenBuffers(1, &mesh->vbo);
glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
glBufferData(GL_ARRAY_BUFFER, mesh->count * mesh->stride, NULL, mesh->usage); glBufferData(GL_ARRAY_BUFFER, mesh->count * mesh->stride, NULL, mesh->usage);
glGenVertexArrays(1, &mesh->vao); if (GLAD_GL_VERSION_3_0) {
glGenVertexArrays(1, &mesh->vao);
}
glGenBuffers(1, &mesh->ibo); glGenBuffers(1, &mesh->ibo);
if (!GLAD_GL_VERSION_3_0 && !GL_ARB_map_buffer_range) {
mesh->data = malloc(mesh->count * mesh->stride);
}
return mesh; return mesh;
} }
@ -95,9 +106,12 @@ void lovrMeshDestroy(const Ref* ref) {
lovrRelease(&mesh->texture->ref); lovrRelease(&mesh->texture->ref);
} }
glDeleteBuffers(1, &mesh->vbo); glDeleteBuffers(1, &mesh->vbo);
glDeleteVertexArrays(1, &mesh->vao); if (GLAD_GL_VERSION_3_0) {
glDeleteVertexArrays(1, &mesh->vao);
}
vec_deinit(&mesh->map); vec_deinit(&mesh->map);
vec_deinit(&mesh->format); vec_deinit(&mesh->format);
free(mesh->data);
free(mesh); free(mesh);
} }
@ -113,7 +127,10 @@ void lovrMeshDraw(Mesh* mesh, mat4 transform) {
lovrGraphicsBindTexture(mesh->texture); lovrGraphicsBindTexture(mesh->texture);
lovrGraphicsPrepare(); lovrGraphicsPrepare();
glBindVertexArray(mesh->vao); if (GLAD_GL_VERSION_3_0) {
glBindVertexArray(mesh->vao);
}
lovrMeshBindAttributes(mesh); lovrMeshBindAttributes(mesh);
int start, count; int start, count;
@ -245,6 +262,12 @@ void lovrMeshSetTexture(Mesh* mesh, Texture* texture) {
} }
void* lovrMeshMap(Mesh* mesh, int start, int count) { void* lovrMeshMap(Mesh* mesh, int start, int count) {
if (!GLAD_GL_VERSION_3_0 && !GLAD_GL_ARB_map_buffer_range) {
mesh->isMapped = 1;
mesh->mapStart = start;
mesh->mapCount = count;
return (char*) mesh->data + start * mesh->stride;
}
// Unmap because the mapped ranges aren't necessarily the same. Could be improved. // Unmap because the mapped ranges aren't necessarily the same. Could be improved.
if (mesh->isMapped && (mesh->mapStart != start || mesh->mapCount != count)) { if (mesh->isMapped && (mesh->mapStart != start || mesh->mapCount != count)) {
@ -260,6 +283,16 @@ void* lovrMeshMap(Mesh* mesh, int start, int count) {
} }
void lovrMeshUnmap(Mesh* mesh) { void lovrMeshUnmap(Mesh* mesh) {
if (!GLAD_GL_VERSION_3_0 && !GLAD_GL_ARB_map_buffer_range) {
mesh->isMapped = 0;
int start = mesh->mapStart * mesh->stride;
int count = mesh->mapCount * mesh->stride;
char* data = (char*) mesh->data + count;
glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
glBufferSubData(GL_ARRAY_BUFFER, start, count, data);
return;
}
if (mesh->isMapped) { if (mesh->isMapped) {
mesh->isMapped = 0; mesh->isMapped = 0;
glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ARRAY_BUFFER);

View File

@ -35,6 +35,7 @@ typedef vec_t(MeshAttribute) MeshFormat;
typedef struct { typedef struct {
Ref ref; Ref ref;
void* data;
int count; int count;
int stride; int stride;
int enabledAttributes; int enabledAttributes;

View File

@ -4,22 +4,37 @@
#include <stdlib.h> #include <stdlib.h>
const char* lovrShaderVertexPrefix = "" const char* lovrShaderVertexPrefix = ""
#ifdef EMSCRIPTEN
"#version 100 \n"
"precision mediump float; \n"
"attribute vec3 lovrPosition; \n"
"attribute vec3 lovrNormal; \n"
"attribute vec2 lovrTexCoord; \n"
"varying vec2 texCoord; \n"
#else
"#version 150 \n" "#version 150 \n"
"uniform mat4 lovrTransform; \n"
"uniform mat4 lovrProjection; \n"
"in vec3 lovrPosition; \n" "in vec3 lovrPosition; \n"
"in vec3 lovrNormal; \n" "in vec3 lovrNormal; \n"
"in vec2 lovrTexCoord; \n" "in vec2 lovrTexCoord; \n"
"out vec2 texCoord; \n" "out vec2 texCoord; \n"
#endif
"uniform mat4 lovrTransform; \n"
"uniform mat4 lovrProjection; \n"
""; "";
const char* lovrShaderFragmentPrefix = "" const char* lovrShaderFragmentPrefix = ""
#ifdef EMSCRIPTEN
"#version 100 \n"
"precision mediump float; \n"
"varying vec2 texCoord; \n"
#else
"#version 150 \n" "#version 150 \n"
"uniform vec4 lovrColor; \n"
"uniform sampler2D lovrTexture; \n"
"in vec2 texCoord; \n" "in vec2 texCoord; \n"
"in vec4 gl_FragCoord; \n" "in vec4 gl_FragCoord; \n"
"out vec4 lovrFragColor; \n" "out vec4 lovrFragColor; \n"
#endif
"uniform vec4 lovrColor; \n"
"uniform sampler2D lovrTexture; \n"
""; "";
const char* lovrShaderVertexSuffix = "" const char* lovrShaderVertexSuffix = ""
@ -31,7 +46,11 @@ const char* lovrShaderVertexSuffix = ""
const char* lovrShaderFragmentSuffix = "" const char* lovrShaderFragmentSuffix = ""
"void main() { \n" "void main() { \n"
#ifdef EMSCRIPTEN
" gl_FragColor = color(lovrColor, lovrTexture, texCoord); \n"
#else
" lovrFragColor = color(lovrColor, lovrTexture, texCoord); \n" " lovrFragColor = color(lovrColor, lovrTexture, texCoord); \n"
#endif
"}" "}"
""; "";
@ -43,12 +62,20 @@ const char* lovrDefaultVertexShader = ""
const char* lovrDefaultFragmentShader = "" const char* lovrDefaultFragmentShader = ""
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n" "vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
#ifdef EMSCRIPTEN
" return graphicsColor * texture2D(image, uv); \n"
#else
" return graphicsColor * texture(image, uv); \n" " return graphicsColor * texture(image, uv); \n"
#endif
"}" "}"
""; "";
const char* lovrSkyboxVertexShader = "" const char* lovrSkyboxVertexShader = ""
#ifdef EMSCRIPTEN
"varying vec3 texturePosition; \n"
#else
"out vec3 texturePosition; \n" "out vec3 texturePosition; \n"
#endif
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n" "vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
" texturePosition = vertex.xyz; \n" " texturePosition = vertex.xyz; \n"
" return projection * transform * vertex; \n" " return projection * transform * vertex; \n"
@ -56,11 +83,19 @@ const char* lovrSkyboxVertexShader = ""
""; "";
const char* lovrSkyboxFragmentShader = "" const char* lovrSkyboxFragmentShader = ""
#ifdef EMSCRIPTEN
"varying vec3 texturePosition; \n"
"uniform samplerCube cube; \n"
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
" return graphicsColor * textureCube(cube, texturePosition); \n"
"}"
#else
"in vec3 texturePosition; \n" "in vec3 texturePosition; \n"
"uniform samplerCube cube; \n" "uniform samplerCube cube; \n"
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n" "vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
" return graphicsColor * texture(cube, texturePosition); \n" " return graphicsColor * texture(cube, texturePosition); \n"
"}" "}"
#endif
""; "";
const char* lovrNoopVertexShader = "" const char* lovrNoopVertexShader = ""

View File

@ -3,11 +3,24 @@
#include "math/mat4.h" #include "math/mat4.h"
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
static GLenum getGLFormat(TextureFormat format) { static GLenum getGLFormat(TextureFormat format) {
switch (format) { switch (format) {
case FORMAT_RED: return GL_RED; case FORMAT_RED:
case FORMAT_RG: return GL_RG; if (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_texture_rg || GLAD_GL_EXT_texture_rg) {
return GL_RED;
} else {
return GL_LUMINANCE;
}
case FORMAT_RG:
if (GLAD_GL_VERSION_3_0 || GLAD_GL_ARB_texture_rg || GLAD_GL_EXT_texture_rg) {
return GL_RG;
} else {
return GL_LUMINANCE_ALPHA;
}
case FORMAT_RGB: return GL_RGB; case FORMAT_RGB: return GL_RGB;
case FORMAT_RGBA: return GL_RGBA; case FORMAT_RGBA: return GL_RGBA;
} }
@ -177,6 +190,10 @@ void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertic
} }
void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical) { void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical) {
if (GLAD_GL_ES_VERSION_2_0) {
horizontal = vertical = WRAP_CLAMP;
}
texture->wrapHorizontal = horizontal; texture->wrapHorizontal = horizontal;
texture->wrapVertical = vertical; texture->wrapVertical = vertical;
lovrGraphicsBindTexture(texture); lovrGraphicsBindTexture(texture);

View File

@ -1,5 +1,4 @@
#include "headset/headset.h" #include "headset/headset.h"
#include "headset/openvr.h"
#include "event/event.h" #include "event/event.h"
void lovrControllerDestroy(const Ref* ref) { void lovrControllerDestroy(const Ref* ref) {

141
src/headset/webvr.c Normal file
View File

@ -0,0 +1,141 @@
#include "headset/headset.h"
#include "graphics/graphics.h"
#include <emscripten.h>
#include <emscripten/vr.h>
static headsetRenderCallback renderCallback;
static void onRequestAnimationFrame(void* userdata) {
lovrGraphicsSetBackgroundColor(1, 0, 0, 1);
lovrGraphicsClear(1, 1);
printf("Yay rendering!\n");
int width = emscripten_vr_get_display_width();
int height = emscripten_vr_get_display_height();
glViewport(0, 0, width, height);
renderCallback(EYE_LEFT, userdata);
glViewport(width, 0, width, height);
renderCallback(EYE_RIGHT, userdata);
}
void lovrHeadsetInit() {
emscripten_vr_init();
}
void lovrHeadsetDestroy() {
//
}
void lovrHeadsetPoll() {
//
}
int lovrHeadsetIsPresent() {
return emscripten_vr_is_present();
}
const char* lovrHeadsetGetType() {
return "WebVR";
}
int lovrHeadsetIsMirrored() {
return 0;
}
void lovrHeadsetSetMirrored(int mirror) {
//
}
void lovrHeadsetGetDisplayDimensions(int* width, int* height) {
*width = *height = 0;
}
void lovrHeadsetGetClipDistance(float* near, float* far) {
*near = *far = 0;
}
void lovrHeadsetSetClipDistance(float near, float far) {
//
}
float lovrHeadsetGetBoundsWidth() {
return 0;
}
float lovrHeadsetGetBoundsDepth() {
return 0;
}
void lovrHeadsetGetBoundsGeometry(float* geometry) {
geometry = NULL;
}
char lovrHeadsetIsBoundsVisible() {
return 0;
}
void lovrHeadsetSetBoundsVisible(char visible) {
//
}
void lovrHeadsetGetPosition(float* x, float* y, float* z) {
*x = *y = *z = 0;
}
void lovrHeadsetGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) {
*x = *y = *z = 0;
}
void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float* z) {
*angle = *x = *y = *z = 0;
}
void lovrHeadsetGetVelocity(float* x, float* y, float* z) {
*x = *y = *z = 0;
}
void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) {
*x = *y = *z = 0;
}
vec_controller_t* lovrHeadsetGetControllers() {
return NULL;
}
int lovrHeadsetControllerIsPresent(Controller* controller) {
return 0;
}
void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y, float* z) {
*x = *y = *z = 0;
}
void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) {
*angle = *x = *y = *z = 0;
}
float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) {
return 0;
}
int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button) {
return 0;
}
void lovrHeadsetControllerVibrate(Controller* controller, float duration) {
//
}
ModelData* lovrHeadsetControllerNewModelData(Controller* controller) {
return NULL;
}
TextureData* lovrHeadsetControllerNewTextureData(Controller* controller) {
return NULL;
}
void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) {
renderCallback = callback;
emscripten_vr_set_render_callback(onRequestAnimationFrame, userdata);
}

View File

@ -1,4 +1,6 @@
GL_ARB_vertex_array_object
GL_ARB_framebuffer_object GL_ARB_framebuffer_object
GL_ARB_map_buffer_range GL_ARB_map_buffer_range
GL_ARB_texture_rg GL_ARB_texture_rg
GL_EXT_texture_rg
GL_EXT_blend_minmax
GL_OES_texture_npot

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@
#ifdef _WIN32 #ifdef _WIN32
#define APIENTRY __stdcall #define APIENTRY __stdcall
#elif EMSCRIPTEN
#define GLFW_INCLUDE_ES2
#endif #endif
#include "lib/glad/glad.h" #include "lib/glad/glad.h"

View File

@ -104,6 +104,39 @@ void lovrDestroy(int exitCode) {
exit(exitCode); exit(exitCode);
} }
#ifdef EMSCRIPTEN
#include <emscripten.h>
static void emscriptenLoop(void* arg) {
lua_State* L = arg;
// lovr.step
lua_getglobal(L, "lovr");
if (lua_isnil(L, -1)) {
return;
}
lua_getfield(L, -1, "step");
if (lua_isnil(L, -1)) {
return;
}
lua_call(L, 0, 0);
}
void lovrRun(lua_State* L) {
// lovr.load
lua_getglobal(L, "lovr");
if (!lua_isnil(L, -1)) {
lua_getfield(L, -1, "load");
if (!lua_isnil(L, -1)) {
lua_call(L, 0, 0);
}
}
emscripten_set_main_loop_arg(emscriptenLoop, (void*) L, 0, 1);
}
#else
void lovrRun(lua_State* L) { void lovrRun(lua_State* L) {
lua_pushcfunction(L, getStackTrace); lua_pushcfunction(L, getStackTrace);
@ -129,3 +162,4 @@ void lovrRun(lua_State* L) {
lovrDestroy(exitCode); lovrDestroy(exitCode);
} }
#endif