mirror of https://github.com/bjornbytes/lovr.git
Merge branch 'master' into fake-headset
This commit is contained in:
commit
a22a9ed1f4
|
@ -27,8 +27,9 @@ set(ASSIMP_BUILD_TESTS OFF CACHE BOOL "")
|
|||
set(ASSIMP_NO_EXPORT ON OFF CACHE BOOL "")
|
||||
set(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT OFF CACHE BOOL "")
|
||||
set(ASSIMP_BUILD_COLLADA_IMPORTER ON CACHE BOOL "")
|
||||
set(ASSIMP_BUILD_OBJ_IMPORTER ON CACHE BOOL "")
|
||||
set(ASSIMP_BUILD_FBX_IMPORTER ON CACHE BOOL "")
|
||||
set(ASSIMP_BUILD_GLTF_IMPORTER ON CACHE BOOL "")
|
||||
set(ASSIMP_BUILD_OBJ_IMPORTER ON CACHE BOOL "")
|
||||
if(EMSCRIPTEN)
|
||||
set(ZLIB_FOUND 1)
|
||||
set(ZLIB_LIBRARIES "-s USE_ZLIB=1")
|
||||
|
@ -197,11 +198,11 @@ set(PHYSFS_BUILD_WX_TEST FALSE CACHE BOOL "")
|
|||
if(EMSCRIPTEN)
|
||||
option(PHYSFS_ARCHIVE_ZIP OFF)
|
||||
add_subdirectory(deps/physfs physfs)
|
||||
include_directories(deps/physfs)
|
||||
include_directories(deps/physfs/src)
|
||||
set(LOVR_PHYSFS physfs)
|
||||
elseif(WIN32)
|
||||
add_subdirectory(deps/physfs physfs)
|
||||
include_directories(deps/physfs)
|
||||
include_directories(deps/physfs/src)
|
||||
set(LOVR_PHYSFS physfs)
|
||||
else()
|
||||
find_package(PhysFS REQUIRED)
|
||||
|
@ -224,12 +225,12 @@ set(LOVR_SRC
|
|||
src/api/types/controller.c
|
||||
src/api/types/font.c
|
||||
src/api/types/joints.c
|
||||
src/api/types/material.c
|
||||
src/api/types/mesh.c
|
||||
src/api/types/model.c
|
||||
src/api/types/randomGenerator.c
|
||||
src/api/types/shader.c
|
||||
src/api/types/shapes.c
|
||||
src/api/types/skybox.c
|
||||
src/api/types/source.c
|
||||
src/api/types/texture.c
|
||||
src/api/types/transform.c
|
||||
|
@ -238,13 +239,15 @@ set(LOVR_SRC
|
|||
src/audio/source.c
|
||||
src/event/event.c
|
||||
src/filesystem/blob.c
|
||||
src/filesystem/file.c
|
||||
src/filesystem/filesystem.c
|
||||
src/graphics/font.c
|
||||
src/graphics/graphics.c
|
||||
src/graphics/material.c
|
||||
src/graphics/mesh.c
|
||||
src/graphics/model.c
|
||||
src/graphics/shader.c
|
||||
src/graphics/skybox.c
|
||||
src/graphics/shaders.c
|
||||
src/graphics/texture.c
|
||||
src/headset/fake.c
|
||||
src/headset/headset.c
|
||||
|
@ -259,6 +262,7 @@ set(LOVR_SRC
|
|||
src/lib/stb/stb_vorbis.c
|
||||
src/lib/vec/vec.c
|
||||
src/loaders/font.c
|
||||
src/loaders/material.c
|
||||
src/loaders/model.c
|
||||
src/loaders/source.c
|
||||
src/loaders/texture.c
|
||||
|
@ -306,6 +310,10 @@ target_link_libraries(lovr
|
|||
)
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(lovr PROPERTIES COMPILE_FLAGS "/wd4244")
|
||||
set_target_properties(lovr PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(lovr PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
|
||||
|
||||
function(move_dll ARG_TARGET)
|
||||
add_custom_command(TARGET lovr POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
|
|
10
COMPILING.md
10
COMPILING.md
|
@ -75,12 +75,20 @@ lovr /path/to/myGame
|
|||
Linux
|
||||
---
|
||||
|
||||
On Arch Linux, first install necessary dependencies:
|
||||
First, install the dependencies using your package manager of choice.
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
```sh
|
||||
pacman -S assimp glfw-x11 luajit physfs freetype2 openal ode
|
||||
```
|
||||
|
||||
#### Debian/Ubuntu
|
||||
|
||||
```sh
|
||||
sudo apt-get install build-essential cmake libassimp-dev libglfw3-dev libluajit-5.1-dev libphysfs-dev libfreetype6-dev libopenal-dev libode-dev
|
||||
```
|
||||
|
||||
Then, build with CMake:
|
||||
|
||||
```sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit abb9a4c8b6d16389ca5a519c18b25f34249c3426
|
||||
Subproject commit 68beaa110991cb5002c8dc3a3d61718845046e79
|
|
@ -23,11 +23,12 @@ Blob* luax_readblob(lua_State* L, int index, const char* debug) {
|
|||
}
|
||||
}
|
||||
|
||||
static void pushDirectoryItem(void* userdata, const char* path, const char* filename) {
|
||||
static int pushDirectoryItem(void* userdata, const char* path, const char* filename) {
|
||||
lua_State* L = userdata;
|
||||
int n = lua_objlen(L, -1);
|
||||
lua_pushstring(L, filename);
|
||||
lua_rawseti(L, -2, n + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Loader to help Lua's require understand PhysFS.
|
||||
|
@ -122,12 +123,6 @@ int l_lovrFilesystemCreateDirectory(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrFilesystemExists(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
lua_pushboolean(L, lovrFilesystemExists(path));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrFilesystemGetAppdataDirectory(lua_State* L) {
|
||||
char buffer[1024];
|
||||
|
||||
|
@ -195,7 +190,11 @@ int l_lovrFilesystemGetSaveDirectory(lua_State* L) {
|
|||
|
||||
int l_lovrFilesystemGetSize(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
lua_pushinteger(L, lovrFilesystemGetSize(path));
|
||||
size_t size = lovrFilesystemGetSize(path);
|
||||
if ((int) size == -1) {
|
||||
return luaL_error(L, "File does not exist");
|
||||
}
|
||||
lua_pushinteger(L, size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -322,7 +321,6 @@ int l_lovrFilesystemWrite(lua_State* L) {
|
|||
const luaL_Reg lovrFilesystem[] = {
|
||||
{ "append", l_lovrFilesystemAppend },
|
||||
{ "createDirectory", l_lovrFilesystemCreateDirectory },
|
||||
{ "exists", l_lovrFilesystemExists },
|
||||
{ "getAppdataDirectory", l_lovrFilesystemGetAppdataDirectory },
|
||||
{ "getDirectoryItems", l_lovrFilesystemGetDirectoryItems },
|
||||
{ "getExecutablePath", l_lovrFilesystemGetExecutablePath },
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "api/lovr.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/mesh.h"
|
||||
#include "graphics/model.h"
|
||||
#include "loaders/font.h"
|
||||
#include "loaders/material.h"
|
||||
#include "loaders/model.h"
|
||||
#include "loaders/texture.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
|
@ -14,6 +16,8 @@ map_int_t CompareModes;
|
|||
map_int_t DrawModes;
|
||||
map_int_t FilterModes;
|
||||
map_int_t HorizontalAligns;
|
||||
map_int_t MaterialColors;
|
||||
map_int_t MaterialTextures;
|
||||
map_int_t MatrixTypes;
|
||||
map_int_t MeshAttributeTypes;
|
||||
map_int_t MeshDrawModes;
|
||||
|
@ -63,24 +67,16 @@ static void luax_readvertices(lua_State* L, int index, vec_float_t* points) {
|
|||
}
|
||||
}
|
||||
|
||||
static Texture* luax_readtexture(lua_State* L, int index) {
|
||||
Blob* blob = luax_readblob(L, index, "Texture");
|
||||
TextureData* textureData = lovrTextureDataFromBlob(blob);
|
||||
Texture* texture = lovrTextureCreate(textureData);
|
||||
lovrRelease(&blob->ref);
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Base
|
||||
|
||||
int l_lovrGraphicsInit(lua_State* L) {
|
||||
lua_newtable(L);
|
||||
luaL_register(L, NULL, lovrGraphics);
|
||||
luax_registertype(L, "Font", lovrFont);
|
||||
luax_registertype(L, "Material", lovrMaterial);
|
||||
luax_registertype(L, "Mesh", lovrMesh);
|
||||
luax_registertype(L, "Model", lovrModel);
|
||||
luax_registertype(L, "Shader", lovrShader);
|
||||
luax_registertype(L, "Skybox", lovrSkybox);
|
||||
luax_registertype(L, "Texture", lovrTexture);
|
||||
|
||||
map_init(&BlendAlphaModes);
|
||||
|
@ -120,6 +116,13 @@ int l_lovrGraphicsInit(lua_State* L) {
|
|||
map_set(&HorizontalAligns, "right", ALIGN_RIGHT);
|
||||
map_set(&HorizontalAligns, "center", ALIGN_CENTER);
|
||||
|
||||
map_init(&MaterialColors);
|
||||
map_set(&MaterialColors, "diffuse", COLOR_DIFFUSE);
|
||||
|
||||
map_init(&MaterialTextures);
|
||||
map_set(&MaterialTextures, "diffuse", TEXTURE_DIFFUSE);
|
||||
map_set(&MaterialTextures, "environment", TEXTURE_ENVIRONMENT_MAP);
|
||||
|
||||
map_init(&MatrixTypes);
|
||||
map_set(&MatrixTypes, "model", MATRIX_MODEL);
|
||||
map_set(&MatrixTypes, "view", MATRIX_VIEW);
|
||||
|
@ -253,26 +256,7 @@ int l_lovrGraphicsGetColor(lua_State* L) {
|
|||
}
|
||||
|
||||
int l_lovrGraphicsSetColor(lua_State* L) {
|
||||
Color color = { 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
lua_rawgeti(L, 1, i);
|
||||
}
|
||||
color.r = luaL_checknumber(L, -4);
|
||||
color.g = luaL_checknumber(L, -3);
|
||||
color.b = luaL_checknumber(L, -2);
|
||||
color.a = luaL_optnumber(L, -1, 255);
|
||||
lua_pop(L, 4);
|
||||
} else if (lua_gettop(L) >= 3) {
|
||||
color.r = lua_tointeger(L, 1);
|
||||
color.g = lua_tointeger(L, 2);
|
||||
color.b = lua_tointeger(L, 3);
|
||||
color.a = lua_isnoneornil(L, 4) ? 255 : lua_tointeger(L, 4);
|
||||
} else {
|
||||
return luaL_error(L, "Invalid color, expected 3 numbers, 4 numbers, or a table");
|
||||
}
|
||||
|
||||
Color color = luax_checkcolor(L, 1);
|
||||
lovrGraphicsSetColor(color);
|
||||
return 0;
|
||||
}
|
||||
|
@ -357,6 +341,22 @@ int l_lovrGraphicsSetLineWidth(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsGetMaterial(lua_State* L) {
|
||||
Material* material = lovrGraphicsGetMaterial();
|
||||
if (material && !material->isDefault) {
|
||||
luax_pushtype(L, Material, material);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsSetMaterial(lua_State* L) {
|
||||
Material* material = lua_isnoneornil(L, 1) ? NULL : luax_checktype(L, 1, Material);
|
||||
lovrGraphicsSetMaterial(material);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsGetPointSize(lua_State* L) {
|
||||
lua_pushnumber(L, lovrGraphicsGetPointSize());
|
||||
return 1;
|
||||
|
@ -493,36 +493,24 @@ int l_lovrGraphicsTriangle(lua_State* L) {
|
|||
}
|
||||
|
||||
int l_lovrGraphicsPlane(lua_State* L) {
|
||||
Texture* texture = NULL;
|
||||
DrawMode drawMode;
|
||||
if (lua_isstring(L, 1)) {
|
||||
drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
|
||||
} else {
|
||||
drawMode = DRAW_MODE_FILL;
|
||||
texture = luax_checktype(L, 1, Texture);
|
||||
if (lua_gettop(L) == 1) {
|
||||
if (lua_isuserdata(L, 1)) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lovrGraphicsPlaneFullscreen(texture);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DrawMode drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
|
||||
float transform[16];
|
||||
luax_readtransform(L, 2, transform, 1);
|
||||
lovrGraphicsPlane(drawMode, texture, transform);
|
||||
lovrGraphicsPlane(drawMode, transform);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luax_rectangularprism(lua_State* L, int uniformScale) {
|
||||
Texture* texture = NULL;
|
||||
DrawMode drawMode;
|
||||
if (lua_isstring(L, 1)) {
|
||||
drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
|
||||
} else {
|
||||
drawMode = DRAW_MODE_FILL;
|
||||
texture = luax_checktype(L, 1, Texture);
|
||||
}
|
||||
DrawMode drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
|
||||
float transform[16];
|
||||
luax_readtransform(L, 2, transform, uniformScale);
|
||||
lovrGraphicsBox(drawMode, texture, transform);
|
||||
lovrGraphicsBox(drawMode, transform);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -550,15 +538,21 @@ int l_lovrGraphicsCylinder(lua_State* L) {
|
|||
}
|
||||
|
||||
int l_lovrGraphicsSphere(lua_State* L) {
|
||||
Texture* texture = NULL;
|
||||
float transform[16];
|
||||
int index = 1;
|
||||
if (lua_isuserdata(L, 1) && (lua_isuserdata(L, 2) || lua_isnumber(L, 2))) {
|
||||
texture = luax_checktype(L, index++, Texture);
|
||||
}
|
||||
index = luax_readtransform(L, index, transform, 1);
|
||||
int segments = luaL_optnumber(L, index, 30);
|
||||
lovrGraphicsSphere(texture, transform, segments, NULL);
|
||||
lovrGraphicsSphere(transform, segments);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsSkybox(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
float angle = luaL_optnumber(L, 2, 0);
|
||||
float ax = luaL_optnumber(L, 3, 0);
|
||||
float ay = luaL_optnumber(L, 4, 1);
|
||||
float az = luaL_optnumber(L, 5, 0);
|
||||
lovrGraphicsSkybox(texture, angle, ax, ay, az);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -598,6 +592,13 @@ int l_lovrGraphicsNewFont(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsNewMaterial(lua_State* L) {
|
||||
MaterialData* materialData = lovrMaterialDataCreateEmpty();
|
||||
Material* material = lovrMaterialCreate(materialData, 0);
|
||||
luax_pushtype(L, Material, material);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsNewMesh(lua_State* L) {
|
||||
int size;
|
||||
int dataIndex = 0;
|
||||
|
@ -671,13 +672,6 @@ int l_lovrGraphicsNewModel(lua_State* L) {
|
|||
Blob* blob = luax_readblob(L, 1, "Model");
|
||||
ModelData* modelData = lovrModelDataCreate(blob);
|
||||
Model* model = lovrModelCreate(modelData);
|
||||
|
||||
if (lua_gettop(L) >= 2) {
|
||||
Texture* texture = luax_readtexture(L, 2);
|
||||
lovrModelSetTexture(model, texture);
|
||||
lovrRelease(&texture->ref);
|
||||
}
|
||||
|
||||
luax_pushtype(L, Model, model);
|
||||
lovrRelease(&model->ref);
|
||||
lovrRelease(&blob->ref);
|
||||
|
@ -707,51 +701,6 @@ int l_lovrGraphicsNewShader(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsNewSkybox(lua_State* L) {
|
||||
Blob* blobs[6] = { NULL };
|
||||
SkyboxType type;
|
||||
|
||||
if (lua_gettop(L) == 1 && lua_type(L, 1) == LUA_TSTRING) {
|
||||
type = SKYBOX_PANORAMA;
|
||||
blobs[0] = luax_readblob(L, 1, "Skybox");
|
||||
} else if (lua_istable(L, 1)) {
|
||||
if (lua_objlen(L, 1) != 6) {
|
||||
return luaL_argerror(L, 1, "Expected 6 strings or a table containing 6 strings");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
lua_rawgeti(L, 1, i + 1);
|
||||
|
||||
if (!lua_isstring(L, -1)) {
|
||||
return luaL_argerror(L, 1, "Expected 6 strings or a table containing 6 strings");
|
||||
}
|
||||
|
||||
blobs[i] = luax_readblob(L, -1, "Skybox");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
type = SKYBOX_CUBE;
|
||||
} else {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
blobs[i] = luax_readblob(L, i + 1, "Skybox");
|
||||
}
|
||||
|
||||
type = SKYBOX_CUBE;
|
||||
}
|
||||
|
||||
Skybox* skybox = lovrSkyboxCreate(blobs, type);
|
||||
luax_pushtype(L, Skybox, skybox);
|
||||
lovrRelease(&skybox->ref);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (blobs[i]) {
|
||||
lovrRelease(&blobs[i]->ref);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrGraphicsNewTexture(lua_State* L) {
|
||||
Texture* texture;
|
||||
|
||||
|
@ -763,7 +712,34 @@ int l_lovrGraphicsNewTexture(lua_State* L) {
|
|||
TextureData* textureData = lovrTextureDataGetEmpty(width, height, FORMAT_RGBA);
|
||||
texture = lovrTextureCreateWithFramebuffer(textureData, *projection, msaa);
|
||||
} else {
|
||||
texture = luax_readtexture(L, 1);
|
||||
Blob* blobs[6];
|
||||
int isTable = lua_istable(L, 1);
|
||||
int count = isTable ? lua_objlen(L, 1) : lua_gettop(L);
|
||||
|
||||
if (count != 1 && count != 6) {
|
||||
return luaL_error(L, "Expected 1 image for a 2D texture or 6 images for a cube texture, got %d", count);
|
||||
}
|
||||
|
||||
if (isTable) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
blobs[i] = luax_readblob(L, -1, "Texture");
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
blobs[i] = luax_readblob(L, i + 1, "Texture");
|
||||
}
|
||||
}
|
||||
|
||||
TextureData* slices[6];
|
||||
for (int i = 0; i < count; i++) {
|
||||
slices[i] = lovrTextureDataFromBlob(blobs[i]);
|
||||
lovrRelease(&blobs[i]->ref);
|
||||
}
|
||||
|
||||
TextureType type = (count == 1) ? TEXTURE_2D : TEXTURE_CUBE;
|
||||
texture = lovrTextureCreate(type, slices, count);
|
||||
}
|
||||
|
||||
luax_pushtype(L, Texture, texture);
|
||||
|
@ -796,6 +772,8 @@ const luaL_Reg lovrGraphics[] = {
|
|||
{ "getSystemLimits", l_lovrGraphicsGetSystemLimits },
|
||||
{ "getLineWidth", l_lovrGraphicsGetLineWidth },
|
||||
{ "setLineWidth", l_lovrGraphicsSetLineWidth },
|
||||
{ "getMaterial", l_lovrGraphicsGetMaterial },
|
||||
{ "setMaterial", l_lovrGraphicsSetMaterial },
|
||||
{ "getPointSize", l_lovrGraphicsGetPointSize },
|
||||
{ "setPointSize", l_lovrGraphicsSetPointSize },
|
||||
{ "getShader", l_lovrGraphicsGetShader },
|
||||
|
@ -819,12 +797,13 @@ const luaL_Reg lovrGraphics[] = {
|
|||
{ "box", l_lovrGraphicsBox },
|
||||
{ "cylinder", l_lovrGraphicsCylinder },
|
||||
{ "sphere", l_lovrGraphicsSphere },
|
||||
{ "skybox", l_lovrGraphicsSkybox },
|
||||
{ "print", l_lovrGraphicsPrint },
|
||||
{ "newFont", l_lovrGraphicsNewFont },
|
||||
{ "newMaterial", l_lovrGraphicsNewMaterial },
|
||||
{ "newMesh", l_lovrGraphicsNewMesh },
|
||||
{ "newModel", l_lovrGraphicsNewModel },
|
||||
{ "newShader", l_lovrGraphicsNewShader },
|
||||
{ "newSkybox", l_lovrGraphicsNewSkybox },
|
||||
{ "newTexture", l_lovrGraphicsNewTexture },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ extern const luaL_Reg lovrGraphics[];
|
|||
extern const luaL_Reg lovrHeadset[];
|
||||
extern const luaL_Reg lovrHingeJoint[];
|
||||
extern const luaL_Reg lovrJoint[];
|
||||
extern const luaL_Reg lovrMaterial[];
|
||||
extern const luaL_Reg lovrMath[];
|
||||
extern const luaL_Reg lovrMesh[];
|
||||
extern const luaL_Reg lovrModel[];
|
||||
|
@ -38,7 +39,6 @@ extern const luaL_Reg lovrPhysics[];
|
|||
extern const luaL_Reg lovrRandomGenerator[];
|
||||
extern const luaL_Reg lovrShader[];
|
||||
extern const luaL_Reg lovrShape[];
|
||||
extern const luaL_Reg lovrSkybox[];
|
||||
extern const luaL_Reg lovrSliderJoint[];
|
||||
extern const luaL_Reg lovrSource[];
|
||||
extern const luaL_Reg lovrSphereShape[];
|
||||
|
@ -61,6 +61,8 @@ extern map_int_t HeadsetOrigins;
|
|||
extern map_int_t HeadsetTypes;
|
||||
extern map_int_t HorizontalAligns;
|
||||
extern map_int_t JointTypes;
|
||||
extern map_int_t MaterialColors;
|
||||
extern map_int_t MaterialTextures;
|
||||
extern map_int_t MatrixTypes;
|
||||
extern map_int_t MeshAttributeTypes;
|
||||
extern map_int_t MeshDrawModes;
|
||||
|
|
|
@ -70,14 +70,8 @@ int l_lovrControllerVibrate(lua_State* L) {
|
|||
int l_lovrControllerNewModel(lua_State* L) {
|
||||
Controller* controller = luax_checktype(L, 1, Controller);
|
||||
ModelData* modelData = lovrHeadsetControllerNewModelData(controller);
|
||||
TextureData* textureData = lovrHeadsetControllerNewTextureData(controller);
|
||||
if (modelData) {
|
||||
Model* model = lovrModelCreate(modelData);
|
||||
if (textureData) {
|
||||
Texture* texture = lovrTextureCreate(textureData);
|
||||
lovrModelSetTexture(model, texture);
|
||||
lovrRelease(&texture->ref);
|
||||
}
|
||||
luax_pushtype(L, Model, model);
|
||||
lovrRelease(&model->ref);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#include "api/lovr.h"
|
||||
#include "graphics/material.h"
|
||||
|
||||
int l_lovrMaterialGetColor(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialColor colorType = *(MaterialColor*) luax_optenum(L, 2, "diffuse", &MaterialColors, "color");
|
||||
Color color = lovrMaterialGetColor(material, colorType);
|
||||
lua_pushinteger(L, color.r);
|
||||
lua_pushinteger(L, color.g);
|
||||
lua_pushinteger(L, color.b);
|
||||
lua_pushinteger(L, color.a);
|
||||
return 4;
|
||||
}
|
||||
|
||||
int l_lovrMaterialSetColor(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialColor colorType = COLOR_DIFFUSE;
|
||||
int index = 2;
|
||||
if (lua_type(L, index) == LUA_TSTRING) {
|
||||
colorType = *(MaterialColor*) luax_checkenum(L, index, &MaterialColors, "color");
|
||||
index++;
|
||||
}
|
||||
Color color = luax_checkcolor(L, index);
|
||||
lovrMaterialSetColor(material, colorType, color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMaterialGetTexture(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialTexture textureType = *(MaterialTexture*) luax_optenum(L, 2, "diffuse", &MaterialTextures, "texture");
|
||||
Texture* texture = lovrMaterialGetTexture(material, textureType);
|
||||
luax_pushtype(L, Texture, texture);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrMaterialSetTexture(lua_State* L) {
|
||||
Material* material = luax_checktype(L, 1, Material);
|
||||
MaterialTexture textureType = TEXTURE_DIFFUSE;
|
||||
int index = 2;
|
||||
if (lua_type(L, index) == LUA_TSTRING) {
|
||||
textureType = *(MaterialTexture*) luax_checkenum(L, index, &MaterialTextures, "texture");
|
||||
index++;
|
||||
}
|
||||
Texture* texture = lua_isnoneornil(L, index) ? NULL : luax_checktype(L, index, Texture);
|
||||
lovrMaterialSetTexture(material, textureType, texture);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrMaterial[] = {
|
||||
{ "getColor", l_lovrMaterialGetColor },
|
||||
{ "setColor", l_lovrMaterialSetColor },
|
||||
{ "getTexture", l_lovrMaterialGetTexture },
|
||||
{ "setTexture", l_lovrMaterialSetTexture },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -273,27 +273,30 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
|
|||
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
int count = lua_objlen(L, 2);
|
||||
unsigned int* indices = malloc(count * sizeof(unsigned int));
|
||||
int indexSize = mesh->indexSize;
|
||||
void* indices = realloc(lovrMeshGetVertexMap(mesh, NULL), indexSize * count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
free(indices);
|
||||
return luaL_error(L, "Mesh vertex map index #%d must be numeric", i);
|
||||
}
|
||||
|
||||
int index = lua_tointeger(L, -1);
|
||||
if (index > lovrMeshGetVertexCount(mesh) || index < 1) {
|
||||
free(indices);
|
||||
return luaL_error(L, "Invalid vertex map value: %d", index);
|
||||
}
|
||||
|
||||
indices[i] = index - 1;
|
||||
if (indexSize == sizeof(uint16_t)) {
|
||||
*(((uint16_t*) indices) + i) = index - 1;
|
||||
} else if (indexSize == sizeof(uint32_t)) {
|
||||
*(((uint32_t*) indices) + i) = index - 1;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lovrMeshSetVertexMap(mesh, indices, count);
|
||||
free(indices);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -336,30 +339,7 @@ int l_lovrMeshSetDrawRange(lua_State* L) {
|
|||
lovrMeshSetRangeEnabled(mesh, 1);
|
||||
int rangeStart = luaL_checkinteger(L, 2) - 1;
|
||||
int rangeCount = luaL_checkinteger(L, 3);
|
||||
if (lovrMeshSetDrawRange(mesh, rangeStart, rangeCount)) {
|
||||
return luaL_error(L, "Invalid mesh draw range (%d, %d)", rangeStart + 1, rangeCount);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMeshGetTexture(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Texture* texture = lovrMeshGetTexture(mesh);
|
||||
|
||||
if (texture) {
|
||||
luax_pushtype(L, Texture, texture);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrMeshSetTexture(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Texture* texture = lua_isnoneornil(L, 2) ? NULL : luax_checktype(L, 2, Texture);
|
||||
lovrMeshSetTexture(mesh, texture);
|
||||
lovrMeshSetDrawRange(mesh, rangeStart, rangeCount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -380,7 +360,5 @@ const luaL_Reg lovrMesh[] = {
|
|||
{ "setDrawMode", l_lovrMeshSetDrawMode },
|
||||
{ "getDrawRange", l_lovrMeshGetDrawRange },
|
||||
{ "setDrawRange", l_lovrMeshSetDrawRange },
|
||||
{ "getTexture", l_lovrMeshGetTexture },
|
||||
{ "setTexture", l_lovrMeshSetTexture },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -9,33 +9,15 @@ int l_lovrModelDraw(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrModelGetTexture(lua_State* L) {
|
||||
int l_lovrModelGetMesh(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
Texture* texture = lovrModelGetTexture(model);
|
||||
luax_pushtype(L, Texture, texture);
|
||||
Mesh* mesh = lovrModelGetMesh(model);
|
||||
luax_pushtype(L, Mesh, mesh);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrModelSetTexture(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
Texture* texture = luax_checktype(L, 2, Texture);
|
||||
lovrModelSetTexture(model, texture);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrModelGetAABB(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
float* aabb = lovrModelGetAABB(model);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
lua_pushnumber(L, aabb[i]);
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrModel[] = {
|
||||
{ "draw", l_lovrModelDraw },
|
||||
{ "getTexture", l_lovrModelGetTexture },
|
||||
{ "setTexture", l_lovrModelSetTexture },
|
||||
{ "getAABB", l_lovrModelGetAABB },
|
||||
{ "getMesh", l_lovrModelGetMesh },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -3,37 +3,39 @@
|
|||
#include "graphics/shader.h"
|
||||
#include "math/transform.h"
|
||||
|
||||
struct TempData {
|
||||
void* data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static struct TempData tempData;
|
||||
|
||||
int l_lovrShaderSend(lua_State* L) {
|
||||
Shader* shader = luax_checktype(L, 1, Shader);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
lua_settop(L, 3);
|
||||
|
||||
int id = lovrShaderGetUniformId(shader, name);
|
||||
if (id == -1) {
|
||||
Uniform* uniform = lovrShaderGetUniform(shader, name);
|
||||
|
||||
if (!uniform) {
|
||||
return luaL_error(L, "Unknown shader variable '%s'", name);
|
||||
}
|
||||
|
||||
GLenum type;
|
||||
int size;
|
||||
lovrShaderGetUniformType(shader, name, &type, &size);
|
||||
lovrGraphicsBindProgram(shader->id);
|
||||
float data[16];
|
||||
int n;
|
||||
vec_float_t values;
|
||||
vec_init(&values);
|
||||
if (!tempData.data) {
|
||||
tempData.data = malloc(uniform->size);
|
||||
} else if (tempData.size < uniform->size) {
|
||||
tempData.size = uniform->size;
|
||||
tempData.data = realloc(tempData.data, tempData.size);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_CUBE:
|
||||
case GL_INT:
|
||||
lovrShaderSendInt(shader, id, luaL_checkinteger(L, 3));
|
||||
break;
|
||||
int* ints = (int*) tempData.data;
|
||||
float* floats = (float*) tempData.data;
|
||||
Texture** textures = (Texture**) tempData.data;
|
||||
|
||||
case GL_FLOAT:
|
||||
lovrShaderSendFloat(shader, id, luaL_checknumber(L, 3));
|
||||
break;
|
||||
int n = 1;
|
||||
int components = uniform->components;
|
||||
|
||||
case GL_FLOAT_VEC2:
|
||||
if (components > 1) {
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
lua_rawgeti(L, 3, 1);
|
||||
if (!lua_istable(L, -1)) {
|
||||
|
@ -45,121 +47,90 @@ int l_lovrShaderSend(lua_State* L) {
|
|||
}
|
||||
|
||||
n = lua_objlen(L, -1);
|
||||
if (n < size) {
|
||||
return luaL_error(L, "Expected %d vec3s, got %d", size, n);
|
||||
if (n != uniform->count) {
|
||||
const char* elements = uniform->count == 1 ? "element" : "elements";
|
||||
return luaL_error(L, "Expected %d %s for array '%s', got %d", uniform->count, elements, uniform->name, n);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
for (int j = 0; j < 2; j++) {
|
||||
lua_rawgeti(L, -1, j + 1);
|
||||
vec_push(&values, lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lovrShaderSendFloatVec2(shader, id, size, values.data);
|
||||
break;
|
||||
|
||||
case GL_FLOAT_VEC3:
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
lua_rawgeti(L, 3, 1);
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_newtable(L);
|
||||
lua_pushvalue(L, 3);
|
||||
lua_rawseti(L, -2, 1);
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_FLOAT:
|
||||
if (components == 1) {
|
||||
floats[0] = luaL_checkinteger(L, 3);
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
n = lua_objlen(L, -1);
|
||||
if (n < size) {
|
||||
return luaL_error(L, "Expected %d vec3s, got %d", size, n);
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
for (int i = 0; i < n; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (lua_type(L, -1) != LUA_TTABLE || (int) lua_objlen(L, -1) != components) {
|
||||
return luaL_error(L, "Expected %d components for uniform '%s' #%d, got %d", components, uniform->name, lua_objlen(L, -1));
|
||||
}
|
||||
for (int j = 0; j < components; j++) {
|
||||
lua_rawgeti(L, -1, j + 1);
|
||||
vec_push(&values, lua_tonumber(L, -1));
|
||||
floats[i * components + j] = luaL_checknumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lovrShaderSendFloatVec3(shader, id, size, values.data);
|
||||
}
|
||||
lovrShaderSetFloat(shader, name, floats, n);
|
||||
break;
|
||||
|
||||
case GL_FLOAT_VEC4:
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
lua_rawgeti(L, 3, 1);
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_newtable(L);
|
||||
lua_pushvalue(L, 3);
|
||||
lua_rawseti(L, -2, 1);
|
||||
case UNIFORM_INT:
|
||||
if (components == 1) {
|
||||
ints[0] = luaL_checkinteger(L, 3);
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
n = lua_objlen(L, -1);
|
||||
if (n < size) {
|
||||
return luaL_error(L, "Expected %d vec3s, got %d", size, n);
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
for (int i = 0; i < n; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (lua_type(L, -1) != LUA_TTABLE || (int) lua_objlen(L, -1) != components) {
|
||||
return luaL_error(L, "Expected %d components for uniform '%s' #%d, got %d", components, uniform->name, lua_objlen(L, -1));
|
||||
}
|
||||
for (int j = 0; j < components; j++) {
|
||||
lua_rawgeti(L, -1, j + 1);
|
||||
vec_push(&values, lua_tonumber(L, -1));
|
||||
ints[i * components + j] = luaL_checkinteger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lovrShaderSendFloatVec4(shader, id, size, values.data);
|
||||
}
|
||||
lovrShaderSetInt(shader, name, ints, n);
|
||||
break;
|
||||
|
||||
case GL_FLOAT_MAT2:
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
lua_rawgeti(L, 3, i + 1);
|
||||
data[i] = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lovrShaderSendFloatMat2(shader, id, data);
|
||||
break;
|
||||
|
||||
case GL_FLOAT_MAT3:
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
lua_rawgeti(L, 3, i + 1);
|
||||
data[i] = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lovrShaderSendFloatMat3(shader, id, data);
|
||||
break;
|
||||
|
||||
case GL_FLOAT_MAT4:
|
||||
if (lua_isuserdata(L, 3)) {
|
||||
case UNIFORM_MATRIX:
|
||||
if (components == 4 && lua_isuserdata(L, 3)) {
|
||||
Transform* transform = luax_checktype(L, 3, Transform);
|
||||
memcpy(data, transform->matrix, 16 * sizeof(float));
|
||||
memcpy(floats, transform->matrix, 16 * sizeof(float));
|
||||
} else {
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
lua_rawgeti(L, 3, i + 1);
|
||||
data[i] = lua_tonumber(L, -1);
|
||||
for (int i = 0; i < n; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
for (int j = 0; j < components * components; j++) {
|
||||
lua_rawgeti(L, -1, j + 1);
|
||||
floats[i * components * components + j] = luaL_checknumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lovrShaderSendFloatMat4(shader, id, data);
|
||||
lovrShaderSetMatrix(shader, name, floats, n);
|
||||
break;
|
||||
|
||||
default:
|
||||
return luaL_error(L, "Unknown uniform type %d", type);
|
||||
case UNIFORM_SAMPLER:
|
||||
if (components == 1) {
|
||||
textures[0] = luax_checktype(L, 3, Texture);
|
||||
} else {
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
for (int i = 0; i < n; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
textures[i] = luax_checktype(L, -1, Texture);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lovrShaderSetTexture(shader, name, textures, n);
|
||||
break;
|
||||
|
||||
vec_deinit(&values);
|
||||
default: break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#include "api/lovr.h"
|
||||
#include "graphics/graphics.h"
|
||||
|
||||
int l_lovrSkyboxDraw(lua_State* L) {
|
||||
Skybox* skybox = luax_checktype(L, 1, Skybox);
|
||||
float angle = luaL_optnumber(L, 2, 0.f);
|
||||
float ax = luaL_optnumber(L, 3, 0.f);
|
||||
float ay = luaL_optnumber(L, 4, 0.f);
|
||||
float az = luaL_optnumber(L, 5, 0.f);
|
||||
lovrGraphicsSkybox(skybox, angle, ax, ay, az);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrSkybox[] = {
|
||||
{ "draw", l_lovrSkyboxDraw },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
int l_lovrTextureGetDimensions(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushnumber(L, lovrTextureGetWidth(texture));
|
||||
lua_pushnumber(L, lovrTextureGetHeight(texture));
|
||||
lua_pushnumber(L, texture->width);
|
||||
lua_pushnumber(L, texture->height);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -21,33 +21,36 @@ int l_lovrTextureGetFilter(lua_State* L) {
|
|||
|
||||
int l_lovrTextureGetHeight(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushnumber(L, lovrTextureGetHeight(texture));
|
||||
lua_pushnumber(L, texture->height);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrTextureGetWidth(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lua_pushnumber(L, lovrTextureGetWidth(texture));
|
||||
lua_pushnumber(L, texture->width);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrTextureGetWrap(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
WrapMode horizontal, vertical;
|
||||
lovrTextureGetWrap(texture, &horizontal, &vertical);
|
||||
luax_pushenum(L, &WrapModes, horizontal);
|
||||
luax_pushenum(L, &WrapModes, vertical);
|
||||
TextureWrap wrap = lovrTextureGetWrap(texture);
|
||||
luax_pushenum(L, &WrapModes, wrap.s);
|
||||
luax_pushenum(L, &WrapModes, wrap.t);
|
||||
if (texture->type == TEXTURE_CUBE) {
|
||||
luax_pushenum(L, &WrapModes, wrap.r);
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
int l_lovrTextureRenderTo(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
lovrGraphicsPushCanvas();
|
||||
lovrGraphicsPushView();
|
||||
lovrTextureBindFramebuffer(texture);
|
||||
lua_settop(L, 2);
|
||||
lua_call(L, 0, 0);
|
||||
lovrTextureResolveMSAA(texture);
|
||||
lovrGraphicsPopCanvas();
|
||||
lovrGraphicsPopView();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -62,9 +65,11 @@ int l_lovrTextureSetFilter(lua_State* L) {
|
|||
|
||||
int l_lovrTextureSetWrap(lua_State* L) {
|
||||
Texture* texture = luax_checktype(L, 1, Texture);
|
||||
WrapMode* horizontal = (WrapMode*) luax_checkenum(L, 2, &WrapModes, "wrap mode");
|
||||
WrapMode* vertical = (WrapMode*) luax_optenum(L, 3, luaL_checkstring(L, 2), &WrapModes, "wrap mode");
|
||||
lovrTextureSetWrap(texture, *horizontal, *vertical);
|
||||
TextureWrap wrap;
|
||||
wrap.s = *(WrapMode*) luax_checkenum(L, 2, &WrapModes, "wrap mode");
|
||||
wrap.t = *(WrapMode*) luax_optenum(L, 3, luaL_checkstring(L, 2), &WrapModes, "wrap mode");
|
||||
wrap.r = *(WrapMode*) luax_optenum(L, 4, luaL_checkstring(L, 2), &WrapModes, "wrap mode");
|
||||
lovrTextureSetWrap(texture, wrap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,8 @@ if not lovr.filesystem.getSource() or not runnable then
|
|||
local logo, controllers
|
||||
|
||||
function lovr.load()
|
||||
logo = lovr.graphics.newTexture(lovr.filesystem.newBlob(lovr._logo, 'logo.png'))
|
||||
logo = lovr.graphics.newMaterial()
|
||||
logo:setTexture(lovr.graphics.newTexture(lovr.filesystem.newBlob(lovr._logo, 'logo.png')))
|
||||
lovr.graphics.setBackgroundColor(245, 252, 255)
|
||||
refreshControllers()
|
||||
end
|
||||
|
@ -97,7 +98,9 @@ if not lovr.filesystem.getSource() or not runnable then
|
|||
local titlePosition = 1.3 - padding
|
||||
local subtitlePosition = titlePosition - font:getHeight() * .25 - padding
|
||||
|
||||
lovr.graphics.plane(logo, 0, 1.8, -3, 1, 0, 0, 1)
|
||||
lovr.graphics.setMaterial(logo)
|
||||
lovr.graphics.plane('fill', 0, 1.8, -3, 1, 0, 0, 1)
|
||||
lovr.graphics.setMaterial()
|
||||
lovr.graphics.setColor(15, 15, 15)
|
||||
lovr.graphics.print('LÖVR', -.01, titlePosition, -3, .25, 0, 0, 1, 0, nil, 'center', 'top')
|
||||
lovr.graphics.setColor(15, 15, 15, fade)
|
||||
|
|
|
@ -174,353 +174,363 @@ unsigned char boot_lua[] = {
|
|||
0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x6f, 0x67, 0x6f, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77,
|
||||
0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x28, 0x29, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x6c, 0x6f, 0x67, 0x6f, 0x3a, 0x73, 0x65, 0x74, 0x54,
|
||||
0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77,
|
||||
0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e,
|
||||
0x6e, 0x65, 0x77, 0x42, 0x6c, 0x6f, 0x62, 0x28, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x5f, 0x6c, 0x6f, 0x67, 0x6f, 0x2c, 0x20, 0x27, 0x6c, 0x6f, 0x67,
|
||||
0x6f, 0x2e, 0x70, 0x6e, 0x67, 0x27, 0x29, 0x29, 0x0a, 0x20, 0x20, 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, 0x34,
|
||||
0x35, 0x2c, 0x20, 0x32, 0x35, 0x32, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
|
||||
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x28,
|
||||
0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x66,
|
||||
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x20, 0x20, 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,
|
||||
0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35,
|
||||
0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x6d,
|
||||
0x6f, 0x64, 0x65, 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72,
|
||||
0x73, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20,
|
||||
0x7a, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x3a, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d,
|
||||
0x6f, 0x64, 0x65, 0x6c, 0x3a, 0x64, 0x72, 0x61, 0x77, 0x28, 0x78, 0x2c,
|
||||
0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x3a, 0x67, 0x65, 0x74,
|
||||
0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28,
|
||||
0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61,
|
||||
0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x2e, 0x31, 0x0a, 0x20,
|
||||
0x20, 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, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x20, 0x66, 0x61, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x38, 0x30, 0x20,
|
||||
0x2b, 0x20, 0x31, 0x35, 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74, 0x68,
|
||||
0x2e, 0x61, 0x62, 0x73, 0x28, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x73, 0x69,
|
||||
0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72,
|
||||
0x2e, 0x67, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x28, 0x29, 0x20, 0x2a,
|
||||
0x20, 0x32, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
|
||||
0x61, 0x6c, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x33, 0x20, 0x2d,
|
||||
0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x62, 0x74, 0x69,
|
||||
0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20,
|
||||
0x3d, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x3a, 0x67,
|
||||
0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20, 0x2a,
|
||||
0x20, 0x2e, 0x32, 0x35, 0x20, 0x2d, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69,
|
||||
0x6e, 0x67, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x6c,
|
||||
0x61, 0x6e, 0x65, 0x28, 0x6c, 0x6f, 0x67, 0x6f, 0x2c, 0x20, 0x30, 0x2c,
|
||||
0x20, 0x31, 0x2e, 0x38, 0x2c, 0x20, 0x2d, 0x33, 0x2c, 0x20, 0x31, 0x2c,
|
||||
0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x6f, 0x2e, 0x70, 0x6e, 0x67, 0x27, 0x29, 0x29, 0x29, 0x0a, 0x20, 0x20,
|
||||
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, 0x31, 0x35, 0x2c, 0x20, 0x31, 0x35, 0x2c, 0x20, 0x31, 0x35, 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, 0x27, 0x4c, 0xc3, 0x96, 0x56, 0x52, 0x27, 0x2c, 0x20, 0x2d, 0x2e,
|
||||
0x30, 0x31, 0x2c, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73,
|
||||
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x2d, 0x33, 0x2c, 0x20, 0x2e,
|
||||
0x32, 0x35, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x2c,
|
||||
0x20, 0x30, 0x2c, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x27, 0x63, 0x65,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x27, 0x2c, 0x20, 0x27, 0x74, 0x6f, 0x70, 0x27,
|
||||
0x29, 0x0a, 0x20, 0x20, 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, 0x31, 0x35, 0x2c, 0x20, 0x31, 0x35, 0x2c,
|
||||
0x20, 0x31, 0x35, 0x2c, 0x20, 0x66, 0x61, 0x64, 0x65, 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, 0x27,
|
||||
0x4e, 0x6f, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3a, 0x28, 0x27, 0x2c,
|
||||
0x20, 0x2d, 0x2e, 0x30, 0x31, 0x2c, 0x20, 0x73, 0x75, 0x62, 0x74, 0x69,
|
||||
0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c,
|
||||
0x20, 0x2d, 0x33, 0x2c, 0x20, 0x2e, 0x31, 0x35, 0x2c, 0x20, 0x30, 0x2c,
|
||||
0x20, 0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x6e, 0x69,
|
||||
0x6c, 0x2c, 0x20, 0x27, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x27, 0x2c,
|
||||
0x20, 0x27, 0x74, 0x6f, 0x70, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e,
|
||||
0x64, 0x0a, 0x0a, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x28, 0x29, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x64,
|
||||
0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x5f, 0x2c,
|
||||
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x20,
|
||||
0x69, 0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65,
|
||||
0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73,
|
||||
0x28, 0x29, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73,
|
||||
0x5b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5d,
|
||||
0x20, 0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x3a, 0x6e, 0x65, 0x77, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x28, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65,
|
||||
0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x61, 0x64, 0x64,
|
||||
0x65, 0x64, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
|
||||
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x0a,
|
||||
0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64,
|
||||
0x20, 0x3d, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x0a, 0x65, 0x6e,
|
||||
0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x63,
|
||||
0x63, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20,
|
||||
0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
|
||||
0x65, 0x2c, 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x66, 0x27, 0x29, 0x0a, 0x6c,
|
||||
0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72,
|
||||
0x0a, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x73, 0x75, 0x63,
|
||||
0x63, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72,
|
||||
0x72, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f,
|
||||
0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2c, 0x20, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e,
|
||||
0x73, 0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28,
|
||||
0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
|
||||
0x79, 0x29, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x27, 0x61,
|
||||
0x75, 0x64, 0x69, 0x6f, 0x27, 0x2c, 0x20, 0x27, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x27, 0x2c, 0x20, 0x27, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
|
||||
0x73, 0x27, 0x2c, 0x20, 0x27, 0x6d, 0x61, 0x74, 0x68, 0x27, 0x2c, 0x20,
|
||||
0x27, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x27, 0x2c, 0x20, 0x27,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x72, 0x27, 0x20, 0x7d, 0x0a, 0x66, 0x6f, 0x72,
|
||||
0x20, 0x5f, 0x2c, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69,
|
||||
0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x6d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x69,
|
||||
0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x73, 0x5b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5d, 0x20, 0x74,
|
||||
0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x5b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x72,
|
||||
0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
|
||||
0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x0a, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61,
|
||||
0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x6f,
|
||||
0x6e, 0x66, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77,
|
||||
0x20, 0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x77, 0x69, 0x6e, 0x64,
|
||||
0x6f, 0x77, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72,
|
||||
0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x28, 0x77, 0x2e, 0x77, 0x69,
|
||||
0x64, 0x74, 0x68, 0x2c, 0x20, 0x77, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68,
|
||||
0x74, 0x2c, 0x20, 0x77, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72,
|
||||
0x65, 0x65, 0x6e, 0x2c, 0x20, 0x77, 0x2e, 0x6d, 0x73, 0x61, 0x61, 0x2c,
|
||||
0x20, 0x77, 0x2e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x77, 0x2e,
|
||||
0x69, 0x63, 0x6f, 0x6e, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d,
|
||||
0x2d, 0x20, 0x63, 0x68, 0x65, 0x65, 0x73, 0x79, 0x2c, 0x20, 0x74, 0x65,
|
||||
0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x20, 0x68, 0x61, 0x63, 0x6b,
|
||||
0x20, 0x2d, 0x20, 0x66, 0x61, 0x6b, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64,
|
||||
0x73, 0x65, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73,
|
||||
0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x77, 0x69, 0x6e,
|
||||
0x64, 0x6f, 0x77, 0x20, 0x54, 0x4f, 0x44, 0x4f, 0x3a, 0x20, 0x66, 0x69,
|
||||
0x78, 0x21, 0x0a, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6d,
|
||||
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x5b, 0x27, 0x68, 0x65, 0x61, 0x64,
|
||||
0x73, 0x65, 0x74, 0x27, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
|
||||
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x5b, 0x27, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||
0x65, 0x74, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
|
||||
0x72, 0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61,
|
||||
0x64, 0x73, 0x65, 0x74, 0x27, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
|
||||
0x2d, 0x2d, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x61, 0x66, 0x74,
|
||||
0x65, 0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x69, 0x73,
|
||||
0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x69, 0x66, 0x20,
|
||||
0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e,
|
||||
0x0a, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x65, 0x72, 0x72, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69,
|
||||
0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||
0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x73, 0x65, 0x74,
|
||||
0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x28, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e,
|
||||
0x64, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||
0x65, 0x74, 0x2e, 0x6d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x20, 0x65,
|
||||
0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x61, 0x6e,
|
||||
0x64, 0x6c, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x74, 0x6d,
|
||||
0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x0a, 0x20,
|
||||
0x20, 0x71, 0x75, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
|
||||
0x20, 0x20, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75,
|
||||
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x6f,
|
||||
0x63, 0x75, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x28, 0x66, 0x29, 0x20, 0x65,
|
||||
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x61, 0x64,
|
||||
0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
|
||||
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x61, 0x64, 0x64, 0x65, 0x64, 0x28,
|
||||
0x63, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64,
|
||||
0x2c, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x3d, 0x20,
|
||||
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65,
|
||||
0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c,
|
||||
0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x63, 0x29,
|
||||
0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
|
||||
0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75,
|
||||
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x2c, 0x20, 0x62, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x70,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x63,
|
||||
0x2c, 0x20, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65,
|
||||
0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64,
|
||||
0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28,
|
||||
0x63, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
|
||||
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64,
|
||||
0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65, 0x6c,
|
||||
0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x63, 0x2c, 0x20, 0x62, 0x29, 0x20,
|
||||
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x7d, 0x2c,
|
||||
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28,
|
||||
0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x27,
|
||||
0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x3a, 0x20, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x74, 0x6f, 0x73, 0x74,
|
||||
0x72, 0x69, 0x6e, 0x67, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x7d, 0x29, 0x0a, 0x0a, 0x6c,
|
||||
0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x20, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x52, 0x65, 0x6e,
|
||||
0x64, 0x65, 0x72, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x28,
|
||||
0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x4f,
|
||||
0x72, 0x69, 0x67, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x28, 0x29, 0x20,
|
||||
0x3d, 0x3d, 0x20, 0x27, 0x68, 0x65, 0x61, 0x64, 0x27, 0x20, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79,
|
||||
0x48, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65,
|
||||
0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a,
|
||||
0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x66,
|
||||
0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20,
|
||||
0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 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,
|
||||
0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27,
|
||||
0x71, 0x75, 0x69, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x28, 0x6e,
|
||||
0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x71, 0x75, 0x69, 0x74,
|
||||
0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
|
||||
0x72, 0x6e, 0x20, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x61,
|
||||
0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e, 0x61, 0x6d, 0x65, 0x5d,
|
||||
0x28, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63,
|
||||
0x61, 0x6c, 0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28,
|
||||
0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 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,
|
||||
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, 0x29, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c,
|
||||
0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x75, 0x70,
|
||||
0x64, 0x61, 0x74, 0x65, 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,
|
||||
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,
|
||||
0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67,
|
||||
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x32,
|
||||
0x34, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x32, 0x2c, 0x20, 0x32, 0x35, 0x35,
|
||||
0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73,
|
||||
0x68, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73,
|
||||
0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20,
|
||||
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x20, 0x20, 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, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35,
|
||||
0x35, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2c, 0x20,
|
||||
0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x61, 0x69,
|
||||
0x72, 0x73, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x78, 0x2c, 0x20, 0x79, 0x2c,
|
||||
0x20, 0x7a, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x3a, 0x67, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x3a, 0x64, 0x72, 0x61, 0x77, 0x28, 0x78,
|
||||
0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x3a, 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, 0x73, 0x65, 0x74,
|
||||
0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65,
|
||||
0x74, 0x50, 0x6f, 0x73, 0x69, 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, 0x73, 0x65, 0x74, 0x56, 0x65, 0x6c,
|
||||
0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
|
||||
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x65,
|
||||
0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70,
|
||||
0x64, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f,
|
||||
0x76, 0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74,
|
||||
0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c,
|
||||
0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
|
||||
0x20, 0x74, 0x68, 0x65, 0x6e, 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,
|
||||
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, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64,
|
||||
0x72, 0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 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,
|
||||
0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70,
|
||||
0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x2e, 0x31, 0x0a,
|
||||
0x20, 0x20, 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, 0x20, 0x20, 0x6c, 0x6f, 0x63,
|
||||
0x61, 0x6c, 0x20, 0x66, 0x61, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x38, 0x30,
|
||||
0x20, 0x2b, 0x20, 0x31, 0x35, 0x30, 0x20, 0x2a, 0x20, 0x6d, 0x61, 0x74,
|
||||
0x68, 0x2e, 0x61, 0x62, 0x73, 0x28, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x73,
|
||||
0x69, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x72, 0x2e, 0x67, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x28, 0x29, 0x20,
|
||||
0x2a, 0x20, 0x32, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
|
||||
0x63, 0x61, 0x6c, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73,
|
||||
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x33, 0x20,
|
||||
0x2d, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x62, 0x74,
|
||||
0x69, 0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x20, 0x3d, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x3a,
|
||||
0x67, 0x65, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x20,
|
||||
0x2a, 0x20, 0x2e, 0x32, 0x35, 0x20, 0x2d, 0x20, 0x70, 0x61, 0x64, 0x64,
|
||||
0x69, 0x6e, 0x67, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73,
|
||||
0x65, 0x74, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x28, 0x6c,
|
||||
0x6f, 0x67, 0x6f, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70,
|
||||
0x6c, 0x61, 0x6e, 0x65, 0x28, 0x27, 0x66, 0x69, 0x6c, 0x6c, 0x27, 0x2c,
|
||||
0x20, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x38, 0x2c, 0x20, 0x2d, 0x33, 0x2c,
|
||||
0x20, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72,
|
||||
0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x61,
|
||||
0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 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,
|
||||
0x31, 0x35, 0x2c, 0x20, 0x31, 0x35, 0x2c, 0x20, 0x31, 0x35, 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,
|
||||
0x27, 0x4c, 0xc3, 0x96, 0x56, 0x52, 0x27, 0x2c, 0x20, 0x2d, 0x2e, 0x30,
|
||||
0x31, 0x2c, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x2d, 0x33, 0x2c, 0x20, 0x2e, 0x32,
|
||||
0x35, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20,
|
||||
0x30, 0x2c, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x27, 0x63, 0x65, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x27, 0x2c, 0x20, 0x27, 0x74, 0x6f, 0x70, 0x27, 0x29,
|
||||
0x0a, 0x20, 0x20, 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, 0x31, 0x35, 0x2c, 0x20, 0x31, 0x35, 0x2c, 0x20,
|
||||
0x31, 0x35, 0x2c, 0x20, 0x66, 0x61, 0x64, 0x65, 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, 0x27, 0x4e,
|
||||
0x6f, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x3a, 0x28, 0x27, 0x2c, 0x20,
|
||||
0x2d, 0x2e, 0x30, 0x31, 0x2c, 0x20, 0x73, 0x75, 0x62, 0x74, 0x69, 0x74,
|
||||
0x6c, 0x65, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20,
|
||||
0x2d, 0x33, 0x2c, 0x20, 0x2e, 0x31, 0x35, 0x2c, 0x20, 0x30, 0x2c, 0x20,
|
||||
0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x6e, 0x69, 0x6c,
|
||||
0x2c, 0x20, 0x27, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x27, 0x2c, 0x20,
|
||||
0x27, 0x74, 0x6f, 0x70, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64,
|
||||
0x0a, 0x0a, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x28, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e,
|
||||
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x5f, 0x2c, 0x20,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x20, 0x69,
|
||||
0x6e, 0x20, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74,
|
||||
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x28,
|
||||
0x29, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x5b,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5d, 0x20,
|
||||
0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x3a, 0x6e, 0x65, 0x77, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x28, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e,
|
||||
0x64, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x61, 0x64, 0x64, 0x65,
|
||||
0x64, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x0a, 0x20,
|
||||
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20,
|
||||
0x3d, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x0a, 0x65, 0x6e, 0x64,
|
||||
0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x63, 0x63,
|
||||
0x65, 0x73, 0x73, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x70,
|
||||
0x63, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65,
|
||||
0x2c, 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x66, 0x27, 0x29, 0x0a, 0x6c, 0x6f,
|
||||
0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x0a,
|
||||
0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63,
|
||||
0x65, 0x73, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72,
|
||||
0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73,
|
||||
0x65, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x63,
|
||||
0x6f, 0x6e, 0x66, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
|
||||
0x29, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x27, 0x61, 0x75,
|
||||
0x64, 0x69, 0x6f, 0x27, 0x2c, 0x20, 0x27, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x27, 0x2c, 0x20, 0x27, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73,
|
||||
0x27, 0x2c, 0x20, 0x27, 0x6d, 0x61, 0x74, 0x68, 0x27, 0x2c, 0x20, 0x27,
|
||||
0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x27, 0x2c, 0x20, 0x27, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x72, 0x27, 0x20, 0x7d, 0x0a, 0x66, 0x6f, 0x72, 0x20,
|
||||
0x5f, 0x2c, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x6e,
|
||||
0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x6d, 0x6f, 0x64, 0x75,
|
||||
0x6c, 0x65, 0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x69, 0x66,
|
||||
0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
|
||||
0x73, 0x5b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5d, 0x20, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x5b,
|
||||
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x72, 0x65,
|
||||
0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x27, 0x20, 0x2e, 0x2e, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
|
||||
0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70,
|
||||
0x68, 0x69, 0x63, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x20,
|
||||
0x3d, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f,
|
||||
0x77, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61,
|
||||
0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x28, 0x77, 0x2e, 0x77, 0x69, 0x64,
|
||||
0x74, 0x68, 0x2c, 0x20, 0x77, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74,
|
||||
0x2c, 0x20, 0x77, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65,
|
||||
0x65, 0x6e, 0x2c, 0x20, 0x77, 0x2e, 0x6d, 0x73, 0x61, 0x61, 0x2c, 0x20,
|
||||
0x77, 0x2e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x2c, 0x20, 0x77, 0x2e, 0x69,
|
||||
0x63, 0x6f, 0x6e, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d,
|
||||
0x20, 0x63, 0x68, 0x65, 0x65, 0x73, 0x79, 0x2c, 0x20, 0x74, 0x65, 0x6d,
|
||||
0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x20,
|
||||
0x2d, 0x20, 0x66, 0x61, 0x6b, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||
0x65, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x20,
|
||||
0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x77, 0x69, 0x6e, 0x64,
|
||||
0x6f, 0x77, 0x20, 0x54, 0x4f, 0x44, 0x4f, 0x3a, 0x20, 0x66, 0x69, 0x78,
|
||||
0x21, 0x0a, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6d, 0x6f,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x73, 0x5b, 0x27, 0x68, 0x65, 0x61, 0x64, 0x73,
|
||||
0x65, 0x74, 0x27, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x5b, 0x27, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65,
|
||||
0x74, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
|
||||
0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64,
|
||||
0x73, 0x65, 0x74, 0x27, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d,
|
||||
0x2d, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x61, 0x66, 0x74, 0x65,
|
||||
0x72, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20,
|
||||
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x69, 0x66, 0x20, 0x63,
|
||||
0x6f, 0x6e, 0x66, 0x65, 0x72, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
|
||||
0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x65, 0x72, 0x72, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66,
|
||||
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65,
|
||||
0x74, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, 0x68,
|
||||
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72,
|
||||
0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x65,
|
||||
0x61, 0x64, 0x73, 0x65, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x28,
|
||||
0x29, 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, 0x65, 0x6e,
|
||||
0x64, 0x0a, 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, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75,
|
||||
0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, 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, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, 0x3d,
|
||||
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x78, 0x69, 0x74,
|
||||
0x20, 0x74, 0x68, 0x65, 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, 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
|
||||
0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x73, 0x65, 0x74, 0x4d,
|
||||
0x69, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x28, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64,
|
||||
0x20, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65,
|
||||
0x74, 0x2e, 0x6d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x20, 0x65, 0x6e,
|
||||
0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x61, 0x6e, 0x64,
|
||||
0x6c, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x74, 0x6d, 0x65,
|
||||
0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x0a, 0x20, 0x20,
|
||||
0x71, 0x75, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20,
|
||||
0x20, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x6f, 0x63,
|
||||
0x75, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x28, 0x66, 0x29, 0x20, 0x65, 0x6e,
|
||||
0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x61, 0x64, 0x64,
|
||||
0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x61, 0x64, 0x64, 0x65, 0x64, 0x28, 0x63,
|
||||
0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c,
|
||||
0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66,
|
||||
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65, 0x6d,
|
||||
0x6f, 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f,
|
||||
0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x63, 0x29, 0x20,
|
||||
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20,
|
||||
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x70,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x2c, 0x20, 0x62, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x70, 0x72,
|
||||
0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c,
|
||||
0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x63, 0x2c,
|
||||
0x20, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e,
|
||||
0x64, 0x2c, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20,
|
||||
0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63,
|
||||
0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20,
|
||||
0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65,
|
||||
0x61, 0x73, 0x65, 0x64, 0x28, 0x63, 0x2c, 0x20, 0x62, 0x29, 0x20, 0x65,
|
||||
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x7d, 0x2c, 0x20,
|
||||
0x7b, 0x0a, 0x20, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20,
|
||||
0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x73,
|
||||
0x65, 0x6c, 0x66, 0x2c, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x27, 0x55,
|
||||
0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x3a, 0x20, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x74, 0x6f, 0x73, 0x74, 0x72,
|
||||
0x69, 0x6e, 0x67, 0x28, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x29, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x7d, 0x29, 0x0a, 0x0a, 0x6c, 0x6f,
|
||||
0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x20, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64,
|
||||
0x65, 0x72, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x28, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
|
||||
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x4f, 0x72,
|
||||
0x69, 0x67, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x28, 0x29, 0x20, 0x3d,
|
||||
0x3d, 0x20, 0x27, 0x68, 0x65, 0x61, 0x64, 0x27, 0x20, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x48,
|
||||
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74,
|
||||
0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c,
|
||||
0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x65,
|
||||
0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x66, 0x6f,
|
||||
0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62,
|
||||
0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 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, 0x69,
|
||||
0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x71,
|
||||
0x75, 0x69, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x28, 0x6e, 0x6f,
|
||||
0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x71, 0x75, 0x69, 0x74, 0x20,
|
||||
0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
|
||||
0x6e, 0x20, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x61, 0x6e,
|
||||
0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e, 0x61, 0x6d, 0x65, 0x5d, 0x28,
|
||||
0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
|
||||
0x6c, 0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29,
|
||||
0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61,
|
||||
0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 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, 0x75,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
|
||||
0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x75, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 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, 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, 0x73, 0x65, 0x74, 0x50,
|
||||
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74,
|
||||
0x50, 0x6f, 0x73, 0x69, 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, 0x73, 0x65, 0x74, 0x56, 0x65, 0x6c, 0x6f,
|
||||
0x63, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65,
|
||||
0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x65, 0x6c,
|
||||
0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
|
||||
0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76,
|
||||
0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, 0x29,
|
||||
0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f,
|
||||
0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20,
|
||||
0x74, 0x68, 0x65, 0x6e, 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, 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, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72,
|
||||
0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 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, 0x68, 0x65,
|
||||
0x61, 0x64, 0x73, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43,
|
||||
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x65, 0x61,
|
||||
0x64, 0x73, 0x65, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x28, 0x29,
|
||||
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, 0x65, 0x6e, 0x64,
|
||||
0x0a, 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, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e,
|
||||
0x28, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72,
|
||||
0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c,
|
||||
0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, 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, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, 0x3d, 0x20,
|
||||
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20,
|
||||
0x74, 0x68, 0x65, 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, 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 = 6266;
|
||||
unsigned int boot_lua_len = 6385;
|
||||
|
|
|
@ -7,6 +7,7 @@ Blob* lovrBlobCreate(void* data, size_t size, const char* name) {
|
|||
blob->data = data;
|
||||
blob->size = size;
|
||||
blob->name = name;
|
||||
blob->seek = 0;
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ typedef struct {
|
|||
void* data;
|
||||
size_t size;
|
||||
const char* name;
|
||||
size_t seek;
|
||||
} Blob;
|
||||
|
||||
Blob* lovrBlobCreate(void* data, size_t size, const char* name);
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#include "filesystem/file.h"
|
||||
#include <physfs.h>
|
||||
|
||||
File* lovrFileCreate(const char* path) {
|
||||
File* file = lovrAlloc(sizeof(File), lovrFileDestroy);
|
||||
if (!file) return NULL;
|
||||
|
||||
file->path = path;
|
||||
file->handle = NULL;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void lovrFileDestroy(const Ref* ref) {
|
||||
File* file = containerof(ref, File);
|
||||
if (file->handle) {
|
||||
PHYSFS_close(file->handle);
|
||||
}
|
||||
free(file);
|
||||
}
|
||||
|
||||
int lovrFileOpen(File* file, FileMode mode) {
|
||||
lovrAssert(!file->handle, "File is already open");
|
||||
file->mode = mode;
|
||||
|
||||
switch (mode) {
|
||||
case OPEN_READ: file->handle = PHYSFS_openRead(file->path); break;
|
||||
case OPEN_WRITE: file->handle = PHYSFS_openWrite(file->path); break;
|
||||
case OPEN_APPEND: file->handle = PHYSFS_openAppend(file->path); break;
|
||||
}
|
||||
|
||||
return file->handle == NULL;
|
||||
}
|
||||
|
||||
void lovrFileClose(File* file) {
|
||||
lovrAssert(file->handle, "File must be open to close it");
|
||||
PHYSFS_close(file->handle);
|
||||
file->handle = NULL;
|
||||
}
|
||||
|
||||
size_t lovrFileRead(File* file, void* data, size_t size, size_t count) {
|
||||
lovrAssert(file->handle && file->mode == OPEN_READ, "File must be open for reading");
|
||||
return PHYSFS_read(file->handle, data, size, count);
|
||||
}
|
||||
|
||||
size_t lovrFileWrite(File* file, void* data, size_t size, size_t count) {
|
||||
lovrAssert(file->handle && (file->mode == OPEN_READ || file->mode == OPEN_WRITE), "File must be open for writing");
|
||||
return PHYSFS_write(file->handle, data, size, count);
|
||||
}
|
||||
|
||||
size_t lovrFileGetSize(File* file) {
|
||||
lovrAssert(file->handle, "File must be open to get its size");
|
||||
return PHYSFS_fileLength(file->handle);
|
||||
}
|
||||
|
||||
int lovrFileSeek(File* file, size_t position) {
|
||||
lovrAssert(file->handle, "File must be open to seek");
|
||||
return !PHYSFS_seek(file->handle, position);
|
||||
}
|
||||
|
||||
size_t lovrFileTell(File* file) {
|
||||
lovrAssert(file->handle, "File must be open to tell");
|
||||
return PHYSFS_tell(file->handle);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#include "util.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
OPEN_READ,
|
||||
OPEN_WRITE,
|
||||
OPEN_APPEND
|
||||
} FileMode;
|
||||
|
||||
typedef struct {
|
||||
Ref ref;
|
||||
const char* path;
|
||||
void* handle;
|
||||
FileMode mode;
|
||||
} File;
|
||||
|
||||
File* lovrFileCreate(const char* filename);
|
||||
void lovrFileDestroy(const Ref* ref);
|
||||
int lovrFileOpen(File* file, FileMode mode);
|
||||
void lovrFileClose(File* file);
|
||||
size_t lovrFileRead(File* file, void* data, size_t size, size_t count);
|
||||
size_t lovrFileWrite(File* file, void* data, size_t size, size_t count);
|
||||
size_t lovrFileGetSize(File* file);
|
||||
int lovrFileSeek(File* file, size_t position);
|
||||
size_t lovrFileTell(File* file);
|
|
@ -1,9 +1,9 @@
|
|||
#include "filesystem/filesystem.h"
|
||||
#include "filesystem/file.h"
|
||||
#include "util.h"
|
||||
#include <physfs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
@ -22,7 +22,7 @@ static FilesystemState state;
|
|||
|
||||
void lovrFilesystemInit(const char* arg0, const char* arg1) {
|
||||
if (!PHYSFS_init(arg0)) {
|
||||
lovrThrow("Could not initialize filesystem: %s", PHYSFS_getLastError());
|
||||
lovrThrow("Could not initialize filesystem: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
||||
}
|
||||
|
||||
state.source = malloc(LOVR_PATH_MAX * sizeof(char));
|
||||
|
@ -60,10 +60,6 @@ int lovrFilesystemCreateDirectory(const char* path) {
|
|||
return !PHYSFS_mkdir(path);
|
||||
}
|
||||
|
||||
int lovrFilesystemExists(const char* path) {
|
||||
return PHYSFS_exists(path);
|
||||
}
|
||||
|
||||
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size) {
|
||||
#ifdef __APPLE__
|
||||
const char* home;
|
||||
|
@ -97,7 +93,7 @@ int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size) {
|
|||
}
|
||||
|
||||
void lovrFilesystemGetDirectoryItems(const char* path, getDirectoryItemsCallback callback, void* userdata) {
|
||||
PHYSFS_enumerateFilesCallback(path, callback, userdata);
|
||||
PHYSFS_enumerate(path, callback, userdata);
|
||||
}
|
||||
|
||||
int lovrFilesystemGetExecutablePath(char* dest, unsigned int size) {
|
||||
|
@ -126,7 +122,8 @@ const char* lovrFilesystemGetIdentity() {
|
|||
}
|
||||
|
||||
long lovrFilesystemGetLastModified(const char* path) {
|
||||
return PHYSFS_getLastModTime(path);
|
||||
PHYSFS_Stat stat;
|
||||
return PHYSFS_stat(path, &stat) ? stat.modtime : -1;
|
||||
}
|
||||
|
||||
const char* lovrFilesystemGetRealDirectory(const char* path) {
|
||||
|
@ -137,15 +134,9 @@ const char* lovrFilesystemGetSaveDirectory() {
|
|||
return state.savePathFull;
|
||||
}
|
||||
|
||||
int lovrFilesystemGetSize(const char* path) {
|
||||
PHYSFS_file* handle = PHYSFS_openRead(path);
|
||||
if (!handle) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int length = PHYSFS_fileLength(handle);
|
||||
PHYSFS_close(handle);
|
||||
return length;
|
||||
size_t lovrFilesystemGetSize(const char* path) {
|
||||
PHYSFS_Stat stat;
|
||||
return PHYSFS_stat(path, &stat) ? stat.filesize : -1;
|
||||
}
|
||||
|
||||
const char* lovrFilesystemGetSource() {
|
||||
|
@ -153,15 +144,29 @@ const char* lovrFilesystemGetSource() {
|
|||
}
|
||||
|
||||
const char* lovrFilesystemGetUserDirectory() {
|
||||
return PHYSFS_getUserDir();
|
||||
#if defined(__APPLE__) || defined(__linux__)
|
||||
const char* home;
|
||||
if ((home = getenv("HOME")) == NULL) {
|
||||
home = getpwuid(getuid())->pw_dir;
|
||||
}
|
||||
return home;
|
||||
#elif _WIN32
|
||||
return getenv("USERPROFILE");
|
||||
#elif EMSCRIPTEN
|
||||
return "/home/web_user";
|
||||
#else
|
||||
#error "This platform is missing an implementation for lovrFilesystemGetUserDirectory"
|
||||
#endif
|
||||
}
|
||||
|
||||
int lovrFilesystemIsDirectory(const char* path) {
|
||||
return PHYSFS_isDirectory(path);
|
||||
PHYSFS_Stat stat;
|
||||
return PHYSFS_stat(path, &stat) ? stat.filetype == PHYSFS_FILETYPE_DIRECTORY : 0;
|
||||
}
|
||||
|
||||
int lovrFilesystemIsFile(const char* path) {
|
||||
return lovrFilesystemExists(path) && !lovrFilesystemIsDirectory(path);
|
||||
PHYSFS_Stat stat;
|
||||
return PHYSFS_stat(path, &stat) ? stat.filetype == PHYSFS_FILETYPE_REGULAR : 0;
|
||||
}
|
||||
|
||||
int lovrFilesystemIsFused() {
|
||||
|
@ -174,15 +179,20 @@ int lovrFilesystemMount(const char* path, const char* mountpoint, int append) {
|
|||
|
||||
void* lovrFilesystemRead(const char* path, size_t* bytesRead) {
|
||||
|
||||
// Open file
|
||||
PHYSFS_file* handle = PHYSFS_openRead(path);
|
||||
if (!handle) {
|
||||
// Create file
|
||||
File* file = lovrFileCreate(path);
|
||||
if (!file) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Open it
|
||||
if (lovrFileOpen(file, OPEN_READ)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get file size
|
||||
int size = PHYSFS_fileLength(handle);
|
||||
if (size < 0) {
|
||||
size_t size = lovrFileGetSize(file);
|
||||
if (size == (unsigned int) -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -193,8 +203,8 @@ void* lovrFilesystemRead(const char* path, size_t* bytesRead) {
|
|||
}
|
||||
|
||||
// Perform read
|
||||
*bytesRead = PHYSFS_read(handle, data, 1, size);
|
||||
PHYSFS_close(handle);
|
||||
*bytesRead = lovrFileRead(file, data, 1, size);
|
||||
lovrFileClose(file);
|
||||
|
||||
// Make sure we got everything
|
||||
if (*bytesRead != (size_t) size) {
|
||||
|
@ -214,7 +224,7 @@ int lovrFilesystemSetIdentity(const char* identity) {
|
|||
|
||||
// Unmount old write directory
|
||||
if (state.savePathFull && state.savePathRelative) {
|
||||
PHYSFS_removeFromSearchPath(state.savePathRelative);
|
||||
PHYSFS_unmount(state.savePathRelative);
|
||||
} else {
|
||||
state.savePathRelative = malloc(LOVR_PATH_MAX);
|
||||
state.savePathFull = malloc(LOVR_PATH_MAX);
|
||||
|
@ -231,7 +241,8 @@ int lovrFilesystemSetIdentity(const char* identity) {
|
|||
strncpy(state.savePathFull, fullPathBuffer, LOVR_PATH_MAX);
|
||||
PHYSFS_mkdir(state.savePathRelative);
|
||||
if (!PHYSFS_setWriteDir(state.savePathFull)) {
|
||||
lovrThrow("Could not set write directory: %s (%s)", PHYSFS_getLastError(), state.savePathRelative);
|
||||
const char* error = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
|
||||
lovrThrow("Could not set write directory: %s (%s)", error, state.savePathRelative);
|
||||
}
|
||||
|
||||
PHYSFS_mount(state.savePathFull, NULL, 0);
|
||||
|
@ -240,16 +251,18 @@ int lovrFilesystemSetIdentity(const char* identity) {
|
|||
}
|
||||
|
||||
int lovrFilesystemUnmount(const char* path) {
|
||||
return !PHYSFS_removeFromSearchPath(path);
|
||||
return !PHYSFS_unmount(path);
|
||||
}
|
||||
|
||||
int lovrFilesystemWrite(const char* path, const char* content, size_t size, int append) {
|
||||
PHYSFS_file* handle = append ? PHYSFS_openAppend(path) : PHYSFS_openWrite(path);
|
||||
if (!handle) {
|
||||
size_t lovrFilesystemWrite(const char* path, const char* content, size_t size, int append) {
|
||||
File* file = lovrFileCreate(path);
|
||||
if (!file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bytesWritten = PHYSFS_write(handle, content, 1, size);
|
||||
PHYSFS_close(handle);
|
||||
lovrFileOpen(file, append ? OPEN_APPEND : OPEN_WRITE);
|
||||
size_t bytesWritten = lovrFileWrite(file, (void*) content, 1, size);
|
||||
lovrFileClose(file);
|
||||
lovrRelease(&file->ref);
|
||||
return bytesWritten;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#define LOVR_PATH_MAX 1024
|
||||
|
||||
typedef void getDirectoryItemsCallback(void* userdata, const char* dir, const char* file);
|
||||
typedef int getDirectoryItemsCallback(void* userdata, const char* dir, const char* file);
|
||||
|
||||
typedef struct {
|
||||
char* source;
|
||||
|
@ -17,7 +17,6 @@ typedef struct {
|
|||
void lovrFilesystemInit(const char* arg0, const char* arg1);
|
||||
void lovrFilesystemDestroy();
|
||||
int lovrFilesystemCreateDirectory(const char* path);
|
||||
int lovrFilesystemExists(const char* path);
|
||||
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size);
|
||||
void lovrFilesystemGetDirectoryItems(const char* path, getDirectoryItemsCallback callback, void* userdata);
|
||||
int lovrFilesystemGetExecutablePath(char* dest, unsigned int size);
|
||||
|
@ -25,7 +24,7 @@ const char* lovrFilesystemGetIdentity();
|
|||
long lovrFilesystemGetLastModified(const char* path);
|
||||
const char* lovrFilesystemGetRealDirectory(const char* path);
|
||||
const char* lovrFilesystemGetSaveDirectory();
|
||||
int lovrFilesystemGetSize(const char* path);
|
||||
size_t lovrFilesystemGetSize(const char* path);
|
||||
const char* lovrFilesystemGetSource();
|
||||
const char* lovrFilesystemGetUserDirectory();
|
||||
int lovrFilesystemIsDirectory(const char* path);
|
||||
|
@ -37,4 +36,4 @@ int lovrFilesystemRemove(const char* path);
|
|||
int lovrFilesystemSetIdentity(const char* identity);
|
||||
int lovrFilesystemSetSource(const char* source);
|
||||
int lovrFilesystemUnmount(const char* path);
|
||||
int lovrFilesystemWrite(const char* path, const char* content, size_t size, int append);
|
||||
size_t lovrFilesystemWrite(const char* path, const char* content, size_t size, int append);
|
||||
|
|
|
@ -49,9 +49,9 @@ Font* lovrFontCreate(FontData* fontData) {
|
|||
// Texture
|
||||
TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RGB);
|
||||
TextureFilter filter = { .mode = FILTER_BILINEAR };
|
||||
font->texture = lovrTextureCreate(textureData);
|
||||
font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1);
|
||||
lovrTextureSetFilter(font->texture, filter);
|
||||
lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP);
|
||||
lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
|
||||
|
||||
return font;
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ void lovrFontAddGlyph(Font* font, Glyph* glyph) {
|
|||
glyph->y = atlas->y;
|
||||
|
||||
// Paste glyph into texture
|
||||
lovrGraphicsBindTexture(font->texture);
|
||||
lovrGraphicsBindTexture(font->texture, TEXTURE_2D, 0);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, atlas->x, atlas->y, glyph->tw, glyph->th, FORMAT_RGB.glFormat, GL_UNSIGNED_BYTE, glyph->data);
|
||||
|
||||
// Advance atlas cursor
|
||||
|
@ -299,7 +299,7 @@ void lovrFontExpandTexture(Font* font) {
|
|||
}
|
||||
|
||||
// Resize the texture storage
|
||||
lovrTextureDataResize(font->texture->textureData, atlas->width, atlas->height, 0x0);
|
||||
lovrTextureDataResize(font->texture->slices[0], atlas->width, atlas->height, 0x0);
|
||||
lovrTextureRefresh(font->texture);
|
||||
|
||||
// Reset the cursor
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "graphics/graphics.h"
|
||||
#include "graphics/shaders.h"
|
||||
#include "loaders/texture.h"
|
||||
#include "loaders/font.h"
|
||||
#include "event/event.h"
|
||||
|
@ -35,6 +36,7 @@ void lovrGraphicsDestroy() {
|
|||
for (int i = 0; i < DEFAULT_SHADER_COUNT; i++) {
|
||||
if (state.defaultShaders[i]) lovrRelease(&state.defaultShaders[i]->ref);
|
||||
}
|
||||
if (state.defaultMaterial) lovrRelease(&state.defaultMaterial->ref);
|
||||
if (state.defaultFont) lovrRelease(&state.defaultFont->ref);
|
||||
if (state.defaultTexture) lovrRelease(&state.defaultTexture->ref);
|
||||
glDeleteVertexArrays(1, &state.streamVAO);
|
||||
|
@ -49,7 +51,7 @@ void lovrGraphicsReset() {
|
|||
int h = lovrGraphicsGetHeight();
|
||||
float projection[16];
|
||||
state.transform = 0;
|
||||
state.canvas = 0;
|
||||
state.view = 0;
|
||||
state.defaultShader = -1;
|
||||
lovrGraphicsSetBackgroundColor((Color) { 0, 0, 0, 255 });
|
||||
lovrGraphicsSetBlendMode(BLEND_ALPHA, BLEND_ALPHA_MULTIPLY);
|
||||
|
@ -58,6 +60,7 @@ void lovrGraphicsReset() {
|
|||
lovrGraphicsSetDefaultFilter((TextureFilter) { .mode = FILTER_TRILINEAR });
|
||||
lovrGraphicsSetDepthTest(COMPARE_LEQUAL);
|
||||
lovrGraphicsSetFont(NULL);
|
||||
lovrGraphicsSetMaterial(NULL);
|
||||
lovrGraphicsSetLineWidth(1);
|
||||
lovrGraphicsSetPointSize(1);
|
||||
lovrGraphicsSetShader(NULL);
|
||||
|
@ -86,9 +89,51 @@ void lovrGraphicsPrepare() {
|
|||
|
||||
mat4 model = state.transforms[state.transform][MATRIX_MODEL];
|
||||
mat4 view = state.transforms[state.transform][MATRIX_VIEW];
|
||||
mat4 projection = state.canvases[state.canvas].projection;
|
||||
mat4 projection = state.views[state.view].projection;
|
||||
lovrShaderSetMatrix(shader, "lovrModel", model, 16);
|
||||
lovrShaderSetMatrix(shader, "lovrView", view, 16);
|
||||
lovrShaderSetMatrix(shader, "lovrProjection", projection, 16);
|
||||
|
||||
float transform[16];
|
||||
mat4_multiply(mat4_set(transform, view), model);
|
||||
lovrShaderSetMatrix(shader, "lovrTransform", transform, 16);
|
||||
|
||||
if (lovrShaderGetUniform(shader, "lovrNormalMatrix")) {
|
||||
if (mat4_invert(transform)) {
|
||||
mat4_transpose(transform);
|
||||
} else {
|
||||
mat4_identity(transform);
|
||||
}
|
||||
|
||||
float normalMatrix[9] = {
|
||||
transform[0], transform[1], transform[2],
|
||||
transform[4], transform[5], transform[6],
|
||||
transform[8], transform[9], transform[10]
|
||||
};
|
||||
|
||||
lovrShaderSetMatrix(shader, "lovrNormalMatrix", normalMatrix, 9);
|
||||
}
|
||||
|
||||
// Color
|
||||
float color[4] = { state.color.r / 255., state.color.g / 255., state.color.b / 255., state.color.a / 255. };
|
||||
lovrShaderSetFloat(shader, "lovrColor", color, 4);
|
||||
|
||||
// Material
|
||||
Material* material = lovrGraphicsGetMaterial();
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_COLORS; i++) {
|
||||
Color color = lovrMaterialGetColor(material, i);
|
||||
float data[4] = { color.r / 255., color.g / 255., color.b / 255., color.a / 255. };
|
||||
lovrShaderSetFloat(shader, lovrShaderColorUniforms[i], data, 4);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
|
||||
Texture* texture = lovrMaterialGetTexture(material, i);
|
||||
lovrShaderSetTexture(shader, lovrShaderTextureUniforms[i], &texture, 1);
|
||||
}
|
||||
|
||||
lovrGraphicsBindProgram(shader->id);
|
||||
lovrShaderBind(shader, model, view, projection, state.color, 0);
|
||||
lovrShaderBind(shader);
|
||||
}
|
||||
|
||||
void lovrGraphicsCreateWindow(int w, int h, int fullscreen, int msaa, const char* title, const char* icon) {
|
||||
|
@ -327,6 +372,31 @@ void lovrGraphicsSetLineWidth(float width) {
|
|||
glLineWidth(width);
|
||||
}
|
||||
|
||||
Material* lovrGraphicsGetMaterial() {
|
||||
if (!state.material) {
|
||||
if (!state.defaultMaterial) {
|
||||
MaterialData* materialData = lovrMaterialDataCreateEmpty();
|
||||
state.defaultMaterial = lovrMaterialCreate(materialData, 1);
|
||||
}
|
||||
|
||||
lovrGraphicsSetMaterial(state.defaultMaterial);
|
||||
}
|
||||
|
||||
return state.material;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetMaterial(Material* material) {
|
||||
if (state.material) {
|
||||
lovrRelease(&state.material->ref);
|
||||
}
|
||||
|
||||
state.material = material;
|
||||
|
||||
if (material) {
|
||||
lovrRetain(&material->ref);
|
||||
}
|
||||
}
|
||||
|
||||
float lovrGraphicsGetPointSize() {
|
||||
return state.pointSize;
|
||||
}
|
||||
|
@ -417,7 +487,7 @@ void lovrGraphicsMatrixTransform(MatrixType type, mat4 transform) {
|
|||
|
||||
// Primitives
|
||||
|
||||
static void lovrGraphicsSetShapeData(float* data, int length) {
|
||||
static void lovrGraphicsSetStreamData(float* data, int length) {
|
||||
vec_clear(&state.streamData);
|
||||
vec_pusharr(&state.streamData, data, length);
|
||||
}
|
||||
|
@ -465,25 +535,22 @@ static void lovrGraphicsDrawPrimitive(GLenum mode, int hasNormals, int hasTexCoo
|
|||
}
|
||||
|
||||
void lovrGraphicsPoints(float* points, int count) {
|
||||
lovrGraphicsBindTexture(NULL);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsSetShapeData(points, count);
|
||||
lovrGraphicsSetStreamData(points, count);
|
||||
lovrGraphicsDrawPrimitive(GL_POINTS, 0, 0, 0);
|
||||
}
|
||||
|
||||
void lovrGraphicsLine(float* points, int count) {
|
||||
lovrGraphicsBindTexture(NULL);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsSetShapeData(points, count);
|
||||
lovrGraphicsSetStreamData(points, count);
|
||||
lovrGraphicsDrawPrimitive(GL_LINE_STRIP, 0, 0, 0);
|
||||
}
|
||||
|
||||
void lovrGraphicsTriangle(DrawMode mode, float* points) {
|
||||
lovrGraphicsBindTexture(NULL);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
|
||||
if (mode == DRAW_MODE_LINE) {
|
||||
lovrGraphicsSetShapeData(points, 9);
|
||||
lovrGraphicsSetStreamData(points, 9);
|
||||
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, 0, 0, 0);
|
||||
} else {
|
||||
float normal[3];
|
||||
|
@ -495,12 +562,12 @@ void lovrGraphicsTriangle(DrawMode mode, float* points) {
|
|||
points[6], points[7], points[8], normal[0], normal[1], normal[2]
|
||||
};
|
||||
|
||||
lovrGraphicsSetShapeData(data, 18);
|
||||
lovrGraphicsSetStreamData(data, 18);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrGraphicsPlane(DrawMode mode, Texture* texture, mat4 transform) {
|
||||
void lovrGraphicsPlane(DrawMode mode, mat4 transform) {
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
|
||||
|
||||
|
@ -512,9 +579,8 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, mat4 transform) {
|
|||
-.5, -.5, 0
|
||||
};
|
||||
|
||||
lovrGraphicsBindTexture(NULL);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsSetShapeData(points, 12);
|
||||
lovrGraphicsSetStreamData(points, 12);
|
||||
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, 0, 0, 0);
|
||||
} else if (mode == DRAW_MODE_FILL) {
|
||||
float data[] = {
|
||||
|
@ -524,9 +590,8 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, mat4 transform) {
|
|||
.5, -.5, 0, 0, 0, -1, 1, 1
|
||||
};
|
||||
|
||||
lovrGraphicsBindTexture(texture);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsSetShapeData(data, 32);
|
||||
lovrGraphicsSetStreamData(data, 32);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 1, 1, 0);
|
||||
}
|
||||
|
||||
|
@ -541,13 +606,16 @@ void lovrGraphicsPlaneFullscreen(Texture* texture) {
|
|||
1, -1, 0, 1, 0
|
||||
};
|
||||
|
||||
lovrGraphicsBindTexture(texture);
|
||||
lovrGraphicsSetDefaultShader(SHADER_FULLSCREEN);
|
||||
lovrGraphicsSetShapeData(data, 20);
|
||||
Material* material = lovrGraphicsGetMaterial();
|
||||
Texture* lastTexture = lovrMaterialGetTexture(material, TEXTURE_DIFFUSE);
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
|
||||
lovrGraphicsSetStreamData(data, 20);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 0, 1, 0);
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, lastTexture);
|
||||
}
|
||||
|
||||
void lovrGraphicsBox(DrawMode mode, Texture* texture, mat4 transform) {
|
||||
void lovrGraphicsBox(DrawMode mode, mat4 transform) {
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
|
||||
|
@ -573,9 +641,8 @@ void lovrGraphicsBox(DrawMode mode, Texture* texture, mat4 transform) {
|
|||
0, 4, 1, 5, 2, 6, 3, 7 // Connections
|
||||
};
|
||||
|
||||
lovrGraphicsBindTexture(NULL);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsSetShapeData(points, 24);
|
||||
lovrGraphicsSetStreamData(points, 24);
|
||||
lovrGraphicsSetIndexData(indices, 24);
|
||||
lovrGraphicsDrawPrimitive(GL_LINES, 0, 0, 1);
|
||||
} else {
|
||||
|
@ -621,9 +688,8 @@ void lovrGraphicsBox(DrawMode mode, Texture* texture, mat4 transform) {
|
|||
.5, .5, .5, 0, 1, 0, 1, 0
|
||||
};
|
||||
|
||||
lovrGraphicsBindTexture(texture);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsSetShapeData(data, 208);
|
||||
lovrGraphicsSetStreamData(data, 208);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 1, 1, 0);
|
||||
}
|
||||
|
||||
|
@ -729,14 +795,13 @@ void lovrGraphicsCylinder(float x1, float y1, float z1, float x2, float y2, floa
|
|||
}
|
||||
}
|
||||
|
||||
lovrGraphicsBindTexture(NULL);
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 0, 1);
|
||||
#undef PUSH_CYLINDER_VERTEX
|
||||
#undef PUSH_CYLINDER_TRIANGLE
|
||||
}
|
||||
|
||||
void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox* skybox) {
|
||||
void lovrGraphicsSphere(mat4 transform, int segments) {
|
||||
vec_clear(&state.streamData);
|
||||
vec_clear(&state.streamIndices);
|
||||
|
||||
|
@ -753,11 +818,9 @@ void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox*
|
|||
vec_push(&state.streamData, y);
|
||||
vec_push(&state.streamData, z);
|
||||
|
||||
if (!skybox) {
|
||||
vec_push(&state.streamData, x);
|
||||
vec_push(&state.streamData, y);
|
||||
vec_push(&state.streamData, z);
|
||||
}
|
||||
|
||||
vec_push(&state.streamData, u);
|
||||
vec_push(&state.streamData, v);
|
||||
|
@ -779,23 +842,20 @@ void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox*
|
|||
}
|
||||
}
|
||||
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
|
||||
if (skybox) {
|
||||
Texture* oldTexture = lovrGraphicsGetTexture();
|
||||
glBindTexture(GL_TEXTURE_2D, skybox->texture);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 0, 1, 1);
|
||||
glBindTexture(GL_TEXTURE_2D, oldTexture->id);
|
||||
} else {
|
||||
lovrGraphicsBindTexture(texture);
|
||||
if (transform) {
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
|
||||
}
|
||||
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 1, 1);
|
||||
|
||||
if (transform) {
|
||||
lovrGraphicsPop();
|
||||
}
|
||||
}
|
||||
|
||||
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az) {
|
||||
void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float az) {
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsOrigin();
|
||||
lovrGraphicsRotate(MATRIX_MODEL, angle, ax, ay, az);
|
||||
|
@ -803,7 +863,7 @@ void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float a
|
|||
int wasCulling = lovrGraphicsIsCullingEnabled();
|
||||
lovrGraphicsSetCullingEnabled(0);
|
||||
|
||||
if (skybox->type == SKYBOX_CUBE) {
|
||||
if (texture->type == TEXTURE_CUBE) {
|
||||
float cube[] = {
|
||||
// Front
|
||||
1.f, -1.f, -1.f,
|
||||
|
@ -846,15 +906,19 @@ void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float a
|
|||
1.f, 1.f, 1.f
|
||||
};
|
||||
|
||||
lovrGraphicsSetShapeData(cube, 78);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->texture);
|
||||
lovrGraphicsSetStreamData(cube, 78);
|
||||
lovrGraphicsSetDefaultShader(SHADER_SKYBOX);
|
||||
Material* material = lovrGraphicsGetMaterial();
|
||||
Texture* lastTexture = lovrMaterialGetTexture(material, TEXTURE_ENVIRONMENT_MAP);
|
||||
lovrMaterialSetTexture(material, TEXTURE_ENVIRONMENT_MAP, texture);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 0, 0, 0);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
} else if (skybox->type == SKYBOX_PANORAMA) {
|
||||
lovrGraphicsSphere(NULL, NULL, 30, skybox);
|
||||
lovrMaterialSetTexture(material, TEXTURE_ENVIRONMENT_MAP, lastTexture);
|
||||
} else if (texture->type == TEXTURE_2D) {
|
||||
Material* material = lovrGraphicsGetMaterial();
|
||||
Texture* lastTexture = lovrMaterialGetTexture(material, TEXTURE_DIFFUSE);
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
|
||||
lovrGraphicsSphere(NULL, 30);
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, lastTexture);
|
||||
}
|
||||
|
||||
lovrGraphicsSetCullingEnabled(wasCulling);
|
||||
|
@ -872,68 +936,80 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl
|
|||
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
|
||||
lovrGraphicsScale(MATRIX_MODEL, scale, scale, scale);
|
||||
lovrGraphicsTranslate(MATRIX_MODEL, 0, offsety, 0);
|
||||
lovrGraphicsBindTexture(font->texture);
|
||||
lovrGraphicsSetDefaultShader(SHADER_FONT);
|
||||
Material* material = lovrGraphicsGetMaterial();
|
||||
Texture* lastTexture = lovrMaterialGetTexture(material, TEXTURE_DIFFUSE);
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, font->texture);
|
||||
glDepthMask(GL_FALSE);
|
||||
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 0, 1, 0);
|
||||
glDepthMask(GL_TRUE);
|
||||
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, lastTexture);
|
||||
lovrGraphicsPop();
|
||||
}
|
||||
|
||||
// Internal State
|
||||
void lovrGraphicsPushCanvas() {
|
||||
if (++state.canvas >= MAX_CANVASES) {
|
||||
lovrThrow("Canvas overflow");
|
||||
void lovrGraphicsPushView() {
|
||||
if (++state.view >= MAX_VIEWS) {
|
||||
lovrThrow("View overflow");
|
||||
}
|
||||
|
||||
memcpy(&state.canvases[state.canvas], &state.canvases[state.canvas - 1], sizeof(CanvasState));
|
||||
memcpy(&state.views[state.view], &state.views[state.view - 1], sizeof(View));
|
||||
}
|
||||
|
||||
void lovrGraphicsPopCanvas() {
|
||||
if (--state.canvas < 0) {
|
||||
lovrThrow("Canvas underflow");
|
||||
void lovrGraphicsPopView() {
|
||||
if (--state.view < 0) {
|
||||
lovrThrow("View underflow");
|
||||
}
|
||||
|
||||
int* viewport = state.canvases[state.canvas].viewport;
|
||||
int* viewport = state.views[state.view].viewport;
|
||||
lovrGraphicsSetViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
lovrGraphicsBindFramebuffer(state.canvases[state.canvas].framebuffer);
|
||||
lovrGraphicsBindFramebuffer(state.views[state.view].framebuffer);
|
||||
}
|
||||
|
||||
mat4 lovrGraphicsGetProjection() {
|
||||
return state.canvases[state.canvas].projection;
|
||||
return state.views[state.view].projection;
|
||||
}
|
||||
|
||||
void lovrGraphicsSetProjection(mat4 projection) {
|
||||
memcpy(state.canvases[state.canvas].projection, projection, 16 * sizeof(float));
|
||||
memcpy(state.views[state.view].projection, projection, 16 * sizeof(float));
|
||||
}
|
||||
|
||||
void lovrGraphicsSetViewport(int x, int y, int w, int h) {
|
||||
state.canvases[state.canvas].viewport[0] = x;
|
||||
state.canvases[state.canvas].viewport[1] = y;
|
||||
state.canvases[state.canvas].viewport[2] = w;
|
||||
state.canvases[state.canvas].viewport[3] = h;
|
||||
state.views[state.view].viewport[0] = x;
|
||||
state.views[state.view].viewport[1] = y;
|
||||
state.views[state.view].viewport[2] = w;
|
||||
state.views[state.view].viewport[3] = h;
|
||||
glViewport(x, y, w, h);
|
||||
}
|
||||
|
||||
void lovrGraphicsBindFramebuffer(int framebuffer) {
|
||||
state.canvases[state.canvas].framebuffer = framebuffer;
|
||||
state.views[state.view].framebuffer = framebuffer;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
}
|
||||
|
||||
Texture* lovrGraphicsGetTexture() {
|
||||
return state.texture;
|
||||
Texture* lovrGraphicsGetTexture(int slot) {
|
||||
return state.textures[slot];
|
||||
}
|
||||
|
||||
void lovrGraphicsBindTexture(Texture* texture) {
|
||||
void lovrGraphicsBindTexture(Texture* texture, TextureType type, int slot) {
|
||||
if (!texture) {
|
||||
if (!state.defaultTexture) {
|
||||
state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA));
|
||||
TextureData* textureData = lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA);
|
||||
state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1);
|
||||
}
|
||||
|
||||
texture = state.defaultTexture;
|
||||
}
|
||||
|
||||
if (texture != state.texture) {
|
||||
state.texture = texture;
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
if (texture != state.textures[slot]) {
|
||||
if (state.textures[slot]) {
|
||||
lovrRelease(&state.textures[slot]->ref);
|
||||
}
|
||||
|
||||
state.textures[slot] = texture;
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(type, texture->id);
|
||||
lovrRetain(&texture->ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
#include "graphics/font.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "graphics/skybox.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "math/math.h"
|
||||
#include "lib/glfw.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MAX_CANVASES 4
|
||||
#define MAX_VIEWS 4
|
||||
#define MAX_TRANSFORMS 60
|
||||
#define INTERNAL_TRANSFORMS 4
|
||||
#define DEFAULT_SHADER_COUNT 4
|
||||
#define MAX_TEXTURES 16
|
||||
|
||||
typedef enum {
|
||||
BLEND_ALPHA,
|
||||
|
@ -48,6 +49,11 @@ typedef enum {
|
|||
COMPARE_GREATER = GL_GREATER
|
||||
} CompareMode;
|
||||
|
||||
typedef enum {
|
||||
MATRIX_MODEL,
|
||||
MATRIX_VIEW
|
||||
} MatrixType;
|
||||
|
||||
typedef struct {
|
||||
int initialized;
|
||||
float pointSizes[2];
|
||||
|
@ -60,17 +66,13 @@ typedef struct {
|
|||
int framebuffer;
|
||||
float projection[16];
|
||||
int viewport[4];
|
||||
} CanvasState;
|
||||
|
||||
typedef enum {
|
||||
MATRIX_MODEL,
|
||||
MATRIX_VIEW
|
||||
} MatrixType;
|
||||
} View;
|
||||
|
||||
typedef struct {
|
||||
GLFWwindow* window;
|
||||
Shader* defaultShaders[DEFAULT_SHADER_COUNT];
|
||||
DefaultShader defaultShader;
|
||||
Material* defaultMaterial;
|
||||
Font* defaultFont;
|
||||
Texture* defaultTexture;
|
||||
float transforms[MAX_TRANSFORMS + INTERNAL_TRANSFORMS][2][16];
|
||||
|
@ -85,6 +87,7 @@ typedef struct {
|
|||
Font* font;
|
||||
GraphicsLimits limits;
|
||||
float lineWidth;
|
||||
Material* material;
|
||||
float pointSize;
|
||||
Shader* shader;
|
||||
Winding winding;
|
||||
|
@ -94,9 +97,9 @@ typedef struct {
|
|||
uint32_t streamIBO;
|
||||
vec_float_t streamData;
|
||||
vec_uint_t streamIndices;
|
||||
CanvasState canvases[MAX_CANVASES];
|
||||
int canvas;
|
||||
Texture* texture;
|
||||
View views[MAX_VIEWS];
|
||||
int view;
|
||||
Texture* textures[MAX_TEXTURES];
|
||||
uint32_t program;
|
||||
uint32_t vertexArray;
|
||||
uint32_t vertexBuffer;
|
||||
|
@ -132,6 +135,8 @@ void lovrGraphicsSetFont(Font* font);
|
|||
GraphicsLimits lovrGraphicsGetLimits();
|
||||
float lovrGraphicsGetLineWidth();
|
||||
void lovrGraphicsSetLineWidth(float width);
|
||||
Material* lovrGraphicsGetMaterial();
|
||||
void lovrGraphicsSetMaterial(Material* material);
|
||||
float lovrGraphicsGetPointSize();
|
||||
void lovrGraphicsSetPointSize(float size);
|
||||
Shader* lovrGraphicsGetShader();
|
||||
|
@ -154,23 +159,23 @@ void lovrGraphicsMatrixTransform(MatrixType type, mat4 transform);
|
|||
void lovrGraphicsPoints(float* points, int count);
|
||||
void lovrGraphicsLine(float* points, int count);
|
||||
void lovrGraphicsTriangle(DrawMode mode, float* points);
|
||||
void lovrGraphicsPlane(DrawMode mode, Texture* texture, mat4 transform);
|
||||
void lovrGraphicsPlane(DrawMode mode, mat4 transform);
|
||||
void lovrGraphicsPlaneFullscreen(Texture* texture);
|
||||
void lovrGraphicsBox(DrawMode mode, Texture* texture, mat4 transform);
|
||||
void lovrGraphicsBox(DrawMode mode, mat4 transform);
|
||||
void lovrGraphicsCylinder(float x1, float y1, float z1, float x2, float y2, float z2, float r1, float r2, int capped, int segments);
|
||||
void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox* skybox);
|
||||
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az);
|
||||
void lovrGraphicsSphere(mat4 transform, int segments);
|
||||
void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float az);
|
||||
void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign);
|
||||
|
||||
// Internal State
|
||||
void lovrGraphicsPushCanvas();
|
||||
void lovrGraphicsPopCanvas();
|
||||
void lovrGraphicsPushView();
|
||||
void lovrGraphicsPopView();
|
||||
mat4 lovrGraphicsGetProjection();
|
||||
void lovrGraphicsSetProjection(mat4 projection);
|
||||
void lovrGraphicsSetViewport(int x, int y, int w, int h);
|
||||
void lovrGraphicsBindFramebuffer(int framebuffer);
|
||||
Texture* lovrGraphicsGetTexture();
|
||||
void lovrGraphicsBindTexture(Texture* texture);
|
||||
void lovrGraphicsBindTexture(Texture* texture, TextureType type, int slot);
|
||||
void lovrGraphicsSetDefaultShader(DefaultShader defaultShader);
|
||||
Shader* lovrGraphicsGetActiveShader();
|
||||
void lovrGraphicsBindProgram(uint32_t program);
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#include "graphics/graphics.h"
|
||||
#include "graphics/material.h"
|
||||
|
||||
Material* lovrMaterialCreate(MaterialData* materialData, int isDefault) {
|
||||
Material* material = lovrAlloc(sizeof(Material), lovrMaterialDestroy);
|
||||
if (!material) return NULL;
|
||||
|
||||
material->materialData = materialData;
|
||||
material->isDefault = isDefault;
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
|
||||
if (materialData->textures[i]) {
|
||||
material->textures[i] = lovrTextureCreate(TEXTURE_2D, &materialData->textures[i], 1);
|
||||
} else {
|
||||
material->textures[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
void lovrMaterialDestroy(const Ref* ref) {
|
||||
Material* material = containerof(ref, Material);
|
||||
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
|
||||
if (material->textures[i]) {
|
||||
lovrRelease(&material->textures[i]->ref);
|
||||
}
|
||||
}
|
||||
free(material);
|
||||
}
|
||||
|
||||
Color lovrMaterialGetColor(Material* material, MaterialColor colorType) {
|
||||
return material->materialData->colors[colorType];
|
||||
}
|
||||
|
||||
void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color) {
|
||||
material->materialData->colors[colorType] = color;
|
||||
}
|
||||
|
||||
Texture* lovrMaterialGetTexture(Material* material, MaterialTexture textureType) {
|
||||
return material->textures[textureType];
|
||||
}
|
||||
|
||||
void lovrMaterialSetTexture(Material* material, MaterialTexture textureType, Texture* texture) {
|
||||
material->textures[textureType] = texture;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#include "util.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "loaders/material.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
Ref ref;
|
||||
MaterialData* materialData;
|
||||
Texture* textures[MAX_MATERIAL_TEXTURES];
|
||||
int isDefault;
|
||||
} Material;
|
||||
|
||||
Material* lovrMaterialCreate(MaterialData* materialData, int isDefault);
|
||||
void lovrMaterialDestroy(const Ref* ref);
|
||||
Color lovrMaterialGetColor(Material* material, MaterialColor colorType);
|
||||
void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color);
|
||||
Texture* lovrMaterialGetTexture(Material* material, MaterialTexture textureType);
|
||||
void lovrMaterialSetTexture(Material* material, MaterialTexture textureType, Texture* texture);
|
|
@ -1,5 +1,6 @@
|
|||
#include "graphics/mesh.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -43,7 +44,6 @@ Mesh* lovrMeshCreate(size_t count, MeshFormat* format, MeshDrawMode drawMode, Me
|
|||
Mesh* mesh = lovrAlloc(sizeof(Mesh), lovrMeshDestroy);
|
||||
if (!mesh) return NULL;
|
||||
|
||||
vec_init(&mesh->map);
|
||||
vec_init(&mesh->format);
|
||||
|
||||
if (format) {
|
||||
|
@ -79,10 +79,12 @@ Mesh* lovrMeshCreate(size_t count, MeshFormat* format, MeshDrawMode drawMode, Me
|
|||
mesh->vao = 0;
|
||||
mesh->vbo = 0;
|
||||
mesh->ibo = 0;
|
||||
mesh->indices = NULL;
|
||||
mesh->indexCount = 0;
|
||||
mesh->indexSize = count > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
|
||||
mesh->isRangeEnabled = 0;
|
||||
mesh->rangeStart = 0;
|
||||
mesh->rangeCount = mesh->count;
|
||||
mesh->texture = NULL;
|
||||
mesh->lastShader = NULL;
|
||||
|
||||
glGenBuffers(1, &mesh->vbo);
|
||||
|
@ -100,14 +102,11 @@ Mesh* lovrMeshCreate(size_t count, MeshFormat* format, MeshDrawMode drawMode, Me
|
|||
|
||||
void lovrMeshDestroy(const Ref* ref) {
|
||||
Mesh* mesh = containerof(ref, Mesh);
|
||||
if (mesh->texture) {
|
||||
lovrRelease(&mesh->texture->ref);
|
||||
}
|
||||
glDeleteBuffers(1, &mesh->vbo);
|
||||
glDeleteBuffers(1, &mesh->ibo);
|
||||
glDeleteVertexArrays(1, &mesh->vao);
|
||||
vec_deinit(&mesh->map);
|
||||
vec_deinit(&mesh->format);
|
||||
free(mesh->indices);
|
||||
#ifdef EMSCRIPTEN
|
||||
free(mesh->data);
|
||||
#endif
|
||||
|
@ -119,21 +118,28 @@ void lovrMeshDraw(Mesh* mesh, mat4 transform) {
|
|||
lovrMeshUnmap(mesh);
|
||||
}
|
||||
|
||||
if (transform) {
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
|
||||
lovrGraphicsBindTexture(mesh->texture);
|
||||
}
|
||||
|
||||
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
|
||||
lovrGraphicsPrepare();
|
||||
lovrGraphicsBindVertexArray(mesh->vao);
|
||||
lovrMeshBindAttributes(mesh);
|
||||
size_t start = mesh->rangeStart;
|
||||
size_t count = mesh->rangeCount;
|
||||
if (mesh->map.length > 0) {
|
||||
glDrawElements(mesh->drawMode, mesh->map.length, GL_UNSIGNED_INT, (GLvoid*) start);
|
||||
if (mesh->indexCount > 0) {
|
||||
count = mesh->isRangeEnabled ? mesh->rangeCount : mesh->indexCount;
|
||||
GLenum indexType = mesh->indexSize == sizeof(uint16_t) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
||||
glDrawElements(mesh->drawMode, count, indexType, (GLvoid*) (start * mesh->indexSize));
|
||||
} else {
|
||||
glDrawArrays(mesh->drawMode, start, count);
|
||||
}
|
||||
|
||||
if (transform) {
|
||||
lovrGraphicsPop();
|
||||
}
|
||||
}
|
||||
|
||||
MeshFormat lovrMeshGetVertexFormat(Mesh* mesh) {
|
||||
|
@ -144,9 +150,8 @@ MeshDrawMode lovrMeshGetDrawMode(Mesh* mesh) {
|
|||
return mesh->drawMode;
|
||||
}
|
||||
|
||||
int lovrMeshSetDrawMode(Mesh* mesh, MeshDrawMode drawMode) {
|
||||
void lovrMeshSetDrawMode(Mesh* mesh, MeshDrawMode drawMode) {
|
||||
mesh->drawMode = drawMode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lovrMeshGetVertexCount(Mesh* mesh) {
|
||||
|
@ -157,21 +162,22 @@ int lovrMeshGetVertexSize(Mesh* mesh) {
|
|||
return mesh->stride;
|
||||
}
|
||||
|
||||
unsigned int* lovrMeshGetVertexMap(Mesh* mesh, size_t* count) {
|
||||
*count = mesh->map.length;
|
||||
return mesh->map.data;
|
||||
void* lovrMeshGetVertexMap(Mesh* mesh, size_t* count) {
|
||||
*count = mesh->indexCount;
|
||||
return mesh->indices;
|
||||
}
|
||||
|
||||
void lovrMeshSetVertexMap(Mesh* mesh, unsigned int* map, size_t count) {
|
||||
if (count == 0 || !map) {
|
||||
vec_clear(&mesh->map);
|
||||
} else {
|
||||
vec_clear(&mesh->map);
|
||||
vec_pusharr(&mesh->map, map, count);
|
||||
void lovrMeshSetVertexMap(Mesh* mesh, void* data, size_t count) {
|
||||
if (!data || count == 0) {
|
||||
mesh->indexCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mesh->indices = data;
|
||||
mesh->indexCount = count;
|
||||
lovrGraphicsBindVertexArray(mesh->vao);
|
||||
lovrGraphicsBindIndexBuffer(mesh->ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), mesh->map.data, GL_STATIC_DRAW);
|
||||
}
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->indexCount * mesh->indexSize, mesh->indices, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
int lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
||||
|
@ -223,32 +229,12 @@ void lovrMeshGetDrawRange(Mesh* mesh, int* start, int* count) {
|
|||
*count = mesh->rangeCount;
|
||||
}
|
||||
|
||||
int lovrMeshSetDrawRange(Mesh* mesh, int start, int count) {
|
||||
if (start < 0 || count < 0 || (size_t) start + count > mesh->count) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void lovrMeshSetDrawRange(Mesh* mesh, int start, int count) {
|
||||
size_t limit = mesh->indexCount > 0 ? mesh->indexCount : mesh->count;
|
||||
int isValidRange = start >= 0 && count >= 0 && (size_t) start + count <= limit;
|
||||
lovrAssert(isValidRange, "Invalid mesh draw range [%d, %d]", start + 1, start + count + 1);
|
||||
mesh->rangeStart = start;
|
||||
mesh->rangeCount = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Texture* lovrMeshGetTexture(Mesh* mesh) {
|
||||
return mesh->texture;
|
||||
}
|
||||
|
||||
void lovrMeshSetTexture(Mesh* mesh, Texture* texture) {
|
||||
if (mesh->texture != texture) {
|
||||
if (mesh->texture) {
|
||||
lovrRelease(&mesh->texture->ref);
|
||||
}
|
||||
|
||||
mesh->texture = texture;
|
||||
|
||||
if (mesh->texture) {
|
||||
lovrRetain(&mesh->texture->ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* lovrMeshMap(Mesh* mesh, int start, size_t count, int read, int write) {
|
||||
|
|
|
@ -49,11 +49,12 @@ typedef struct {
|
|||
GLuint vao;
|
||||
GLuint vbo;
|
||||
GLuint ibo;
|
||||
vec_uint_t map;
|
||||
void* indices;
|
||||
size_t indexCount;
|
||||
size_t indexSize;
|
||||
int isRangeEnabled;
|
||||
int rangeStart;
|
||||
int rangeCount;
|
||||
Texture* texture;
|
||||
Shader* lastShader;
|
||||
} Mesh;
|
||||
|
||||
|
@ -62,17 +63,17 @@ void lovrMeshDestroy(const Ref* ref);
|
|||
void lovrMeshDraw(Mesh* mesh, mat4 transform);
|
||||
MeshFormat lovrMeshGetVertexFormat(Mesh* mesh);
|
||||
MeshDrawMode lovrMeshGetDrawMode(Mesh* mesh);
|
||||
int lovrMeshSetDrawMode(Mesh* mesh, MeshDrawMode drawMode);
|
||||
void lovrMeshSetDrawMode(Mesh* mesh, MeshDrawMode drawMode);
|
||||
int lovrMeshGetVertexCount(Mesh* mesh);
|
||||
int lovrMeshGetVertexSize(Mesh* mesh);
|
||||
unsigned int* lovrMeshGetVertexMap(Mesh* mesh, size_t* count);
|
||||
void lovrMeshSetVertexMap(Mesh* mesh, unsigned int* map, size_t count);
|
||||
void* lovrMeshGetVertexMap(Mesh* mesh, size_t* count);
|
||||
void lovrMeshSetVertexMap(Mesh* mesh, void* data, size_t count);
|
||||
int lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name);
|
||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, int enabled);
|
||||
int lovrMeshIsRangeEnabled(Mesh* mesh);
|
||||
void lovrMeshSetRangeEnabled(Mesh* mesh, char isEnabled);
|
||||
void lovrMeshGetDrawRange(Mesh* mesh, int* start, int* count);
|
||||
int lovrMeshSetDrawRange(Mesh* mesh, int start, int count);
|
||||
void lovrMeshSetDrawRange(Mesh* mesh, int start, int count);
|
||||
Texture* lovrMeshGetTexture(Mesh* mesh);
|
||||
void lovrMeshSetTexture(Mesh* mesh, Texture* texture);
|
||||
void* lovrMeshMap(Mesh* mesh, int start, size_t count, int read, int write);
|
||||
|
|
|
@ -3,65 +3,31 @@
|
|||
#include "math/mat4.h"
|
||||
#include "math/vec3.h"
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
|
||||
static void visitNode(Model* model, ModelData* modelData, ModelNode* node, mat4 transform, vec_float_t* vertices, vec_uint_t* indices) {
|
||||
float newTransform[16];
|
||||
static void renderNode(Model* model, int nodeIndex) {
|
||||
ModelNode* node = &model->modelData->nodes[nodeIndex];
|
||||
Material* currentMaterial = lovrGraphicsGetMaterial();
|
||||
int useMaterials = currentMaterial->isDefault;
|
||||
|
||||
if (transform) {
|
||||
mat4_set(newTransform, transform);
|
||||
} else {
|
||||
mat4_identity(newTransform);
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsMatrixTransform(MATRIX_MODEL, node->transform);
|
||||
|
||||
for (int i = 0; i < node->primitives.length; i++) {
|
||||
ModelPrimitive* primitive = &model->modelData->primitives[node->primitives.data[i]];
|
||||
if (useMaterials) {
|
||||
lovrGraphicsSetMaterial(model->materials[primitive->material]);
|
||||
}
|
||||
lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount);
|
||||
lovrMeshDraw(model->mesh, NULL);
|
||||
}
|
||||
|
||||
mat4_multiply(newTransform, node->transform);
|
||||
|
||||
int indexOffset = vertices->length / 3;
|
||||
|
||||
// Meshes
|
||||
for (int m = 0; m < node->meshes.length; m++) {
|
||||
ModelMesh* mesh = modelData->meshes.data[node->meshes.data[m]];
|
||||
|
||||
// Transformed vertices
|
||||
for (int v = 0; v < mesh->vertices.length; v++) {
|
||||
ModelVertex vertex = mesh->vertices.data[v];
|
||||
|
||||
float vec[3] = { vertex.x, vertex.y, vertex.z };
|
||||
mat4_transform(newTransform, vec);
|
||||
vec_pusharr(vertices, vec, 3);
|
||||
|
||||
model->aabb[0] = MIN(model->aabb[0], vec[0]);
|
||||
model->aabb[1] = MAX(model->aabb[1], vec[0]);
|
||||
model->aabb[2] = MIN(model->aabb[2], vec[1]);
|
||||
model->aabb[3] = MAX(model->aabb[3], vec[1]);
|
||||
model->aabb[4] = MIN(model->aabb[4], vec[2]);
|
||||
model->aabb[5] = MAX(model->aabb[5], vec[2]);
|
||||
|
||||
if (modelData->hasNormals) {
|
||||
ModelVertex normal = mesh->normals.data[v];
|
||||
vec_push(vertices, normal.x);
|
||||
vec_push(vertices, normal.y);
|
||||
vec_push(vertices, normal.z);
|
||||
for (int i = 0; i < node->children.length; i++) {
|
||||
renderNode(model, node->children.data[i]);
|
||||
}
|
||||
|
||||
if (modelData->hasTexCoords) {
|
||||
ModelVertex texCoord = mesh->texCoords.data[v];
|
||||
vec_push(vertices, texCoord.x);
|
||||
vec_push(vertices, texCoord.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Face vertex indices
|
||||
for (int f = 0; f < mesh->faces.length; f++) {
|
||||
ModelFace face = mesh->faces.data[f];
|
||||
vec_push(indices, face.indices[0] + indexOffset);
|
||||
vec_push(indices, face.indices[1] + indexOffset);
|
||||
vec_push(indices, face.indices[2] + indexOffset);
|
||||
}
|
||||
}
|
||||
|
||||
for (int c = 0; c < node->children.length; c++) {
|
||||
visitNode(model, modelData, node->children.data[c], newTransform, vertices, indices);
|
||||
lovrGraphicsPop();
|
||||
if (useMaterials) {
|
||||
lovrGraphicsSetMaterial(currentMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,85 +36,61 @@ Model* lovrModelCreate(ModelData* modelData) {
|
|||
if (!model) return NULL;
|
||||
|
||||
model->modelData = modelData;
|
||||
model->aabb[0] = FLT_MAX;
|
||||
model->aabb[1] = FLT_MIN;
|
||||
model->aabb[2] = FLT_MAX;
|
||||
model->aabb[3] = FLT_MIN;
|
||||
model->aabb[4] = FLT_MAX;
|
||||
model->aabb[5] = FLT_MIN;
|
||||
|
||||
vec_float_t vertices;
|
||||
vec_init(&vertices);
|
||||
|
||||
vec_uint_t indices;
|
||||
vec_init(&indices);
|
||||
|
||||
visitNode(model, modelData, modelData->root, NULL, &vertices, &indices);
|
||||
|
||||
MeshFormat format;
|
||||
vec_init(&format);
|
||||
|
||||
int components = 3;
|
||||
MeshAttribute position = { .name = "lovrPosition", .type = MESH_FLOAT, .count = 3 };
|
||||
vec_push(&format, position);
|
||||
MeshAttribute attribute = { .name = "lovrPosition", .type = MESH_FLOAT, .count = 3 };
|
||||
vec_push(&format, attribute);
|
||||
|
||||
if (modelData->hasNormals) {
|
||||
MeshAttribute normal = { .name = "lovrNormal", .type = MESH_FLOAT, .count = 3 };
|
||||
vec_push(&format, normal);
|
||||
components += 3;
|
||||
MeshAttribute attribute = { .name = "lovrNormal", .type = MESH_FLOAT, .count = 3 };
|
||||
vec_push(&format, attribute);
|
||||
}
|
||||
|
||||
if (modelData->hasTexCoords) {
|
||||
MeshAttribute texCoord = { .name = "lovrTexCoord", .type = MESH_FLOAT, .count = 2 };
|
||||
vec_push(&format, texCoord);
|
||||
components += 2;
|
||||
if (modelData->hasUVs) {
|
||||
MeshAttribute attribute = { .name = "lovrTexCoord", .type = MESH_FLOAT, .count = 2 };
|
||||
vec_push(&format, attribute);
|
||||
}
|
||||
|
||||
model->mesh = lovrMeshCreate(vertices.length / components, &format, MESH_TRIANGLES, MESH_STATIC);
|
||||
void* data = lovrMeshMap(model->mesh, 0, vertices.length / components, 0, 1);
|
||||
memcpy(data, vertices.data, vertices.length * sizeof(float));
|
||||
model->mesh = lovrMeshCreate(modelData->vertexCount, &format, MESH_TRIANGLES, MESH_STATIC);
|
||||
void* data = lovrMeshMap(model->mesh, 0, modelData->vertexCount, 0, 1);
|
||||
memcpy(data, modelData->vertices, modelData->vertexCount * modelData->vertexSize * sizeof(float));
|
||||
lovrMeshUnmap(model->mesh);
|
||||
lovrMeshSetVertexMap(model->mesh, indices.data, indices.length);
|
||||
lovrMeshSetVertexMap(model->mesh, modelData->indices, modelData->indexCount);
|
||||
lovrMeshSetRangeEnabled(model->mesh, 1);
|
||||
|
||||
model->texture = NULL;
|
||||
model->materials = malloc(modelData->materialCount * sizeof(Material*));
|
||||
for (int i = 0; i < modelData->materialCount; i++) {
|
||||
model->materials[i] = lovrMaterialCreate(&modelData->materials[i], 0);
|
||||
}
|
||||
|
||||
vec_deinit(&format);
|
||||
vec_deinit(&vertices);
|
||||
vec_deinit(&indices);
|
||||
return model;
|
||||
}
|
||||
|
||||
void lovrModelDestroy(const Ref* ref) {
|
||||
Model* model = containerof(ref, Model);
|
||||
if (model->texture) {
|
||||
lovrRelease(&model->texture->ref);
|
||||
for (int i = 0; i < model->modelData->materialCount; i++) {
|
||||
lovrRelease(&model->materials[i]->ref);
|
||||
}
|
||||
free(model->materials);
|
||||
lovrModelDataDestroy(model->modelData);
|
||||
lovrRelease(&model->mesh->ref);
|
||||
free(model);
|
||||
}
|
||||
|
||||
void lovrModelDraw(Model* model, mat4 transform) {
|
||||
lovrMeshDraw(model->mesh, transform);
|
||||
}
|
||||
|
||||
Texture* lovrModelGetTexture(Model* model) {
|
||||
return model->texture;
|
||||
}
|
||||
|
||||
void lovrModelSetTexture(Model* model, Texture* texture) {
|
||||
if (model->texture) {
|
||||
lovrRelease(&model->texture->ref);
|
||||
if (model->modelData->nodeCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
model->texture = texture;
|
||||
lovrMeshSetTexture(model->mesh, model->texture);
|
||||
|
||||
if (model->texture) {
|
||||
lovrRetain(&model->texture->ref);
|
||||
}
|
||||
lovrGraphicsPush();
|
||||
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
|
||||
renderNode(model, 0);
|
||||
lovrGraphicsPop();
|
||||
}
|
||||
|
||||
float* lovrModelGetAABB(Model* model) {
|
||||
return model->aabb;
|
||||
Mesh* lovrModelGetMesh(Model* model) {
|
||||
return model->mesh;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "loaders/model.h"
|
||||
#include "graphics/material.h"
|
||||
#include "graphics/mesh.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "math/math.h"
|
||||
|
@ -11,13 +12,10 @@ typedef struct {
|
|||
Ref ref;
|
||||
ModelData* modelData;
|
||||
Mesh* mesh;
|
||||
Texture* texture;
|
||||
float aabb[6];
|
||||
Material** materials;
|
||||
} Model;
|
||||
|
||||
Model* lovrModelCreate(ModelData* modelData);
|
||||
void lovrModelDestroy(const Ref* ref);
|
||||
void lovrModelDraw(Model* model, mat4 transform);
|
||||
Texture* lovrModelGetTexture(Model* model);
|
||||
void lovrModelSetTexture(Model* model, Texture* texture);
|
||||
float* lovrModelGetAABB(Model* model);
|
||||
Mesh* lovrModelGetMesh(Model* model);
|
||||
|
|
|
@ -1,90 +1,66 @@
|
|||
#include "graphics/shader.h"
|
||||
#include "graphics/shaders.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "math/mat4.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char* lovrShaderVertexPrefix = ""
|
||||
#ifdef EMSCRIPTEN
|
||||
"#version 300 es \n"
|
||||
"precision mediump float; \n"
|
||||
#else
|
||||
"#version 150 \n"
|
||||
#endif
|
||||
"in vec3 lovrPosition; \n"
|
||||
"in vec3 lovrNormal; \n"
|
||||
"in vec2 lovrTexCoord; \n"
|
||||
"out vec2 texCoord; \n"
|
||||
"uniform mat4 lovrModel; \n"
|
||||
"uniform mat4 lovrView; \n"
|
||||
"uniform mat4 lovrProjection; \n"
|
||||
"uniform mat4 lovrTransform; \n"
|
||||
"uniform mat3 lovrNormalMatrix; \n";
|
||||
static UniformType getUniformType(GLenum type, const char* debug) {
|
||||
switch (type) {
|
||||
case GL_FLOAT:
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_FLOAT_VEC4:
|
||||
return UNIFORM_FLOAT;
|
||||
|
||||
static const char* lovrShaderFragmentPrefix = ""
|
||||
#ifdef EMSCRIPTEN
|
||||
"#version 300 es \n"
|
||||
"precision mediump float; \n"
|
||||
#else
|
||||
"#version 150 \n"
|
||||
"in vec4 gl_FragCoord; \n"
|
||||
#endif
|
||||
"in vec2 texCoord; \n"
|
||||
"out vec4 lovrFragColor; \n"
|
||||
"uniform vec4 lovrColor; \n"
|
||||
"uniform sampler2D lovrTexture; \n";
|
||||
case GL_INT:
|
||||
case GL_INT_VEC2:
|
||||
case GL_INT_VEC3:
|
||||
case GL_INT_VEC4:
|
||||
return UNIFORM_INT;
|
||||
|
||||
static const char* lovrShaderVertexSuffix = ""
|
||||
"void main() { \n"
|
||||
" texCoord = lovrTexCoord; \n"
|
||||
" gl_Position = position(lovrProjection, lovrTransform, vec4(lovrPosition, 1.0)); \n"
|
||||
"}";
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT4:
|
||||
return UNIFORM_MATRIX;
|
||||
|
||||
static const char* lovrShaderFragmentSuffix = ""
|
||||
"void main() { \n"
|
||||
" lovrFragColor = color(lovrColor, lovrTexture, texCoord); \n"
|
||||
"}";
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_CUBE:
|
||||
return UNIFORM_SAMPLER;
|
||||
|
||||
static const char* lovrDefaultVertexShader = ""
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" return projection * transform * vertex; \n"
|
||||
"}";
|
||||
default:
|
||||
lovrThrow("Unsupported type for uniform '%s'", debug);
|
||||
return UNIFORM_FLOAT;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* lovrDefaultFragmentShader = ""
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" return graphicsColor * texture(image, uv); \n"
|
||||
"}";
|
||||
static int getUniformComponents(GLenum type) {
|
||||
switch (type) {
|
||||
case GL_FLOAT:
|
||||
case GL_INT:
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_CUBE:
|
||||
return 1;
|
||||
|
||||
static const char* lovrSkyboxVertexShader = ""
|
||||
"out vec3 texturePosition; \n"
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" texturePosition = vertex.xyz; \n"
|
||||
" return projection * transform * vertex; \n"
|
||||
"}";
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_INT_VEC2:
|
||||
case GL_FLOAT_MAT2:
|
||||
return 2;
|
||||
|
||||
static const char* lovrSkyboxFragmentShader = ""
|
||||
"in vec3 texturePosition; \n"
|
||||
"uniform samplerCube cube; \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" return graphicsColor * texture(cube, texturePosition); \n"
|
||||
"}";
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_INT_VEC3:
|
||||
case GL_FLOAT_MAT3:
|
||||
return 3;
|
||||
|
||||
static const char* lovrFontFragmentShader = ""
|
||||
"float median(float r, float g, float b) { \n"
|
||||
" return max(min(r, g), min(max(r, g), b)); \n"
|
||||
"} \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" vec3 col = texture(image, uv).rgb; \n"
|
||||
" float sdf = median(col.r, col.g, col.b); \n"
|
||||
" float w = fwidth(sdf); \n"
|
||||
" float alpha = smoothstep(.5 - w, .5 + w, sdf); \n"
|
||||
" return vec4(graphicsColor.rgb, graphicsColor.a * alpha); \n"
|
||||
"}";
|
||||
case GL_FLOAT_VEC4:
|
||||
case GL_INT_VEC4:
|
||||
case GL_FLOAT_MAT4:
|
||||
return 4;
|
||||
|
||||
static const char* lovrNoopVertexShader = ""
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" return vertex; \n"
|
||||
"}";
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static GLuint compileShader(GLenum type, const char* source) {
|
||||
GLuint shader = glCreateShader(type);
|
||||
|
@ -160,34 +136,95 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
|
|||
|
||||
// Link
|
||||
GLuint id = linkShaders(vertexShader, fragmentShader);
|
||||
shader->id = id;
|
||||
|
||||
// Compute information about uniforms
|
||||
lovrGraphicsBindProgram(id);
|
||||
|
||||
// Uniform introspection
|
||||
GLint uniformCount;
|
||||
int textureSlot = 0;
|
||||
GLsizei bufferSize = LOVR_MAX_UNIFORM_LENGTH / sizeof(GLchar);
|
||||
map_init(&shader->uniforms);
|
||||
glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount);
|
||||
for (int i = 0; i < uniformCount; i++) {
|
||||
Uniform uniform;
|
||||
glGetActiveUniform(id, i, bufferSize, NULL, &uniform.count, &uniform.type, uniform.name);
|
||||
glGetActiveUniform(id, i, bufferSize, NULL, &uniform.count, &uniform.glType, uniform.name);
|
||||
|
||||
char* subscript = strchr(uniform.name, '[');
|
||||
if (subscript) {
|
||||
*subscript = '\0';
|
||||
}
|
||||
uniform.location = glGetUniformLocation(id, uniform.name);
|
||||
|
||||
uniform.index = i;
|
||||
map_set(&shader->uniforms, uniform.name, uniform);
|
||||
uniform.location = glGetUniformLocation(id, uniform.name);
|
||||
uniform.type = getUniformType(uniform.glType, uniform.name);
|
||||
uniform.components = getUniformComponents(uniform.glType);
|
||||
uniform.baseTextureSlot = (uniform.type == UNIFORM_SAMPLER) ? textureSlot : -1;
|
||||
|
||||
switch (uniform.type) {
|
||||
case UNIFORM_FLOAT:
|
||||
uniform.size = uniform.components * uniform.count * sizeof(float);
|
||||
uniform.value.data = malloc(uniform.size);
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
uniform.size = uniform.components * uniform.count * sizeof(int);
|
||||
uniform.value.data = malloc(uniform.size);
|
||||
break;
|
||||
|
||||
case UNIFORM_MATRIX:
|
||||
uniform.size = uniform.components * uniform.components * uniform.count * sizeof(int);
|
||||
uniform.value.data = malloc(uniform.size);
|
||||
break;
|
||||
|
||||
case UNIFORM_SAMPLER:
|
||||
uniform.size = uniform.components * uniform.count * MAX(sizeof(Texture*), sizeof(int));
|
||||
uniform.value.data = malloc(uniform.size);
|
||||
|
||||
// Use the value for ints to bind texture slots, but use the value for textures afterwards.
|
||||
for (int i = 0; i < uniform.count; i++) {
|
||||
uniform.value.ints[i] = uniform.baseTextureSlot + i;
|
||||
}
|
||||
glUniform1iv(uniform.location, uniform.count, uniform.value.ints);
|
||||
break;
|
||||
}
|
||||
|
||||
// Initial state
|
||||
shader->id = id;
|
||||
mat4_identity(shader->model);
|
||||
mat4_identity(shader->view);
|
||||
mat4_identity(shader->projection);
|
||||
shader->color = (Color) { 0, 0, 0, 0 };
|
||||
memset(uniform.value.data, 0, uniform.size);
|
||||
|
||||
// Send initial uniform values to shader
|
||||
lovrGraphicsBindProgram(id);
|
||||
lovrShaderBind(shader, shader->model, shader->view, shader->projection, shader->color, 1);
|
||||
size_t offset = 0;
|
||||
for (int j = 0; j < uniform.count; j++) {
|
||||
int location = uniform.location;
|
||||
|
||||
if (uniform.count > 1) {
|
||||
char name[LOVR_MAX_UNIFORM_LENGTH];
|
||||
snprintf(name, LOVR_MAX_UNIFORM_LENGTH, "%s[%d]", uniform.name, j);
|
||||
location = glGetUniformLocation(id, name);
|
||||
}
|
||||
|
||||
switch (uniform.type) {
|
||||
case UNIFORM_FLOAT:
|
||||
glGetUniformfv(id, location, &uniform.value.floats[offset]);
|
||||
offset += uniform.components;
|
||||
break;
|
||||
|
||||
case UNIFORM_INT:
|
||||
glGetUniformiv(id, location, &uniform.value.ints[offset]);
|
||||
offset += uniform.components;
|
||||
break;
|
||||
|
||||
case UNIFORM_MATRIX:
|
||||
glGetUniformfv(id, location, &uniform.value.floats[offset]);
|
||||
offset += uniform.components * uniform.components;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
map_set(&shader->uniforms, uniform.name, uniform);
|
||||
textureSlot += (uniform.type == UNIFORM_SAMPLER) ? uniform.count : 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
@ -195,11 +232,7 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
|
|||
Shader* lovrShaderCreateDefault(DefaultShader type) {
|
||||
switch (type) {
|
||||
case SHADER_DEFAULT: return lovrShaderCreate(NULL, NULL);
|
||||
case SHADER_SKYBOX: {
|
||||
Shader* shader = lovrShaderCreate(lovrSkyboxVertexShader, lovrSkyboxFragmentShader);
|
||||
lovrShaderSendInt(shader, lovrShaderGetUniformId(shader, "cube"), 1);
|
||||
return shader;
|
||||
}
|
||||
case SHADER_SKYBOX: return lovrShaderCreate(lovrSkyboxVertexShader, lovrSkyboxFragmentShader); break;
|
||||
case SHADER_FONT: return lovrShaderCreate(NULL, lovrFontFragmentShader);
|
||||
case SHADER_FULLSCREEN: return lovrShaderCreate(lovrNoopVertexShader, NULL);
|
||||
default: lovrThrow("Unknown default shader type");
|
||||
|
@ -213,64 +246,54 @@ void lovrShaderDestroy(const Ref* ref) {
|
|||
free(shader);
|
||||
}
|
||||
|
||||
void lovrShaderBind(Shader* shader, mat4 model, mat4 view, mat4 projection, Color color, int force) {
|
||||
int dirtyModel = force || memcmp(shader->model, model, 16 * sizeof(float));
|
||||
int dirtyView = force || memcmp(shader->view, view, 16 * sizeof(float));
|
||||
int dirtyTransform = dirtyModel || dirtyView;
|
||||
int dirtyProjection = force || memcmp(shader->projection, projection, 16 * sizeof(float));
|
||||
int dirtyColor = force || memcmp(&shader->color, &color, sizeof(Color));
|
||||
void lovrShaderBind(Shader* shader) {
|
||||
map_iter_t iter = map_iter(&shader->uniforms);
|
||||
const char* key;
|
||||
while ((key = map_next(&shader->uniforms, &iter)) != NULL) {
|
||||
Uniform* uniform = map_get(&shader->uniforms, key);
|
||||
|
||||
if (dirtyModel) {
|
||||
int uniformId = lovrShaderGetUniformId(shader, "lovrModel");
|
||||
lovrShaderSendFloatMat4(shader, uniformId, model);
|
||||
memcpy(shader->model, model, 16 * sizeof(float));
|
||||
if (uniform->type != UNIFORM_SAMPLER && !uniform->dirty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dirtyView) {
|
||||
int uniformId = lovrShaderGetUniformId(shader, "lovrView");
|
||||
lovrShaderSendFloatMat4(shader, uniformId, view);
|
||||
memcpy(shader->view, view, 16 * sizeof(float));
|
||||
uniform->dirty = 0;
|
||||
int count = uniform->count;
|
||||
void* data = uniform->value.data;
|
||||
|
||||
switch (uniform->type) {
|
||||
case UNIFORM_FLOAT:
|
||||
switch (uniform->components) {
|
||||
case 1: glUniform1fv(uniform->location, count, data); break;
|
||||
case 2: glUniform2fv(uniform->location, count, data); break;
|
||||
case 3: glUniform3fv(uniform->location, count, data); break;
|
||||
case 4: glUniform4fv(uniform->location, count, data); break;
|
||||
}
|
||||
break;
|
||||
|
||||
if (dirtyTransform) {
|
||||
float matrix[16];
|
||||
int uniformId = lovrShaderGetUniformId(shader, "lovrTransform");
|
||||
|
||||
mat4_multiply(mat4_set(matrix, view), model);
|
||||
|
||||
if (uniformId > -1) {
|
||||
lovrShaderSendFloatMat4(shader, uniformId, matrix);
|
||||
case UNIFORM_INT:
|
||||
switch (uniform->components) {
|
||||
case 1: glUniform1iv(uniform->location, count, data); break;
|
||||
case 2: glUniform2iv(uniform->location, count, data); break;
|
||||
case 3: glUniform3iv(uniform->location, count, data); break;
|
||||
case 4: glUniform4iv(uniform->location, count, data); break;
|
||||
}
|
||||
break;
|
||||
|
||||
if (mat4_invert(matrix)) {
|
||||
mat4_transpose(matrix);
|
||||
} else {
|
||||
mat4_identity(matrix);
|
||||
case UNIFORM_MATRIX:
|
||||
switch (uniform->components) {
|
||||
case 2: glUniformMatrix2fv(uniform->location, count, GL_FALSE, data); break;
|
||||
case 3: glUniformMatrix3fv(uniform->location, count, GL_FALSE, data); break;
|
||||
case 4: glUniformMatrix4fv(uniform->location, count, GL_FALSE, data); break;
|
||||
}
|
||||
break;
|
||||
|
||||
float normalMatrix[9] = {
|
||||
matrix[0], matrix[1], matrix[2],
|
||||
matrix[4], matrix[5], matrix[6],
|
||||
matrix[8], matrix[9], matrix[10]
|
||||
};
|
||||
|
||||
uniformId = lovrShaderGetUniformId(shader, "lovrNormalMatrix");
|
||||
if (uniformId > -1) {
|
||||
lovrShaderSendFloatMat3(shader, uniformId, normalMatrix);
|
||||
case UNIFORM_SAMPLER:
|
||||
for (int i = 0; i < count; i++) {
|
||||
TextureType type = uniform->glType == GL_SAMPLER_2D ? TEXTURE_2D : TEXTURE_CUBE;
|
||||
lovrGraphicsBindTexture(uniform->value.textures[i], type, uniform->baseTextureSlot + i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dirtyProjection) {
|
||||
int uniformId = lovrShaderGetUniformId(shader, "lovrProjection");
|
||||
lovrShaderSendFloatMat4(shader, uniformId, projection);
|
||||
memcpy(shader->projection, projection, 16 * sizeof(float));
|
||||
}
|
||||
|
||||
if (dirtyColor) {
|
||||
int uniformId = lovrShaderGetUniformId(shader, "lovrColor");
|
||||
float c[4] = { color.r / 255., color.g / 255., color.b / 255., color.a / 255. };
|
||||
lovrShaderSendFloatVec4(shader, uniformId, 1, c);
|
||||
shader->color = color;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,51 +305,39 @@ int lovrShaderGetAttributeId(Shader* shader, const char* name) {
|
|||
return glGetAttribLocation(shader->id, name);
|
||||
}
|
||||
|
||||
int lovrShaderGetUniformId(Shader* shader, const char* name) {
|
||||
Uniform* uniform = map_get(&shader->uniforms, name);
|
||||
return uniform ? uniform->location : -1;
|
||||
Uniform* lovrShaderGetUniform(Shader* shader, const char* name) {
|
||||
return map_get(&shader->uniforms, name);
|
||||
}
|
||||
|
||||
int lovrShaderGetUniformType(Shader* shader, const char* name, GLenum* type, int* count) {
|
||||
static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int count, size_t size, const char* debug) {
|
||||
Uniform* uniform = map_get(&shader->uniforms, name);
|
||||
|
||||
if (!uniform) {
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
*type = uniform->type;
|
||||
*count = uniform->count;
|
||||
return 0;
|
||||
lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, uniform->name);
|
||||
lovrAssert(count * size == uniform->size, "Expected %d %ss for uniform %s, got %d", uniform->count, debug, uniform->name, count);
|
||||
|
||||
if (!uniform->dirty && !memcmp(uniform->value.data, data, count * size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(uniform->value.data, data, count * size);
|
||||
uniform->dirty = 1;
|
||||
}
|
||||
|
||||
void lovrShaderSendInt(Shader* shader, int id, int value) {
|
||||
glUniform1i(id, value);
|
||||
void lovrShaderSetFloat(Shader* shader, const char* name, float* data, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, data, count, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSendFloat(Shader* shader, int id, float value) {
|
||||
glUniform1f(id, value);
|
||||
void lovrShaderSetInt(Shader* shader, const char* name, int* data, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_INT, data, count, sizeof(int), "int");
|
||||
}
|
||||
|
||||
void lovrShaderSendFloatVec2(Shader* shader, int id, int count, float* vector) {
|
||||
glUniform2fv(id, count, vector);
|
||||
void lovrShaderSetMatrix(Shader* shader, const char* name, float* data, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_MATRIX, data, count, sizeof(float), "float");
|
||||
}
|
||||
|
||||
void lovrShaderSendFloatVec3(Shader* shader, int id, int count, float* vector) {
|
||||
glUniform3fv(id, count, vector);
|
||||
}
|
||||
|
||||
void lovrShaderSendFloatVec4(Shader* shader, int id, int count, float* vector) {
|
||||
glUniform4fv(id, count, vector);
|
||||
}
|
||||
|
||||
void lovrShaderSendFloatMat2(Shader* shader, int id, float* matrix) {
|
||||
glUniformMatrix2fv(id, 1, GL_FALSE, matrix);
|
||||
}
|
||||
|
||||
void lovrShaderSendFloatMat3(Shader* shader, int id, float* matrix) {
|
||||
glUniformMatrix3fv(id, 1, GL_FALSE, matrix);
|
||||
}
|
||||
|
||||
void lovrShaderSendFloatMat4(Shader* shader, int id, float* matrix) {
|
||||
glUniformMatrix4fv(id, 1, GL_FALSE, matrix);
|
||||
void lovrShaderSetTexture(Shader* shader, const char* name, Texture** data, int count) {
|
||||
lovrShaderSetUniform(shader, name, UNIFORM_SAMPLER, data, count, sizeof(Texture*), "texture");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "graphics/texture.h"
|
||||
#include "math/math.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "lib/glfw.h"
|
||||
|
@ -10,6 +11,20 @@
|
|||
#define LOVR_SHADER_TEX_COORD 2
|
||||
#define LOVR_MAX_UNIFORM_LENGTH 256
|
||||
|
||||
typedef enum {
|
||||
UNIFORM_FLOAT,
|
||||
UNIFORM_MATRIX,
|
||||
UNIFORM_INT,
|
||||
UNIFORM_SAMPLER
|
||||
} UniformType;
|
||||
|
||||
typedef union {
|
||||
void* data;
|
||||
int* ints;
|
||||
float* floats;
|
||||
Texture** textures;
|
||||
} UniformValue;
|
||||
|
||||
typedef enum {
|
||||
SHADER_DEFAULT,
|
||||
SHADER_SKYBOX,
|
||||
|
@ -19,10 +34,16 @@ typedef enum {
|
|||
|
||||
typedef struct {
|
||||
GLchar name[LOVR_MAX_UNIFORM_LENGTH];
|
||||
GLenum glType;
|
||||
int index;
|
||||
int location;
|
||||
GLenum type;
|
||||
int count;
|
||||
int components;
|
||||
size_t size;
|
||||
UniformType type;
|
||||
UniformValue value;
|
||||
int baseTextureSlot;
|
||||
int dirty;
|
||||
} Uniform;
|
||||
|
||||
typedef map_t(Uniform) map_uniform_t;
|
||||
|
@ -40,15 +61,10 @@ typedef struct {
|
|||
Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource);
|
||||
Shader* lovrShaderCreateDefault(DefaultShader type);
|
||||
void lovrShaderDestroy(const Ref* ref);
|
||||
void lovrShaderBind(Shader* shader, mat4 model, mat4 view, mat4 projection, Color color, int force);
|
||||
void lovrShaderBind(Shader* shader);
|
||||
int lovrShaderGetAttributeId(Shader* shader, const char* name);
|
||||
int lovrShaderGetUniformId(Shader* shader, const char* name);
|
||||
int lovrShaderGetUniformType(Shader* shader, const char* name, GLenum* type, int* count);
|
||||
void lovrShaderSendInt(Shader* shader, int id, int value);
|
||||
void lovrShaderSendFloat(Shader* shader, int id, float value);
|
||||
void lovrShaderSendFloatVec2(Shader* shader, int id, int count, float* vector);
|
||||
void lovrShaderSendFloatVec3(Shader* shader, int id, int count,float* vector);
|
||||
void lovrShaderSendFloatVec4(Shader* shader, int id, int count, float* vector);
|
||||
void lovrShaderSendFloatMat2(Shader* shader, int id, float* matrix);
|
||||
void lovrShaderSendFloatMat3(Shader* shader, int id, float* matrix);
|
||||
void lovrShaderSendFloatMat4(Shader* shader, int id, float* matrix);
|
||||
Uniform* lovrShaderGetUniform(Shader* shader, const char* name);
|
||||
void lovrShaderSetFloat(Shader* shader, const char* name, float* data, int count);
|
||||
void lovrShaderSetInt(Shader* shader, const char* name, int* data, int count);
|
||||
void lovrShaderSetMatrix(Shader* shader, const char* name, float* data, int count);
|
||||
void lovrShaderSetTexture(Shader* shader, const char* name, Texture** data, int count);
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#include "graphics/shaders.h"
|
||||
|
||||
const char* lovrShaderColorUniforms[] = {
|
||||
"lovrDiffuseColor"
|
||||
};
|
||||
|
||||
const char* lovrShaderTextureUniforms[] = {
|
||||
"lovrDiffuseTexture",
|
||||
"lovrEnvironmentTexture"
|
||||
};
|
||||
|
||||
const char* lovrShaderVertexPrefix = ""
|
||||
#ifdef EMSCRIPTEN
|
||||
"#version 300 es \n"
|
||||
"precision mediump float; \n"
|
||||
#else
|
||||
"#version 150 \n"
|
||||
#endif
|
||||
"in vec3 lovrPosition; \n"
|
||||
"in vec3 lovrNormal; \n"
|
||||
"in vec2 lovrTexCoord; \n"
|
||||
"out vec2 texCoord; \n"
|
||||
"uniform mat4 lovrModel; \n"
|
||||
"uniform mat4 lovrView; \n"
|
||||
"uniform mat4 lovrProjection; \n"
|
||||
"uniform mat4 lovrTransform; \n"
|
||||
"uniform mat3 lovrNormalMatrix; \n";
|
||||
|
||||
const char* lovrShaderFragmentPrefix = ""
|
||||
#ifdef EMSCRIPTEN
|
||||
"#version 300 es \n"
|
||||
"precision mediump float; \n"
|
||||
#else
|
||||
"#version 150 \n"
|
||||
"in vec4 gl_FragCoord; \n"
|
||||
#endif
|
||||
"in vec2 texCoord; \n"
|
||||
"out vec4 lovrFragColor; \n"
|
||||
"uniform vec4 lovrColor; \n"
|
||||
"uniform vec4 lovrDiffuseColor; \n"
|
||||
"uniform sampler2D lovrDiffuseTexture; \n"
|
||||
"uniform samplerCube lovrEnvironmentTexture; \n";
|
||||
|
||||
const char* lovrShaderVertexSuffix = ""
|
||||
"void main() { \n"
|
||||
" texCoord = lovrTexCoord; \n"
|
||||
" gl_Position = position(lovrProjection, lovrTransform, vec4(lovrPosition, 1.0)); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrShaderFragmentSuffix = ""
|
||||
"void main() { \n"
|
||||
" lovrFragColor = color(lovrColor, lovrDiffuseTexture, texCoord); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrDefaultVertexShader = ""
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" return projection * transform * vertex; \n"
|
||||
"}";
|
||||
|
||||
const char* lovrDefaultFragmentShader = ""
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" return graphicsColor * lovrDiffuseColor * texture(image, uv); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrSkyboxVertexShader = ""
|
||||
"out vec3 texturePosition; \n"
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" texturePosition = vertex.xyz; \n"
|
||||
" return projection * transform * vertex; \n"
|
||||
"}";
|
||||
|
||||
const char* lovrSkyboxFragmentShader = ""
|
||||
"in vec3 texturePosition; \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" return graphicsColor * texture(lovrEnvironmentTexture, texturePosition); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrFontFragmentShader = ""
|
||||
"float median(float r, float g, float b) { \n"
|
||||
" return max(min(r, g), min(max(r, g), b)); \n"
|
||||
"} \n"
|
||||
"vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) { \n"
|
||||
" vec3 col = texture(image, uv).rgb; \n"
|
||||
" float sdf = median(col.r, col.g, col.b); \n"
|
||||
" float w = fwidth(sdf); \n"
|
||||
" float alpha = smoothstep(.5 - w, .5 + w, sdf); \n"
|
||||
" return vec4(graphicsColor.rgb, graphicsColor.a * alpha); \n"
|
||||
"}";
|
||||
|
||||
const char* lovrNoopVertexShader = ""
|
||||
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
|
||||
" return vertex; \n"
|
||||
"}";
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
extern const char* lovrShaderColorUniforms[];
|
||||
extern const char* lovrShaderTextureUniforms[];
|
||||
extern const char* lovrShaderVertexPrefix;
|
||||
extern const char* lovrShaderVertexSuffix;
|
||||
extern const char* lovrShaderFragmentPrefix;
|
||||
extern const char* lovrShaderFragmentSuffix;
|
||||
extern const char* lovrDefaultVertexShader;
|
||||
extern const char* lovrDefaultFragmentShader;
|
||||
extern const char* lovrSkyboxVertexShader;
|
||||
extern const char* lovrSkyboxFragmentShader;
|
||||
extern const char* lovrFontFragmentShader;
|
||||
extern const char* lovrNoopVertexShader;
|
|
@ -1,56 +0,0 @@
|
|||
#include "graphics/skybox.h"
|
||||
#include "lib/stb/stb_image.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
Skybox* lovrSkyboxCreate(Blob** blobs, SkyboxType type) {
|
||||
Skybox* skybox = lovrAlloc(sizeof(Skybox), lovrSkyboxDestroy);
|
||||
if (!skybox) return NULL;
|
||||
|
||||
skybox->type = type;
|
||||
|
||||
GLenum binding;
|
||||
int count;
|
||||
|
||||
if (type == SKYBOX_CUBE) {
|
||||
binding = GL_TEXTURE_CUBE_MAP;
|
||||
count = 6;
|
||||
} else {
|
||||
binding = GL_TEXTURE_2D;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
glGenTextures(1, &skybox->texture);
|
||||
glBindTexture(binding, skybox->texture);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int width, height, channels;
|
||||
stbi_set_flip_vertically_on_load(0);
|
||||
unsigned char* image = stbi_load_from_memory(blobs[i]->data, blobs[i]->size, &width, &height, &channels, 3);
|
||||
lovrAssert(image, "Could not load skybox image %d", i);
|
||||
|
||||
if (type == SKYBOX_CUBE) {
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||
}
|
||||
|
||||
free(image);
|
||||
}
|
||||
|
||||
glTexParameteri(binding, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(binding, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(binding, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(binding, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (type == SKYBOX_CUBE) {
|
||||
glTexParameteri(binding, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
return skybox;
|
||||
}
|
||||
|
||||
void lovrSkyboxDestroy(const Ref* ref) {
|
||||
Skybox* skybox = containerof(ref, Skybox);
|
||||
glDeleteTextures(1, &skybox->texture);
|
||||
free(skybox);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#include "filesystem/blob.h"
|
||||
#include "lib/glad/glad.h"
|
||||
#include "util.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
SKYBOX_CUBE,
|
||||
SKYBOX_PANORAMA
|
||||
} SkyboxType;
|
||||
|
||||
typedef struct {
|
||||
Ref ref;
|
||||
SkyboxType type;
|
||||
GLuint texture;
|
||||
} Skybox;
|
||||
|
||||
Skybox* lovrSkyboxCreate(Blob** blobs, SkyboxType type);
|
||||
void lovrSkyboxDestroy(const Ref* ref);
|
|
@ -6,9 +6,9 @@
|
|||
#include <stdio.h>
|
||||
|
||||
static void lovrTextureCreateStorage(Texture* texture) {
|
||||
TextureData* textureData = texture->textureData;
|
||||
TextureData* textureData = texture->slices[0];
|
||||
|
||||
if (textureData->format.compressed || !textureData->mipmaps.generated) {
|
||||
if (textureData->format.compressed || !textureData->mipmaps.generated || texture->type == TEXTURE_CUBE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -32,30 +32,50 @@ static void lovrTextureCreateStorage(Texture* texture) {
|
|||
#endif
|
||||
}
|
||||
|
||||
Texture* lovrTextureCreate(TextureData* textureData) {
|
||||
static void validateSlices(TextureType type, TextureData* slices[6], int sliceCount) {
|
||||
if (type == TEXTURE_CUBE) {
|
||||
lovrAssert(sliceCount == 6, "Cube textures must have 6 images");
|
||||
int width = slices[0]->width;
|
||||
int height = slices[0]->height;
|
||||
lovrAssert(width == height, "Cube textures must be square");
|
||||
for (int i = 1; i < sliceCount; i++) {
|
||||
int hasSameDimensions = slices[i]->width == width && slices[i]->height == height;
|
||||
lovrAssert(hasSameDimensions, "All textures in a cube texture must have the same dimensions");
|
||||
}
|
||||
} else if (type == TEXTURE_2D) {
|
||||
lovrAssert(sliceCount == 1, "2D textures can only contain a single image");
|
||||
} else {
|
||||
lovrThrow("Unknown texture type");
|
||||
}
|
||||
}
|
||||
|
||||
Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCount) {
|
||||
Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy);
|
||||
if (!texture) return NULL;
|
||||
|
||||
texture->type = type;
|
||||
validateSlices(type, slices, sliceCount);
|
||||
texture->sliceCount = sliceCount;
|
||||
memcpy(texture->slices, slices, sliceCount * sizeof(TextureData*));
|
||||
texture->framebuffer = 0;
|
||||
texture->depthBuffer = 0;
|
||||
texture->textureData = textureData;
|
||||
glGenTextures(1, &texture->id);
|
||||
lovrGraphicsBindTexture(texture);
|
||||
lovrGraphicsBindTexture(texture, type, 0);
|
||||
lovrTextureCreateStorage(texture);
|
||||
lovrTextureRefresh(texture);
|
||||
lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter());
|
||||
|
||||
lovrTextureSetWrap(texture, WRAP_REPEAT, WRAP_REPEAT);
|
||||
WrapMode wrapMode = (type == TEXTURE_CUBE) ? WRAP_CLAMP : WRAP_REPEAT;
|
||||
lovrTextureSetWrap(texture, (TextureWrap) { .s = wrapMode, .t = wrapMode, .r = wrapMode });
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa) {
|
||||
Texture* texture = lovrTextureCreate(textureData);
|
||||
Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1);
|
||||
if (!texture) return NULL;
|
||||
|
||||
int width = texture->textureData->width;
|
||||
int height = texture->textureData->height;
|
||||
int width = texture->width;
|
||||
int height = texture->height;
|
||||
texture->projection = projection;
|
||||
texture->msaa = msaa;
|
||||
|
||||
|
@ -102,7 +122,9 @@ Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProje
|
|||
|
||||
void lovrTextureDestroy(const Ref* ref) {
|
||||
Texture* texture = containerof(ref, Texture);
|
||||
lovrTextureDataDestroy(texture->textureData);
|
||||
for (int i = 0; i < texture->sliceCount; i++) {
|
||||
lovrTextureDataDestroy(texture->slices[i]);
|
||||
}
|
||||
if (texture->framebuffer) {
|
||||
glDeleteFramebuffers(1, &texture->framebuffer);
|
||||
}
|
||||
|
@ -112,23 +134,19 @@ void lovrTextureDestroy(const Ref* ref) {
|
|||
|
||||
void lovrTextureBindFramebuffer(Texture* texture) {
|
||||
lovrAssert(texture->framebuffer, "Texture cannot be used as a canvas");
|
||||
|
||||
int w = texture->textureData->width;
|
||||
int h = texture->textureData->height;
|
||||
|
||||
lovrGraphicsBindFramebuffer(texture->framebuffer);
|
||||
lovrGraphicsSetViewport(0, 0, w, h);
|
||||
lovrGraphicsSetViewport(0, 0, texture->width, texture->height);
|
||||
|
||||
if (texture->projection == PROJECTION_ORTHOGRAPHIC) {
|
||||
float projection[16];
|
||||
mat4_orthographic(projection, 0, w, 0, h, -1, 1);
|
||||
mat4_orthographic(projection, 0, texture->width, 0, texture->height, -1, 1);
|
||||
lovrGraphicsSetProjection(projection);
|
||||
} else if (texture->projection == PROJECTION_PERSPECTIVE) {
|
||||
mat4 projection = lovrGraphicsGetProjection();
|
||||
float b = projection[5];
|
||||
float c = projection[10];
|
||||
float d = projection[14];
|
||||
float aspect = (float) w / h;
|
||||
float aspect = (float) texture->width / texture->height;
|
||||
float k = (c - 1.f) / (c + 1.f);
|
||||
float near = (d * (1.f - k)) / (2.f * k);
|
||||
float far = k * near;
|
||||
|
@ -145,43 +163,42 @@ void lovrTextureResolveMSAA(Texture* texture) {
|
|||
return;
|
||||
}
|
||||
|
||||
int w = texture->textureData->width;
|
||||
int h = texture->textureData->height;
|
||||
|
||||
int width = texture->width;
|
||||
int height = texture->height;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, texture->framebuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, texture->resolveFramebuffer);
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void lovrTextureRefresh(Texture* texture) {
|
||||
TextureData* textureData = texture->textureData;
|
||||
lovrGraphicsBindTexture(texture, texture->type, 0);
|
||||
|
||||
validateSlices(texture->type, texture->slices, texture->sliceCount);
|
||||
texture->width = texture->slices[0]->width;
|
||||
texture->height = texture->slices[0]->height;
|
||||
|
||||
for (int i = 0; i < texture->sliceCount; i++) {
|
||||
TextureData* textureData = texture->slices[i];
|
||||
GLenum glInternalFormat = textureData->format.glInternalFormat;
|
||||
GLenum glFormat = textureData->format.glFormat;
|
||||
lovrGraphicsBindTexture(texture);
|
||||
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : GL_TEXTURE_2D;
|
||||
|
||||
if (textureData->format.compressed) {
|
||||
Mipmap m; int i;
|
||||
vec_foreach(&textureData->mipmaps.list, m, i) {
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
|
||||
glCompressedTexImage2D(binding, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
|
||||
}
|
||||
} else {
|
||||
int w = textureData->width;
|
||||
int h = textureData->height;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data);
|
||||
if (textureData->mipmaps.generated) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glGenerateMipmap(GL_TEXTURE_2D); // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int lovrTextureGetHeight(Texture* texture) {
|
||||
return texture->textureData->height;
|
||||
}
|
||||
|
||||
int lovrTextureGetWidth(Texture* texture) {
|
||||
return texture->textureData->width;
|
||||
}
|
||||
|
||||
TextureFilter lovrTextureGetFilter(Texture* texture) {
|
||||
|
@ -189,9 +206,9 @@ TextureFilter lovrTextureGetFilter(Texture* texture) {
|
|||
}
|
||||
|
||||
void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
||||
int hasMipmaps = texture->textureData->format.compressed || texture->textureData->mipmaps.generated;
|
||||
int hasMipmaps = texture->slices[0]->format.compressed || texture->slices[0]->mipmaps.generated;
|
||||
float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
|
||||
lovrGraphicsBindTexture(texture);
|
||||
lovrGraphicsBindTexture(texture, texture->type, 0);
|
||||
texture->filter = filter;
|
||||
|
||||
switch (filter.mode) {
|
||||
|
@ -225,15 +242,16 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
|
||||
}
|
||||
|
||||
void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertical) {
|
||||
*horizontal = texture->wrapHorizontal;
|
||||
*vertical = texture->wrapVertical;
|
||||
TextureWrap lovrTextureGetWrap(Texture* texture) {
|
||||
return texture->wrap;
|
||||
}
|
||||
|
||||
void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical) {
|
||||
texture->wrapHorizontal = horizontal;
|
||||
texture->wrapVertical = vertical;
|
||||
lovrGraphicsBindTexture(texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horizontal);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vertical);
|
||||
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
|
||||
texture->wrap = wrap;
|
||||
lovrGraphicsBindTexture(texture, texture->type, 0);
|
||||
glTexParameteri(texture->type, GL_TEXTURE_WRAP_S, wrap.s);
|
||||
glTexParameteri(texture->type, GL_TEXTURE_WRAP_T, wrap.t);
|
||||
if (texture->type == TEXTURE_CUBE) {
|
||||
glTexParameteri(texture->type, GL_TEXTURE_WRAP_R, wrap.r);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
TEXTURE_2D = GL_TEXTURE_2D,
|
||||
TEXTURE_CUBE = GL_TEXTURE_CUBE_MAP
|
||||
} TextureType;
|
||||
|
||||
typedef enum {
|
||||
FILTER_NEAREST,
|
||||
FILTER_BILINEAR,
|
||||
|
@ -22,6 +27,12 @@ typedef enum {
|
|||
WRAP_MIRRORED_REPEAT = GL_MIRRORED_REPEAT
|
||||
} WrapMode;
|
||||
|
||||
typedef struct {
|
||||
WrapMode s;
|
||||
WrapMode t;
|
||||
WrapMode r;
|
||||
} TextureWrap;
|
||||
|
||||
typedef enum {
|
||||
PROJECTION_ORTHOGRAPHIC,
|
||||
PROJECTION_PERSPECTIVE
|
||||
|
@ -29,7 +40,11 @@ typedef enum {
|
|||
|
||||
typedef struct {
|
||||
Ref ref;
|
||||
TextureData* textureData;
|
||||
TextureType type;
|
||||
TextureData* slices[6];
|
||||
int sliceCount;
|
||||
int width;
|
||||
int height;
|
||||
GLuint id;
|
||||
GLuint msaaId;
|
||||
GLuint framebuffer;
|
||||
|
@ -37,22 +52,19 @@ typedef struct {
|
|||
GLuint depthBuffer;
|
||||
TextureProjection projection;
|
||||
TextureFilter filter;
|
||||
WrapMode wrapHorizontal;
|
||||
WrapMode wrapVertical;
|
||||
TextureWrap wrap;
|
||||
int msaa;
|
||||
} Texture;
|
||||
|
||||
GLenum lovrTextureGetGLFormat(TextureFormat format);
|
||||
|
||||
Texture* lovrTextureCreate(TextureData* textureData);
|
||||
Texture* lovrTextureCreate(TextureType type, TextureData* data[6], int count);
|
||||
Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa);
|
||||
void lovrTextureDestroy(const Ref* ref);
|
||||
void lovrTextureBindFramebuffer(Texture* texture);
|
||||
void lovrTextureResolveMSAA(Texture* texture);
|
||||
void lovrTextureRefresh(Texture* texture);
|
||||
int lovrTextureGetHeight(Texture* texture);
|
||||
int lovrTextureGetWidth(Texture* texture);
|
||||
TextureFilter lovrTextureGetFilter(Texture* texture);
|
||||
void lovrTextureSetFilter(Texture* texture, TextureFilter filter);
|
||||
void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertical);
|
||||
void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical);
|
||||
TextureWrap lovrTextureGetWrap(Texture* texture);
|
||||
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap);
|
||||
|
|
|
@ -383,10 +383,6 @@ static ModelData* fakeControllerNewModelData(Controller* controller) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static TextureData* fakeControllerNewTextureData(Controller* controller) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void fakeRenderTo(headsetRenderCallback callback, void* userdata) {
|
||||
// float head[16], transform[16], projection[16];
|
||||
|
@ -491,7 +487,6 @@ HeadsetImpl lovrHeadsetFakeDriver = {
|
|||
fakeControllerIsTouched,
|
||||
fakeControllerVibrate,
|
||||
fakeControllerNewModelData,
|
||||
fakeControllerNewTextureData,
|
||||
fakeRenderTo,
|
||||
fakeUpdate,
|
||||
};
|
||||
|
|
|
@ -229,13 +229,6 @@ ModelData* lovrHeadsetControllerNewModelData(Controller* controller)
|
|||
}
|
||||
}
|
||||
|
||||
TextureData* lovrHeadsetControllerNewTextureData(Controller* controller) {
|
||||
if( headset && controller) {
|
||||
return headset->controllerNewTextureData(controller);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) {
|
||||
if (headset) {
|
||||
|
|
|
@ -90,7 +90,6 @@ typedef struct {
|
|||
int (*controllerIsTouched)(Controller* controller, ControllerButton button);
|
||||
void (*controllerVibrate)(Controller* controller, float duration, float power);
|
||||
ModelData* (*controllerNewModelData)(Controller* controller);
|
||||
TextureData* (*controllerNewTextureData)(Controller* controller);
|
||||
void (*renderTo)(headsetRenderCallback callback, void* userdata);
|
||||
void (*update)(float dt);
|
||||
} HeadsetImpl;
|
||||
|
@ -130,7 +129,6 @@ int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button)
|
|||
int lovrHeadsetControllerIsTouched(Controller* controller, ControllerButton button);
|
||||
void lovrHeadsetControllerVibrate(Controller* controller, float duration, float power);
|
||||
ModelData* lovrHeadsetControllerNewModelData(Controller* controller);
|
||||
TextureData* lovrHeadsetControllerNewTextureData(Controller* controller);
|
||||
void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata);
|
||||
void lovrHeadsetUpdate(float dt);
|
||||
|
||||
|
|
|
@ -656,77 +656,64 @@ static ModelData* openvrControllerNewModelData(Controller* controller) {
|
|||
}
|
||||
}
|
||||
|
||||
RenderModel_t* vrModel = state.deviceModels[id];
|
||||
|
||||
ModelData* modelData = malloc(sizeof(ModelData));
|
||||
if (!modelData) return NULL;
|
||||
|
||||
ModelMesh* mesh = malloc(sizeof(ModelMesh));
|
||||
vec_init(&modelData->meshes);
|
||||
vec_push(&modelData->meshes, mesh);
|
||||
|
||||
vec_init(&mesh->faces);
|
||||
for (uint32_t i = 0; i < vrModel->unTriangleCount; i++) {
|
||||
ModelFace face;
|
||||
face.indices[0] = vrModel->rIndexData[3 * i + 0];
|
||||
face.indices[1] = vrModel->rIndexData[3 * i + 1];
|
||||
face.indices[2] = vrModel->rIndexData[3 * i + 2];
|
||||
vec_push(&mesh->faces, face);
|
||||
}
|
||||
|
||||
vec_init(&mesh->vertices);
|
||||
vec_init(&mesh->normals);
|
||||
vec_init(&mesh->texCoords);
|
||||
for (size_t i = 0; i < vrModel->unVertexCount; i++) {
|
||||
float* position = vrModel->rVertexData[i].vPosition.v;
|
||||
float* normal = vrModel->rVertexData[i].vNormal.v;
|
||||
float* texCoords = vrModel->rVertexData[i].rfTextureCoord;
|
||||
ModelVertex v;
|
||||
|
||||
v.x = position[0];
|
||||
v.y = position[1];
|
||||
v.z = position[2];
|
||||
vec_push(&mesh->vertices, v);
|
||||
|
||||
v.x = normal[0];
|
||||
v.y = normal[1];
|
||||
v.z = normal[2];
|
||||
vec_push(&mesh->normals, v);
|
||||
|
||||
v.x = texCoords[0];
|
||||
v.y = texCoords[1];
|
||||
v.z = 0.f;
|
||||
vec_push(&mesh->texCoords, v);
|
||||
}
|
||||
|
||||
ModelNode* root = malloc(sizeof(ModelNode));
|
||||
vec_init(&root->meshes);
|
||||
vec_push(&root->meshes, 0);
|
||||
vec_init(&root->children);
|
||||
mat4_identity(root->transform);
|
||||
|
||||
modelData->root = root;
|
||||
modelData->hasNormals = 1;
|
||||
modelData->hasTexCoords = 1;
|
||||
|
||||
return modelData;
|
||||
}
|
||||
|
||||
static TextureData* openvrControllerNewTextureData(Controller* controller) {
|
||||
if (!state.isInitialized || !controller) return NULL;
|
||||
|
||||
int id = controller->id;
|
||||
|
||||
if (!state.deviceModels[id]) {
|
||||
openvrControllerNewModelData(controller);
|
||||
}
|
||||
|
||||
// Load texture
|
||||
if (!state.deviceTextures[id]) {
|
||||
while (state.renderModels->LoadTexture_Async(state.deviceModels[id]->diffuseTextureId, &state.deviceTextures[id]) == EVRRenderModelError_VRRenderModelError_Loading) {
|
||||
lovrSleep(.001);
|
||||
}
|
||||
}
|
||||
|
||||
RenderModel_t* vrModel = state.deviceModels[id];
|
||||
|
||||
ModelData* modelData = malloc(sizeof(ModelData));
|
||||
if (!modelData) return NULL;
|
||||
|
||||
modelData->indexCount = vrModel->unTriangleCount;
|
||||
modelData->indices = malloc(modelData->indexCount * sizeof(unsigned int));
|
||||
memcpy(modelData->indices, vrModel->rIndexData, modelData->indexCount * sizeof(unsigned int));
|
||||
|
||||
modelData->vertexCount = vrModel->unVertexCount;
|
||||
modelData->vertexSize = 8;
|
||||
modelData->vertices = malloc(modelData->vertexCount * modelData->vertexSize * sizeof(float));
|
||||
|
||||
int vertex = 0;
|
||||
for (size_t i = 0; i < vrModel->unVertexCount; i++) {
|
||||
float* position = vrModel->rVertexData[i].vPosition.v;
|
||||
float* normal = vrModel->rVertexData[i].vNormal.v;
|
||||
float* texCoords = vrModel->rVertexData[i].rfTextureCoord;
|
||||
|
||||
modelData->vertices[vertex++] = position[0];
|
||||
modelData->vertices[vertex++] = position[1];
|
||||
modelData->vertices[vertex++] = position[2];
|
||||
|
||||
modelData->vertices[vertex++] = normal[0];
|
||||
modelData->vertices[vertex++] = normal[1];
|
||||
modelData->vertices[vertex++] = normal[2];
|
||||
|
||||
modelData->vertices[vertex++] = texCoords[0];
|
||||
modelData->vertices[vertex++] = texCoords[1];
|
||||
}
|
||||
|
||||
modelData->nodeCount = 1;
|
||||
modelData->primitiveCount = 1;
|
||||
modelData->materialCount = 1;
|
||||
|
||||
modelData->nodes = malloc(1 * sizeof(ModelNode));
|
||||
modelData->primitives = malloc(1 * sizeof(ModelPrimitive));
|
||||
modelData->materials = malloc(1 * sizeof(MaterialData));
|
||||
|
||||
// Geometry
|
||||
ModelNode* root = &modelData->nodes[0];
|
||||
root->parent = -1;
|
||||
mat4_identity(root->transform);
|
||||
vec_init(&root->children);
|
||||
vec_init(&root->primitives);
|
||||
vec_push(&root->primitives, 0);
|
||||
modelData->primitives[0].material = 0;
|
||||
modelData->primitives[0].drawStart = 0;
|
||||
modelData->primitives[0].drawCount = modelData->vertexCount;
|
||||
|
||||
// Material
|
||||
RenderModel_TextureMap_t* vrTexture = state.deviceTextures[id];
|
||||
|
||||
TextureData* textureData = malloc(sizeof(TextureData));
|
||||
|
@ -743,7 +730,14 @@ static TextureData* openvrControllerNewTextureData(Controller* controller) {
|
|||
textureData->data = memcpy(malloc(size), vrTexture->rubTextureMapData, size);;
|
||||
textureData->mipmaps.generated = 1;
|
||||
textureData->blob = NULL;
|
||||
return textureData;
|
||||
|
||||
modelData->materials[0] = *lovrMaterialDataCreateEmpty();
|
||||
modelData->materials[0].textures[TEXTURE_DIFFUSE] = textureData;
|
||||
|
||||
modelData->hasNormals = 1;
|
||||
modelData->hasUVs = 1;
|
||||
|
||||
return modelData;
|
||||
}
|
||||
|
||||
static void openvrRenderTo(headsetRenderCallback callback, void* userdata) {
|
||||
|
@ -758,7 +752,7 @@ static void openvrRenderTo(headsetRenderCallback callback, void* userdata) {
|
|||
float head[16], transform[16], projection[16];
|
||||
float (*matrix)[4];
|
||||
|
||||
lovrGraphicsPushCanvas();
|
||||
lovrGraphicsPushView();
|
||||
state.isRendering = 1;
|
||||
state.compositor->WaitGetPoses(state.renderPoses, 16, NULL, 0);
|
||||
|
||||
|
@ -789,7 +783,8 @@ static void openvrRenderTo(headsetRenderCallback callback, void* userdata) {
|
|||
lovrTextureResolveMSAA(state.texture);
|
||||
|
||||
// OpenVR changes the OpenGL texture binding, so we reset it after rendering
|
||||
Texture* oldTexture = lovrGraphicsGetTexture();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
Texture* oldTexture = lovrGraphicsGetTexture(0);
|
||||
|
||||
// Submit
|
||||
uintptr_t texture = (uintptr_t) state.texture->id;
|
||||
|
@ -803,7 +798,7 @@ static void openvrRenderTo(headsetRenderCallback callback, void* userdata) {
|
|||
}
|
||||
|
||||
state.isRendering = 0;
|
||||
lovrGraphicsPopCanvas();
|
||||
lovrGraphicsPopView();
|
||||
|
||||
if (state.isMirrored) {
|
||||
Color oldColor = lovrGraphicsGetColor();
|
||||
|
@ -861,7 +856,6 @@ HeadsetImpl lovrHeadsetOpenVRDriver = {
|
|||
openvrControllerIsTouched,
|
||||
openvrControllerVibrate,
|
||||
openvrControllerNewModelData,
|
||||
openvrControllerNewTextureData,
|
||||
openvrRenderTo,
|
||||
openvrUpdate,
|
||||
};
|
||||
|
|
|
@ -249,10 +249,6 @@ static ModelData* webvrControllerNewModelData(Controller* controller) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static TextureData* webvrControllerNewTextureData(Controller* controller) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void webvrRenderTo(headsetRenderCallback callback, void* userdata) {
|
||||
state.renderCallback = callback;
|
||||
emscripten_vr_set_render_callback(onRequestAnimationFrame, userdata);
|
||||
|
@ -293,7 +289,6 @@ HeadsetImpl lovrHeadsetWebVRDriver = {
|
|||
webvrControllerIsTouched,
|
||||
webvrControllerVibrate,
|
||||
webvrControllerNewModelData,
|
||||
webvrControllerNewTextureData,
|
||||
webvrRenderTo,
|
||||
webvrUpdate,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#include "loaders/material.h"
|
||||
|
||||
MaterialData* lovrMaterialDataCreateEmpty() {
|
||||
MaterialData* materialData = malloc(sizeof(MaterialData));
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_COLORS; i++) {
|
||||
materialData->colors[i] = (Color) { 0xff, 0xff, 0xff, 0xff };
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) {
|
||||
materialData->textures[i] = NULL;
|
||||
}
|
||||
|
||||
return materialData;
|
||||
}
|
||||
|
||||
void lovrMaterialDataDestroy(MaterialData* materialData) {
|
||||
free(materialData);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include "loaders/texture.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
COLOR_DIFFUSE,
|
||||
MAX_MATERIAL_COLORS
|
||||
} MaterialColor;
|
||||
|
||||
typedef enum {
|
||||
TEXTURE_DIFFUSE,
|
||||
TEXTURE_ENVIRONMENT_MAP,
|
||||
MAX_MATERIAL_TEXTURES
|
||||
} MaterialTexture;
|
||||
|
||||
typedef struct {
|
||||
Color colors[MAX_MATERIAL_COLORS];
|
||||
TextureData* textures[MAX_MATERIAL_TEXTURES];
|
||||
} MaterialData;
|
||||
|
||||
MaterialData* lovrMaterialDataCreateEmpty();
|
||||
void lovrMaterialDataDestroy(MaterialData* materialData);
|
|
@ -1,30 +1,171 @@
|
|||
#include "loaders/model.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "filesystem/file.h"
|
||||
#include "math/math.h"
|
||||
#include "math/mat4.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assimp/cfileio.h>
|
||||
#include <assimp/cimport.h>
|
||||
#include <assimp/config.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/matrix4x4.h>
|
||||
#include <assimp/vector3.h>
|
||||
#include <assimp/postprocess.h>
|
||||
|
||||
static void assimpNodeTraversal(ModelNode* node, struct aiNode* assimpNode) {
|
||||
static void normalizePath(const char* path, char* dst, size_t size) {
|
||||
if (path[0] == '/') {
|
||||
strncpy(dst, path, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dst, 0, size);
|
||||
|
||||
while (*path != '\0') {
|
||||
if (*path == '/') {
|
||||
path++;
|
||||
continue;
|
||||
}
|
||||
if (*path == '.') {
|
||||
if (path[1] == '\0' || path[1] == '/') {
|
||||
path++;
|
||||
continue;
|
||||
}
|
||||
if (path[1] == '.' && (path[2] == '\0' || path[2] == '/')) {
|
||||
path += 2;
|
||||
while ((--dst)[-1] != '/');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (*path != '\0' && *path != '/') {
|
||||
*dst++ = *path++;
|
||||
}
|
||||
*dst++ = '/';
|
||||
}
|
||||
|
||||
*--dst = '\0';
|
||||
}
|
||||
|
||||
// Blob IO (to avoid reading data twice)
|
||||
static unsigned long assimpBlobRead(struct aiFile* assimpFile, char* buffer, size_t size, size_t count) {
|
||||
Blob* blob = (Blob*) assimpFile->UserData;
|
||||
char* data = blob->data;
|
||||
size_t bytes = MIN(count * size * sizeof(char), blob->size - blob->seek);
|
||||
memcpy(buffer, data + blob->seek, bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static size_t assimpBlobGetSize(struct aiFile* assimpFile) {
|
||||
Blob* blob = (Blob*) assimpFile->UserData;
|
||||
return blob->size;
|
||||
}
|
||||
|
||||
static aiReturn assimpBlobSeek(struct aiFile* assimpFile, unsigned long position, enum aiOrigin origin) {
|
||||
Blob* blob = (Blob*) assimpFile->UserData;
|
||||
switch (origin) {
|
||||
case aiOrigin_SET: blob->seek = position; break;
|
||||
case aiOrigin_CUR: blob->seek += position; break;
|
||||
case aiOrigin_END: blob->seek = blob->size - position; break;
|
||||
default: return aiReturn_FAILURE;
|
||||
}
|
||||
return blob->seek < blob->size ? aiReturn_SUCCESS : aiReturn_FAILURE;
|
||||
}
|
||||
|
||||
static unsigned long assimpBlobTell(struct aiFile* assimpFile) {
|
||||
Blob* blob = (Blob*) assimpFile->UserData;
|
||||
return blob->seek;
|
||||
}
|
||||
|
||||
// File IO (for reading referenced materials/textures)
|
||||
static unsigned long assimpFileRead(struct aiFile* assimpFile, char* buffer, size_t size, size_t count) {
|
||||
File* file = (File*) assimpFile->UserData;
|
||||
unsigned long bytes = lovrFileRead(file, buffer, size, count);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static size_t assimpFileGetSize(struct aiFile* assimpFile) {
|
||||
File* file = (File*) assimpFile->UserData;
|
||||
return lovrFileGetSize(file);
|
||||
}
|
||||
|
||||
static aiReturn assimpFileSeek(struct aiFile* assimpFile, unsigned long position, enum aiOrigin origin) {
|
||||
File* file = (File*) assimpFile->UserData;
|
||||
return lovrFileSeek(file, position) ? aiReturn_FAILURE : aiReturn_SUCCESS;
|
||||
}
|
||||
|
||||
static unsigned long assimpFileTell(struct aiFile* assimpFile) {
|
||||
File* file = (File*) assimpFile->UserData;
|
||||
return lovrFileTell(file);
|
||||
}
|
||||
|
||||
static struct aiFile* assimpFileOpen(struct aiFileIO* io, const char* path, const char* mode) {
|
||||
struct aiFile* assimpFile = malloc(sizeof(struct aiFile));
|
||||
Blob* blob = (Blob*) io->UserData;
|
||||
if (!strcmp(blob->name, path)) {
|
||||
assimpFile->ReadProc = assimpBlobRead;
|
||||
assimpFile->FileSizeProc = assimpBlobGetSize;
|
||||
assimpFile->SeekProc = assimpBlobSeek;
|
||||
assimpFile->TellProc = assimpBlobTell;
|
||||
assimpFile->UserData = (void*) blob;
|
||||
} else {
|
||||
char normalizedPath[LOVR_PATH_MAX];
|
||||
normalizePath(path, normalizedPath, LOVR_PATH_MAX);
|
||||
|
||||
File* file = lovrFileCreate(path);
|
||||
if (lovrFileOpen(file, OPEN_READ)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assimpFile->ReadProc = assimpFileRead;
|
||||
assimpFile->FileSizeProc = assimpFileGetSize;
|
||||
assimpFile->SeekProc = assimpFileSeek;
|
||||
assimpFile->TellProc = assimpFileTell;
|
||||
assimpFile->UserData = (void*) file;
|
||||
}
|
||||
|
||||
return assimpFile;
|
||||
}
|
||||
|
||||
static void assimpFileClose(struct aiFileIO* io, struct aiFile* assimpFile) {
|
||||
void* blob = io->UserData;
|
||||
if (assimpFile->UserData != blob) {
|
||||
File* file = (File*) assimpFile->UserData;
|
||||
lovrFileClose(file);
|
||||
lovrRelease(&file->ref);
|
||||
}
|
||||
free(assimpFile);
|
||||
}
|
||||
|
||||
static void assimpSumChildren(struct aiNode* assimpNode, int* totalChildren) {
|
||||
(*totalChildren)++;
|
||||
for (unsigned int i = 0; i < assimpNode->mNumChildren; i++) {
|
||||
assimpSumChildren(assimpNode->mChildren[i], totalChildren);
|
||||
}
|
||||
}
|
||||
|
||||
static void assimpNodeTraversal(ModelData* modelData, struct aiNode* assimpNode, int* nodeId) {
|
||||
int currentIndex = *nodeId;
|
||||
ModelNode* node = &modelData->nodes[currentIndex];
|
||||
|
||||
// Transform
|
||||
struct aiMatrix4x4 m = assimpNode->mTransformation;
|
||||
aiTransposeMatrix4(&m);
|
||||
mat4_set(node->transform, (float*) &m);
|
||||
|
||||
// Meshes
|
||||
vec_init(&node->meshes);
|
||||
vec_pusharr(&node->meshes, assimpNode->mMeshes, assimpNode->mNumMeshes);
|
||||
// Primitives
|
||||
vec_init(&node->primitives);
|
||||
vec_pusharr(&node->primitives, assimpNode->mMeshes, assimpNode->mNumMeshes);
|
||||
|
||||
// Children
|
||||
vec_init(&node->children);
|
||||
for (unsigned int n = 0; n < assimpNode->mNumChildren; n++) {
|
||||
ModelNode* child = malloc(sizeof(ModelNode));
|
||||
assimpNodeTraversal(child, assimpNode->mChildren[n]);
|
||||
vec_push(&node->children, child);
|
||||
(*nodeId)++;
|
||||
vec_push(&node->children, *nodeId);
|
||||
ModelNode* child = &modelData->nodes[*nodeId];
|
||||
child->parent = currentIndex;
|
||||
assimpNodeTraversal(modelData, assimpNode->mChildren[n], nodeId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,104 +173,160 @@ ModelData* lovrModelDataCreate(Blob* blob) {
|
|||
ModelData* modelData = malloc(sizeof(ModelData));
|
||||
if (!modelData) return NULL;
|
||||
|
||||
modelData->hasNormals = 0;
|
||||
modelData->hasTexCoords = 0;
|
||||
struct aiFileIO assimpIO;
|
||||
assimpIO.OpenProc = assimpFileOpen;
|
||||
assimpIO.CloseProc = assimpFileClose;
|
||||
assimpIO.UserData = (void*) blob;
|
||||
|
||||
struct aiPropertyStore* propertyStore = aiCreatePropertyStore();
|
||||
aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE);
|
||||
unsigned int flags = aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_OptimizeGraph | aiProcess_FlipUVs;
|
||||
const struct aiScene* scene = aiImportFileFromMemory(blob->data, blob->size, flags, NULL);
|
||||
const struct aiScene* scene = aiImportFileExWithProperties(blob->name, flags, &assimpIO, propertyStore);
|
||||
aiReleasePropertyStore(propertyStore);
|
||||
|
||||
if (!scene) {
|
||||
lovrThrow("Unable to load model from '%s': %s\n", blob->name, aiGetErrorString());
|
||||
}
|
||||
|
||||
modelData->nodeCount = 0;
|
||||
modelData->vertexCount = 0;
|
||||
modelData->indexCount = 0;
|
||||
modelData->hasNormals = 0;
|
||||
modelData->hasUVs = 0;
|
||||
|
||||
// Meshes
|
||||
vec_init(&modelData->meshes);
|
||||
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
|
||||
struct aiMesh* assimpMesh = scene->mMeshes[m];
|
||||
ModelMesh* mesh = malloc(sizeof(ModelMesh));
|
||||
vec_push(&modelData->meshes, mesh);
|
||||
modelData->vertexCount += assimpMesh->mNumVertices;
|
||||
modelData->indexCount += assimpMesh->mNumFaces * 3;
|
||||
modelData->hasNormals |= assimpMesh->mNormals != NULL;
|
||||
modelData->hasUVs |= assimpMesh->mTextureCoords[0] != NULL;
|
||||
}
|
||||
|
||||
// Faces
|
||||
vec_init(&mesh->faces);
|
||||
// Allocate
|
||||
int indexSize = modelData->vertexCount > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
|
||||
modelData->primitiveCount = scene->mNumMeshes;
|
||||
modelData->primitives = malloc(modelData->primitiveCount * sizeof(ModelPrimitive));
|
||||
modelData->vertexSize = 3 + (modelData->hasNormals ? 3 : 0) + (modelData->hasUVs ? 2 : 0);
|
||||
modelData->vertices = malloc(modelData->vertexSize * modelData->vertexCount * sizeof(float));
|
||||
modelData->indices = malloc(modelData->indexCount * indexSize);
|
||||
|
||||
// Load
|
||||
int vertex = 0;
|
||||
int index = 0;
|
||||
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
|
||||
struct aiMesh* assimpMesh = scene->mMeshes[m];
|
||||
modelData->primitives[m].material = assimpMesh->mMaterialIndex;
|
||||
modelData->primitives[m].drawStart = index;
|
||||
modelData->primitives[m].drawCount = 0;
|
||||
|
||||
// Indices
|
||||
for (unsigned int f = 0; f < assimpMesh->mNumFaces; f++) {
|
||||
struct aiFace assimpFace = assimpMesh->mFaces[f];
|
||||
lovrAssert(assimpFace.mNumIndices == 3, "Only triangular faces are supported");
|
||||
|
||||
// Skip lines and points, polygons are triangulated
|
||||
if (assimpFace.mNumIndices != 3) {
|
||||
continue;
|
||||
}
|
||||
modelData->primitives[m].drawCount += assimpFace.mNumIndices;
|
||||
|
||||
ModelFace face;
|
||||
if (indexSize == sizeof(uint16_t)) {
|
||||
uint16_t* indices = modelData->indices;
|
||||
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
|
||||
face.indices[i] = assimpFace.mIndices[i];
|
||||
indices[index++] = (vertex / modelData->vertexSize) + assimpFace.mIndices[i];
|
||||
}
|
||||
} else if (indexSize == sizeof(uint32_t)) {
|
||||
uint32_t* indices = modelData->indices;
|
||||
for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) {
|
||||
indices[index++] = (vertex / modelData->vertexSize) + assimpFace.mIndices[i];
|
||||
}
|
||||
}
|
||||
vec_push(&mesh->faces, face);
|
||||
}
|
||||
|
||||
// Vertices
|
||||
vec_init(&mesh->vertices);
|
||||
for (unsigned int v = 0; v < assimpMesh->mNumVertices; v++) {
|
||||
ModelVertex vertex;
|
||||
vertex.x = assimpMesh->mVertices[v].x;
|
||||
vertex.y = assimpMesh->mVertices[v].y;
|
||||
vertex.z = assimpMesh->mVertices[v].z;
|
||||
vec_push(&mesh->vertices, vertex);
|
||||
modelData->vertices[vertex++] = assimpMesh->mVertices[v].x;
|
||||
modelData->vertices[vertex++] = assimpMesh->mVertices[v].y;
|
||||
modelData->vertices[vertex++] = assimpMesh->mVertices[v].z;
|
||||
|
||||
if (modelData->hasNormals) {
|
||||
if (assimpMesh->mNormals) {
|
||||
modelData->vertices[vertex++] = assimpMesh->mNormals[v].x;
|
||||
modelData->vertices[vertex++] = assimpMesh->mNormals[v].y;
|
||||
modelData->vertices[vertex++] = assimpMesh->mNormals[v].z;
|
||||
} else {
|
||||
modelData->vertices[vertex++] = 0;
|
||||
modelData->vertices[vertex++] = 0;
|
||||
modelData->vertices[vertex++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Normals
|
||||
lovrAssert(assimpMesh->mNormals, "Model must have normals");
|
||||
|
||||
modelData->hasNormals = 1;
|
||||
vec_init(&mesh->normals);
|
||||
for (unsigned int n = 0; n < assimpMesh->mNumVertices; n++) {
|
||||
ModelVertex normal;
|
||||
normal.x = assimpMesh->mNormals[n].x;
|
||||
normal.y = assimpMesh->mNormals[n].y;
|
||||
normal.z = assimpMesh->mNormals[n].z;
|
||||
vec_push(&mesh->normals, normal);
|
||||
}
|
||||
|
||||
modelData->hasTexCoords = modelData->hasTexCoords || assimpMesh->mTextureCoords[0] != NULL;
|
||||
if (modelData->hasUVs) {
|
||||
if (assimpMesh->mTextureCoords[0]) {
|
||||
vec_init(&mesh->texCoords);
|
||||
for (unsigned int i = 0; i < assimpMesh->mNumVertices; i++) {
|
||||
ModelVertex texCoord;
|
||||
texCoord.x = assimpMesh->mTextureCoords[0][i].x;
|
||||
texCoord.y = assimpMesh->mTextureCoords[0][i].y;
|
||||
vec_push(&mesh->texCoords, texCoord);
|
||||
modelData->vertices[vertex++] = assimpMesh->mTextureCoords[0][v].x;
|
||||
modelData->vertices[vertex++] = assimpMesh->mTextureCoords[0][v].y;
|
||||
} else {
|
||||
modelData->vertices[vertex++] = 0;
|
||||
modelData->vertices[vertex++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Materials
|
||||
modelData->materialCount = scene->mNumMaterials;
|
||||
modelData->materials = malloc(modelData->materialCount * sizeof(MaterialData));
|
||||
for (unsigned int m = 0; m < scene->mNumMaterials; m++) {
|
||||
MaterialData* materialData = lovrMaterialDataCreateEmpty();
|
||||
struct aiMaterial* material = scene->mMaterials[m];
|
||||
struct aiColor4D color;
|
||||
struct aiString str;
|
||||
|
||||
if (aiGetMaterialColor(material, AI_MATKEY_COLOR_DIFFUSE, &color) == aiReturn_SUCCESS) {
|
||||
materialData->colors[COLOR_DIFFUSE].r = color.r * 255;
|
||||
materialData->colors[COLOR_DIFFUSE].g = color.g * 255;
|
||||
materialData->colors[COLOR_DIFFUSE].b = color.b * 255;
|
||||
materialData->colors[COLOR_DIFFUSE].a = color.a * 255;
|
||||
}
|
||||
|
||||
if (aiGetMaterialTexture(material, aiTextureType_DIFFUSE, 0, &str, NULL, NULL, NULL, NULL, NULL, NULL) == aiReturn_SUCCESS) {
|
||||
char* path = str.data;
|
||||
char normalizedPath[LOVR_PATH_MAX];
|
||||
normalizePath(path, normalizedPath, LOVR_PATH_MAX);
|
||||
|
||||
size_t size;
|
||||
void* data = lovrFilesystemRead(path, &size);
|
||||
if (data) {
|
||||
Blob* blob = lovrBlobCreate(data, size, path);
|
||||
materialData->textures[TEXTURE_DIFFUSE] = lovrTextureDataFromBlob(blob);
|
||||
}
|
||||
}
|
||||
|
||||
modelData->materials[m] = *materialData;
|
||||
}
|
||||
|
||||
// Nodes
|
||||
modelData->root = malloc(sizeof(ModelNode));
|
||||
assimpNodeTraversal(modelData->root, scene->mRootNode);
|
||||
modelData->nodeCount = 0;
|
||||
assimpSumChildren(scene->mRootNode, &modelData->nodeCount);
|
||||
modelData->nodes = malloc(modelData->nodeCount * sizeof(ModelNode));
|
||||
modelData->nodes[0].parent = -1;
|
||||
int nodeIndex = 0;
|
||||
assimpNodeTraversal(modelData, scene->mRootNode, &nodeIndex);
|
||||
|
||||
aiReleaseImport(scene);
|
||||
return modelData;
|
||||
}
|
||||
|
||||
void lovrModelDataDestroy(ModelData* modelData) {
|
||||
for (int i = 0; i < modelData->meshes.length; i++) {
|
||||
ModelMesh* mesh = modelData->meshes.data[i];
|
||||
vec_deinit(&mesh->faces);
|
||||
vec_deinit(&mesh->vertices);
|
||||
vec_deinit(&mesh->normals);
|
||||
if (modelData->hasTexCoords) {
|
||||
vec_deinit(&mesh->texCoords);
|
||||
}
|
||||
free(mesh);
|
||||
for (int i = 0; i < modelData->nodeCount; i++) {
|
||||
vec_deinit(&modelData->nodes[i].children);
|
||||
vec_deinit(&modelData->nodes[i].primitives);
|
||||
}
|
||||
|
||||
vec_void_t nodes;
|
||||
vec_init(&nodes);
|
||||
vec_push(&nodes, modelData->root);
|
||||
while (nodes.length > 0) {
|
||||
ModelNode* node = vec_first(&nodes);
|
||||
vec_extend(&nodes, &node->children);
|
||||
vec_deinit(&node->meshes);
|
||||
vec_deinit(&node->children);
|
||||
vec_splice(&nodes, 0, 1);
|
||||
free(node);
|
||||
for (int i = 0; i < modelData->materialCount; i++) {
|
||||
lovrMaterialDataDestroy(&modelData->materials[i]);
|
||||
}
|
||||
|
||||
vec_deinit(&modelData->meshes);
|
||||
vec_deinit(&nodes);
|
||||
free(modelData->nodes);
|
||||
free(modelData->primitives);
|
||||
free(modelData->materials);
|
||||
free(modelData->vertices);
|
||||
free(modelData->indices);
|
||||
free(modelData);
|
||||
}
|
||||
|
|
|
@ -1,43 +1,37 @@
|
|||
#include "filesystem/blob.h"
|
||||
#include "loaders/material.h"
|
||||
#include "util.h"
|
||||
#include "lib/vec/vec.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} ModelVertex;
|
||||
int material;
|
||||
int drawStart;
|
||||
int drawCount;
|
||||
} ModelPrimitive;
|
||||
|
||||
typedef vec_t(ModelVertex) vec_model_vertex_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int indices[3];
|
||||
} ModelFace;
|
||||
|
||||
typedef vec_t(ModelFace) vec_model_face_t;
|
||||
|
||||
typedef struct {
|
||||
vec_model_face_t faces;
|
||||
vec_model_vertex_t vertices;
|
||||
vec_model_vertex_t normals;
|
||||
vec_model_vertex_t texCoords;
|
||||
} ModelMesh;
|
||||
|
||||
typedef vec_t(ModelMesh*) vec_model_mesh_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct ModelNode {
|
||||
float transform[16];
|
||||
vec_uint_t meshes;
|
||||
vec_void_t children;
|
||||
int parent;
|
||||
vec_uint_t children;
|
||||
vec_uint_t primitives;
|
||||
} ModelNode;
|
||||
|
||||
typedef struct {
|
||||
ModelNode* root;
|
||||
vec_model_mesh_t meshes;
|
||||
ModelNode* nodes;
|
||||
ModelPrimitive* primitives;
|
||||
MaterialData* materials;
|
||||
float* vertices;
|
||||
void* indices;
|
||||
int nodeCount;
|
||||
int primitiveCount;
|
||||
int materialCount;
|
||||
int vertexCount;
|
||||
int vertexSize;
|
||||
int indexCount;
|
||||
int hasNormals;
|
||||
int hasTexCoords;
|
||||
int hasUVs;
|
||||
} ModelData;
|
||||
|
||||
ModelData* lovrModelDataCreate(Blob* blob);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "filesystem/blob.h"
|
||||
#include "lib/glad/glad.h"
|
||||
#include <stddef.h>
|
||||
#include "lib/glfw.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma once
|
||||
|
|
24
src/luax.c
24
src/luax.c
|
@ -148,3 +148,27 @@ void* luax_optenum(lua_State* L, int index, const char* fallback, map_int_t* map
|
|||
|
||||
return value;
|
||||
}
|
||||
|
||||
Color luax_checkcolor(lua_State* L, int index) {
|
||||
Color color = { 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
lua_rawgeti(L, 1, i);
|
||||
}
|
||||
color.r = luaL_checknumber(L, -4);
|
||||
color.g = luaL_checknumber(L, -3);
|
||||
color.b = luaL_checknumber(L, -2);
|
||||
color.a = luaL_optnumber(L, -1, 255);
|
||||
lua_pop(L, 4);
|
||||
} else if (lua_gettop(L) >= index + 2) {
|
||||
color.r = lua_tointeger(L, index);
|
||||
color.g = lua_tointeger(L, index + 1);
|
||||
color.b = lua_tointeger(L, index + 2);
|
||||
color.a = lua_isnoneornil(L, index + 3) ? 255 : lua_tointeger(L, index + 3);
|
||||
} else {
|
||||
luaL_error(L, "Invalid color, expected 3 numbers, 4 numbers, or a table");
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
#include "lib/map/map.h"
|
||||
#include "util.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -35,3 +36,4 @@ void luax_registerobject(lua_State* L, void* object);
|
|||
void luax_pushenum(lua_State* L, map_int_t* map, int value);
|
||||
void* luax_checkenum(lua_State* L, int index, map_int_t* map, const char* typeName);
|
||||
void* luax_optenum(lua_State* L, int index, const char* fallback, map_int_t* map, const char* typeName);
|
||||
Color luax_checkcolor(lua_State* L, int index);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "math/quat.h"
|
||||
#include "math/vec3.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// m0 m4 m8 m12
|
||||
|
|
Loading…
Reference in New Issue