mirror of https://github.com/bjornbytes/lovr.git
Add new array implementation; Upgrade filesystem;
Filesystem: - Uses streaming file IO. - Uses less memory when requiring files. - Simplifies its require path implementation.
This commit is contained in:
parent
f8f6d98df4
commit
eb1e257209
|
@ -316,6 +316,7 @@ endif()
|
|||
|
||||
set(LOVR_SRC
|
||||
src/main.c
|
||||
src/core/arr.c
|
||||
src/core/luax.c
|
||||
src/core/maf.c
|
||||
src/core/platform.c
|
||||
|
@ -324,7 +325,6 @@ set(LOVR_SRC
|
|||
src/core/util.c
|
||||
src/api/l_lovr.c
|
||||
src/lib/map/map.c
|
||||
src/lib/vec/vec.c
|
||||
src/lib/sds/sds.c
|
||||
)
|
||||
|
||||
|
|
|
@ -31,10 +31,11 @@ static int l_lovrColliderRemoveShape(lua_State* L) {
|
|||
|
||||
static int l_lovrColliderGetShapes(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
lua_newtable(L);
|
||||
vec_void_t* shapes = lovrColliderGetShapes(collider);
|
||||
for (int i = 0; i < shapes->length; i++) {
|
||||
luax_pushshape(L, shapes->data[i]);
|
||||
size_t count;
|
||||
Shape** shapes = lovrColliderGetShapes(collider, &count);
|
||||
lua_createtable(L, count, 0);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
luax_pushshape(L, shapes[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
|
@ -42,10 +43,11 @@ static int l_lovrColliderGetShapes(lua_State* L) {
|
|||
|
||||
static int l_lovrColliderGetJoints(lua_State* L) {
|
||||
Collider* collider = luax_checktype(L, 1, Collider);
|
||||
lua_newtable(L);
|
||||
vec_void_t* joints = lovrColliderGetJoints(collider);
|
||||
for (int i = 0; i < joints->length; i++) {
|
||||
luax_pushjoint(L, joints->data[i]);
|
||||
size_t count;
|
||||
Joint** joints = lovrColliderGetJoints(collider, &count);
|
||||
lua_createtable(L, count, 0);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
luax_pushjoint(L, joints[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
return 1;
|
||||
|
|
|
@ -33,13 +33,14 @@ static int l_lovrCurveRender(lua_State* L) {
|
|||
lovrAssert(points, "Out of memory");
|
||||
lovrCurveRender(curve, t1, t2, points, n);
|
||||
lua_createtable(L, n, 0);
|
||||
for (int i = 0; i < n; i += 4) {
|
||||
int j = 1;
|
||||
for (int i = 0; i < 4 * n; i += 4) {
|
||||
lua_pushnumber(L, points[i + 0]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
lua_rawseti(L, -2, j++);
|
||||
lua_pushnumber(L, points[i + 1]);
|
||||
lua_rawseti(L, -2, i + 2);;
|
||||
lua_rawseti(L, -2, j++);
|
||||
lua_pushnumber(L, points[i + 2]);
|
||||
lua_rawseti(L, -2, i + 3);
|
||||
lua_rawseti(L, -2, j++);
|
||||
}
|
||||
free(points);
|
||||
return 1;
|
||||
|
@ -62,7 +63,7 @@ static int l_lovrCurveGetPointCount(lua_State* L) {
|
|||
|
||||
static int l_lovrCurveGetPoint(lua_State* L) {
|
||||
Curve* curve = luax_checktype(L, 1, Curve);
|
||||
int index = luaL_checkinteger(L, 2) - 1;
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
float point[4];
|
||||
lovrCurveGetPoint(curve, index, point);
|
||||
|
@ -74,7 +75,7 @@ static int l_lovrCurveGetPoint(lua_State* L) {
|
|||
|
||||
static int l_lovrCurveSetPoint(lua_State* L) {
|
||||
Curve* curve = luax_checktype(L, 1, Curve);
|
||||
int index = luaL_checkinteger(L, 2) - 1;
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
float point[4];
|
||||
luax_readvec3(L, 3, point, NULL);
|
||||
|
@ -86,7 +87,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
|
|||
Curve* curve = luax_checktype(L, 1, Curve);
|
||||
float point[4];
|
||||
int i = luax_readvec3(L, 2, point, NULL);
|
||||
int index = lua_isnoneornil(L, i) ? lovrCurveGetPointCount(curve) : luaL_checkinteger(L, i) - 1;
|
||||
size_t index = lua_isnoneornil(L, i) ? lovrCurveGetPointCount(curve) : luaL_checkinteger(L, i) - 1;
|
||||
lovrAssert(index >= 0 && index <= lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCurveAddPoint(curve, point, index);
|
||||
return 0;
|
||||
|
@ -94,7 +95,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
|
|||
|
||||
static int l_lovrCurveRemovePoint(lua_State* L) {
|
||||
Curve* curve = luax_checktype(L, 1, Curve);
|
||||
int index = luaL_checkinteger(L, 2) - 1;
|
||||
size_t index = luaL_checkinteger(L, 2) - 1;
|
||||
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||
lovrCurveRemovePoint(curve, index);
|
||||
return 0;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "data/textureData.h"
|
||||
#include "core/ref.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int l_lovrDataNewBlob(lua_State* L) {
|
||||
size_t size;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "api.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "filesystem/file.h"
|
||||
#include "data/blob.h"
|
||||
#include "core/ref.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "platform.h"
|
||||
|
||||
// Returns a Blob, leaving stack unchanged. The Blob must be released when finished.
|
||||
|
@ -32,65 +34,28 @@ static int pushDirectoryItem(void* userdata, const char* path, const char* filen
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemLoad(lua_State* L);
|
||||
typedef struct {
|
||||
File file;
|
||||
char buffer[4096];
|
||||
} luax_Reader;
|
||||
|
||||
static int moduleLoader(lua_State* L) {
|
||||
const char* module = luaL_gsub(L, lua_tostring(L, -1), ".", "/");
|
||||
lua_pop(L, 2);
|
||||
|
||||
char* path; int i;
|
||||
vec_foreach(lovrFilesystemGetRequirePath(), path, i) {
|
||||
const char* filename = luaL_gsub(L, path, "?", module);
|
||||
if (lovrFilesystemIsFile(filename)) {
|
||||
return l_lovrFilesystemLoad(L);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static const char* readCallback(lua_State* L, void* data, size_t* size) {
|
||||
luax_Reader* reader = data;
|
||||
*size = lovrFileRead(&reader->file, reader->buffer, sizeof(reader->buffer));
|
||||
return *size == 0 ? NULL : reader->buffer;
|
||||
}
|
||||
|
||||
static const char* libraryExtensions[] = {
|
||||
#ifdef _WIN32
|
||||
".dll", NULL
|
||||
#elif __APPLE__
|
||||
".so", ".dylib", NULL
|
||||
#else
|
||||
".so", NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
static int libraryLoader(lua_State* L) {
|
||||
const char* modulePath = luaL_gsub(L, lua_tostring(L, -1), ".", "/");
|
||||
const char* moduleFunction = luaL_gsub(L, lua_tostring(L, -1), ".", "_");
|
||||
char* hyphen = strchr(moduleFunction, '-');
|
||||
moduleFunction = hyphen ? hyphen + 1 : moduleFunction;
|
||||
lua_pop(L, 3);
|
||||
|
||||
char* path; int i;
|
||||
vec_foreach(lovrFilesystemGetCRequirePath(), path, i) {
|
||||
for (const char** extension = libraryExtensions; *extension != NULL; extension++) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, 63, "%s%s", modulePath, *extension);
|
||||
const char* filename = luaL_gsub(L, path, "??", buffer);
|
||||
filename = luaL_gsub(L, filename, "?", modulePath);
|
||||
lua_pop(L, 2);
|
||||
|
||||
if (lovrFilesystemIsFile(filename)) {
|
||||
char fullPath[LOVR_PATH_MAX];
|
||||
const char* realPath = lovrFilesystemGetRealDirectory(filename);
|
||||
snprintf(fullPath, LOVR_PATH_MAX - 1, "%s%c%s", realPath, lovrDirSep, filename);
|
||||
lua_getglobal(L, "package");
|
||||
lua_getfield(L, -1, "loadlib");
|
||||
lua_pushstring(L, fullPath);
|
||||
lua_pushfstring(L, "luaopen_%s", moduleFunction);
|
||||
lua_call(L, 2, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
static int luax_loadfile(lua_State* L, const char* path, const char* debug) {
|
||||
luax_Reader reader;
|
||||
lovrFileInit(&reader.file, path);
|
||||
lovrAssert(lovrFileOpen(&reader.file, OPEN_READ), "Could not open file %s", path);
|
||||
int status = lua_load(L, readCallback, &reader, debug);
|
||||
lovrFileDestroy(&reader.file);
|
||||
switch (status) {
|
||||
case LUA_ERRMEM: return luaL_error(L, "Memory allocation error: %s", lua_tostring(L, -1));
|
||||
case LUA_ERRSYNTAX: return luaL_error(L, "Syntax error: %s", lua_tostring(L, -1));
|
||||
default: return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemAppend(lua_State* L) {
|
||||
|
@ -167,19 +132,9 @@ static int l_lovrFilesystemGetRealDirectory(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void pushRequirePath(lua_State* L, vec_str_t* path) {
|
||||
char* pattern; int i;
|
||||
vec_foreach(path, pattern, i) {
|
||||
lua_pushstring(L, pattern);
|
||||
lua_pushliteral(L, ";");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_concat(L, path->length * 2 - 1);
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemGetRequirePath(lua_State* L) {
|
||||
pushRequirePath(L, lovrFilesystemGetRequirePath());
|
||||
pushRequirePath(L, lovrFilesystemGetCRequirePath());
|
||||
lua_pushstring(L, lovrFilesystemGetRequirePath());
|
||||
lua_pushstring(L, lovrFilesystemGetCRequirePath());
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -246,23 +201,9 @@ static int l_lovrFilesystemIsFused(lua_State* L) {
|
|||
|
||||
static int l_lovrFilesystemLoad(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
size_t size;
|
||||
char* content = lovrFilesystemRead(path, -1, &size);
|
||||
|
||||
if (!content) {
|
||||
return luaL_error(L, "Could not read file '%s'", path);
|
||||
}
|
||||
|
||||
char debug[LOVR_PATH_MAX];
|
||||
snprintf(debug, LOVR_PATH_MAX, "@%s", path);
|
||||
|
||||
int status = luaL_loadbuffer(L, content, size, debug);
|
||||
free(content);
|
||||
switch (status) {
|
||||
case LUA_ERRMEM: return luaL_error(L, "Memory allocation error: %s", lua_tostring(L, -1));
|
||||
case LUA_ERRSYNTAX: return luaL_error(L, "Syntax error: %s", lua_tostring(L, -1));
|
||||
default: return 1;
|
||||
}
|
||||
lua_pushfstring(L, "@%s", path);
|
||||
const char* debug = lua_tostring(L, -1);
|
||||
return luax_loadfile(L, path, debug);
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemMount(lua_State* L) {
|
||||
|
@ -318,8 +259,8 @@ static int l_lovrFilesystemSetIdentity(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrFilesystemSetRequirePath(lua_State* L) {
|
||||
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(luaL_checkstring(L, 1));
|
||||
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(luaL_checkstring(L, 2));
|
||||
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(lua_tostring(L, 1));
|
||||
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(lua_tostring(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -379,6 +320,129 @@ static const luaL_Reg lovrFilesystem[] = {
|
|||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static int luaLoader(lua_State* L) {
|
||||
const char* module = lua_tostring(L, 1);
|
||||
const char* p = lovrFilesystemGetRequirePath();
|
||||
|
||||
char buffer[1024] = { '@' };
|
||||
char* debug = &buffer[0];
|
||||
char* filename = &buffer[1];
|
||||
char* f = filename;
|
||||
size_t n = sizeof(buffer) - 1;
|
||||
|
||||
// Loop over the require path, character by character, and:
|
||||
// - Replace question marks with the module that's being required, converting '.' to '/'.
|
||||
// - If there's a semicolon/eof, treat it as the end of a potential filename and try to load it.
|
||||
// The filename buffer has an '@' before it so it can also be used as the debug label for the Lua
|
||||
// chunk without additional memory allocation.
|
||||
|
||||
while (1) {
|
||||
if (*p == ';' || *p == '\0') {
|
||||
*f = '\0';
|
||||
|
||||
if (lovrFilesystemIsFile(filename)) {
|
||||
return luax_loadfile(L, filename, debug);
|
||||
}
|
||||
|
||||
if (*p == '\0') {
|
||||
break;
|
||||
} else {
|
||||
p++;
|
||||
f = filename;
|
||||
n = sizeof(buffer) - 1;
|
||||
}
|
||||
} else if (*p == '?') {
|
||||
for (const char* m = module; n && *m; n--, m++) {
|
||||
*f++ = *m == '.' ? '/' : *m;
|
||||
}
|
||||
p++;
|
||||
} else {
|
||||
*f++ = *p++;
|
||||
n--;
|
||||
}
|
||||
|
||||
lovrAssert(n > 0, "Tried to require a filename that was too long (%s)", module);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libLoader(lua_State* L) {
|
||||
#ifdef _WIN32
|
||||
const char* extension = ".dll";
|
||||
#else
|
||||
const char* extension = ".so";
|
||||
#endif
|
||||
|
||||
const char* module = lua_tostring(L, 1);
|
||||
const char* hyphen = strchr(module, '-');
|
||||
const char* symbol = hyphen ? hyphen + 1 : module;
|
||||
const char* p = lovrFilesystemGetCRequirePath();
|
||||
|
||||
char filename[1024];
|
||||
char* f = filename;
|
||||
size_t n = sizeof(filename);
|
||||
|
||||
lua_getglobal(L, "package");
|
||||
while (1) {
|
||||
if (*p == ';' || *p == '\0') {
|
||||
*f = '\0';
|
||||
|
||||
if (lovrFilesystemIsFile(filename)) {
|
||||
lua_getfield(L, -1, "loadlib");
|
||||
|
||||
// Synthesize the absolute path to the library on disk (outside of physfs)
|
||||
luaL_Buffer buffer;
|
||||
luaL_buffinit(L, &buffer);
|
||||
luaL_addstring(&buffer, lovrFilesystemGetRealDirectory(filename));
|
||||
luaL_addchar(&buffer, lovrDirSep);
|
||||
luaL_addstring(&buffer, filename);
|
||||
luaL_pushresult(&buffer);
|
||||
|
||||
// Synthesize the symbol to load: luaopen_ followed by the module name with dots converted
|
||||
// to underscores, starting after the first hyphen (if there is one).
|
||||
luaL_buffinit(L, &buffer);
|
||||
luaL_addstring(&buffer, "luaopen_");
|
||||
for (const char* s = symbol; *s; s++) {
|
||||
luaL_addchar(&buffer, *s == '.' ? '_' : *s);
|
||||
}
|
||||
luaL_pushresult(&buffer);
|
||||
|
||||
// Finally call package.loadlib with the library path and symbol name
|
||||
lua_call(L, 2, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*p == '\0') {
|
||||
break;
|
||||
} else {
|
||||
p++;
|
||||
f = filename;
|
||||
n = sizeof(filename);
|
||||
}
|
||||
} else if (*p == '?') {
|
||||
for (const char* m = module; n && *m; n--, m++) {
|
||||
*f++ = *m == '.' ? lovrDirSep : *m;
|
||||
}
|
||||
p++;
|
||||
|
||||
if (*p == '?') {
|
||||
for (const char* e = extension; n && *e; n--, e++) {
|
||||
*f++ = *e;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
} else {
|
||||
*f++ = *p++;
|
||||
n--;
|
||||
}
|
||||
|
||||
lovrAssert(n > 0, "Tried to require a filename that was too long (%s)", module);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luaopen_lovr_filesystem(lua_State* L) {
|
||||
lua_getglobal(L, "arg");
|
||||
if (lua_istable(L, -1)) {
|
||||
|
@ -401,7 +465,7 @@ int luaopen_lovr_filesystem(lua_State* L) {
|
|||
|
||||
lua_newtable(L);
|
||||
luaL_register(L, NULL, lovrFilesystem);
|
||||
luax_registerloader(L, moduleLoader, 2);
|
||||
luax_registerloader(L, libraryLoader, 3);
|
||||
luax_registerloader(L, luaLoader, 2);
|
||||
luax_registerloader(L, libLoader, 3);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "data/rasterizer.h"
|
||||
#include "data/textureData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/ref.h"
|
||||
#include "util.h"
|
||||
#include <math.h>
|
||||
|
@ -443,7 +444,7 @@ static int l_lovrGraphicsGetStats(lua_State* L) {
|
|||
lua_pushinteger(L, stats->shaderSwitches);
|
||||
lua_setfield(L, 1, "shaderswitches");
|
||||
lua_createtable(L, 0, stats->timers.length);
|
||||
for (int i = 0; i < stats->timers.length; i++) {
|
||||
for (size_t i = 0; i < stats->timers.length; i++) {
|
||||
lua_pushstring(L, stats->timers.data[i].label);
|
||||
lua_pushnumber(L, stats->timers.data[i].time);
|
||||
lua_settable(L, -3);
|
||||
|
@ -1010,8 +1011,8 @@ static void luax_checkuniformtype(lua_State* L, int index, UniformType* baseType
|
|||
}
|
||||
|
||||
static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
|
||||
vec_uniform_t uniforms;
|
||||
vec_init(&uniforms);
|
||||
arr_uniform_t uniforms;
|
||||
arr_init(&uniforms);
|
||||
|
||||
BlockType type = luaL_checkoption(L, 1, NULL, BlockTypes);
|
||||
|
||||
|
@ -1039,7 +1040,7 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
|
|||
}
|
||||
|
||||
lovrAssert(uniform.count >= 1, "Uniform count must be positive, got %d for '%s'", uniform.count, uniform.name);
|
||||
vec_push(&uniforms, uniform);
|
||||
arr_push(&uniforms, uniform);
|
||||
|
||||
// Pop the table, leaving the key for lua_next to nom
|
||||
lua_pop(L, 1);
|
||||
|
@ -1063,7 +1064,7 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
|
|||
Buffer* buffer = lovrBufferCreate(size, NULL, type == BLOCK_COMPUTE ? BUFFER_SHADER_STORAGE : BUFFER_UNIFORM, usage, readable);
|
||||
ShaderBlock* block = lovrShaderBlockCreate(type, buffer, &uniforms);
|
||||
luax_pushtype(L, ShaderBlock, block);
|
||||
vec_deinit(&uniforms);
|
||||
arr_free(&uniforms);
|
||||
lovrRelease(Buffer, buffer);
|
||||
lovrRelease(ShaderBlock, block);
|
||||
return 1;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "data/modelData.h"
|
||||
#include "graphics/model.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/maf.h"
|
||||
#include "core/ref.h"
|
||||
#include <stdlib.h>
|
||||
|
@ -230,12 +231,17 @@ static int l_lovrHeadsetGetBoundsGeometry(lua_State* L) {
|
|||
lua_settop(L, 1);
|
||||
} else {
|
||||
lua_settop(L, 0);
|
||||
lua_createtable(L, count, 0);
|
||||
lua_createtable(L, count / 4, 0);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_pushnumber(L, points[i]);
|
||||
lua_rawseti(L, 1, i + 1);
|
||||
int j = 1;
|
||||
for (uint32_t i = 0; i < count; i += 4) {
|
||||
lua_pushnumber(L, points[i + 0]);
|
||||
lua_rawseti(L, 1, j++);
|
||||
lua_pushnumber(L, points[i + 1]);
|
||||
lua_rawseti(L, 1, j++);
|
||||
lua_pushnumber(L, points[i + 2]);
|
||||
lua_rawseti(L, 1, j++);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -608,8 +614,8 @@ int luaopen_lovr_headset(lua_State* L) {
|
|||
luax_pushconf(L);
|
||||
lua_getfield(L, -1, "headset");
|
||||
|
||||
vec_t(HeadsetDriver) drivers;
|
||||
vec_init(&drivers);
|
||||
arr_t(HeadsetDriver, 8) drivers;
|
||||
arr_init(&drivers);
|
||||
float offset = 1.7f;
|
||||
int msaa = 4;
|
||||
|
||||
|
@ -620,7 +626,7 @@ int luaopen_lovr_headset(lua_State* L) {
|
|||
int n = luax_len(L, -1);
|
||||
for (int i = 0; i < n; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
vec_push(&drivers, luaL_checkoption(L, -1, NULL, HeadsetDrivers));
|
||||
arr_push(&drivers, luaL_checkoption(L, -1, NULL, HeadsetDrivers));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
@ -640,7 +646,7 @@ int luaopen_lovr_headset(lua_State* L) {
|
|||
luax_atexit(L, lovrHeadsetDestroy);
|
||||
}
|
||||
|
||||
vec_deinit(&drivers);
|
||||
arr_free(&drivers);
|
||||
lua_pop(L, 2);
|
||||
|
||||
headsetRenderData.ref = LUA_NOREF;
|
||||
|
|
|
@ -79,16 +79,9 @@ float* luax_newmathtype(lua_State* L, MathType type) {
|
|||
}
|
||||
|
||||
static int l_lovrMathNewCurve(lua_State* L) {
|
||||
Curve* curve = lovrCurveCreate();
|
||||
int top = lua_gettop(L);
|
||||
|
||||
if (top == 1 && lua_type(L, 1) == LUA_TNUMBER) {
|
||||
Curve* curve = lovrCurveCreate(luaL_checkinteger(L, 1));
|
||||
luax_pushtype(L, Curve, curve);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Curve* curve = lovrCurveCreate(3);
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
int pointIndex = 0;
|
||||
int length = luax_len(L, 1);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "thread/channel.h"
|
||||
#include "core/ref.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int threadRunner(void* data) {
|
||||
Thread* thread = (Thread*) data;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#include "arr.h"
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void _arr_reserve(void** data, void* temp, size_t n, size_t* capacity, size_t stride) {
|
||||
size_t oldCapacity = *capacity;
|
||||
|
||||
while (*capacity < n) {
|
||||
*capacity <<= 1;
|
||||
lovrAssert(*capacity > 0, "Out of memory");
|
||||
}
|
||||
|
||||
if (*data == temp) {
|
||||
*data = realloc(NULL, *capacity * stride);
|
||||
lovrAssert(*data, "Out of memory");
|
||||
memcpy(*data, temp, oldCapacity * stride);
|
||||
} else {
|
||||
*data = realloc(*data, *capacity * stride);
|
||||
lovrAssert(*data, "Out of memory");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
// A dynamic array that uses the stack initially and switches to the heap if it gets big enough.
|
||||
|
||||
#define arr_t(T, n)\
|
||||
struct { T *data; T temp[n]; size_t length, capacity; }
|
||||
|
||||
#define arr_init(a)\
|
||||
(a)->data = (a)->temp,\
|
||||
(a)->length = 0,\
|
||||
(a)->capacity = sizeof((a)->temp) / sizeof((a)->temp[0])
|
||||
|
||||
#define arr_free(a)\
|
||||
if ((a)->data != (a)->temp) free((a)->data)
|
||||
|
||||
#define arr_reserve(a, n)\
|
||||
n > (a)->capacity ?\
|
||||
_arr_reserve((void**) &((a)->data), (a)->temp, n, &(a)->capacity, sizeof(*(a)->data)) :\
|
||||
(void) 0
|
||||
|
||||
#define arr_push(a, x)\
|
||||
arr_reserve(a, (a)->length + 1),\
|
||||
(a)->data[(a)->length++] = x
|
||||
|
||||
#define arr_pop(a)\
|
||||
(a)->data[--(a)->length]
|
||||
|
||||
#define arr_append(a, p, n)\
|
||||
arr_reserve(a, (a)->length + n),\
|
||||
memcpy((a)->data + (a)->length, p, n * sizeof(*(p))),\
|
||||
(a)->length += n
|
||||
|
||||
#define arr_splice(a, i, n)\
|
||||
memmove((a)->data + i, (a)->data + (i + n), n * sizeof(*(a)->data)),\
|
||||
(a)->length -= n
|
||||
|
||||
#define arr_clear(a)\
|
||||
(a)->length = 0
|
||||
|
||||
void _arr_reserve(void** data, void* temp, size_t n, size_t* capacity, size_t stride);
|
|
@ -1,20 +0,0 @@
|
|||
Copyright (c) 2014 rxi
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,114 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2014 rxi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "vec.h"
|
||||
|
||||
|
||||
int vec_expand_(char **data, int *length, int *capacity, int memsz) {
|
||||
if (*length + 1 > *capacity) {
|
||||
void *ptr;
|
||||
int n = (*capacity == 0) ? 1 : *capacity << 1;
|
||||
ptr = realloc(*data, n * memsz);
|
||||
if (ptr == NULL) return -1;
|
||||
*data = ptr;
|
||||
*capacity = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vec_reserve_(char **data, int *length, int *capacity, int memsz, int n) {
|
||||
(void) length;
|
||||
if (n > *capacity) {
|
||||
void *ptr = realloc(*data, n * memsz);
|
||||
if (ptr == NULL) return -1;
|
||||
*data = ptr;
|
||||
*capacity = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vec_reserve_po2_(
|
||||
char **data, int *length, int *capacity, int memsz, int n
|
||||
) {
|
||||
int n2 = 1;
|
||||
if (n == 0) return 0;
|
||||
while (n2 < n) n2 <<= 1;
|
||||
return vec_reserve_(data, length, capacity, memsz, n2);
|
||||
}
|
||||
|
||||
|
||||
int vec_compact_(char **data, int *length, int *capacity, int memsz) {
|
||||
if (*length == 0) {
|
||||
free(*data);
|
||||
*data = NULL;
|
||||
*capacity = 0;
|
||||
return 0;
|
||||
} else {
|
||||
void *ptr;
|
||||
int n = *length;
|
||||
ptr = realloc(*data, n * memsz);
|
||||
if (ptr == NULL) return -1;
|
||||
*capacity = n;
|
||||
*data = ptr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vec_insert_(char **data, int *length, int *capacity, int memsz,
|
||||
int idx
|
||||
) {
|
||||
int err = vec_expand_(data, length, capacity, memsz);
|
||||
if (err) return err;
|
||||
memmove(*data + (idx + 1) * memsz,
|
||||
*data + idx * memsz,
|
||||
(*length - idx) * memsz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void vec_splice_(char **data, int *length, int *capacity, int memsz,
|
||||
int start, int count
|
||||
) {
|
||||
(void) capacity;
|
||||
memmove(*data + start * memsz,
|
||||
*data + (start + count) * memsz,
|
||||
(*length - start - count) * memsz);
|
||||
}
|
||||
|
||||
|
||||
void vec_swapsplice_(char **data, int *length, int *capacity, int memsz,
|
||||
int start, int count
|
||||
) {
|
||||
(void) capacity;
|
||||
memmove(*data + start * memsz,
|
||||
*data + (*length - count) * memsz,
|
||||
count * memsz);
|
||||
}
|
||||
|
||||
|
||||
void vec_swap_(char **data, int *length, int *capacity, int memsz,
|
||||
int idx1, int idx2
|
||||
) {
|
||||
unsigned char *a, *b, tmp;
|
||||
int count;
|
||||
(void) length;
|
||||
(void) capacity;
|
||||
if (idx1 == idx2) return;
|
||||
a = (unsigned char*) *data + idx1 * memsz;
|
||||
b = (unsigned char*) *data + idx2 * memsz;
|
||||
count = memsz;
|
||||
while (count--) {
|
||||
tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
a++, b++;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2014 rxi
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef VEC_H
|
||||
#define VEC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define VEC_VERSION "0.2.1"
|
||||
|
||||
|
||||
#define vec_unpack_(v)\
|
||||
(char**)&(v)->data, &(v)->length, &(v)->capacity, sizeof(*(v)->data)
|
||||
|
||||
|
||||
#define vec_t(T)\
|
||||
struct { T *data; int length, capacity; }
|
||||
|
||||
|
||||
#define vec_init(v)\
|
||||
memset((v), 0, sizeof(*(v)))
|
||||
|
||||
|
||||
#define vec_deinit(v)\
|
||||
( free((v)->data),\
|
||||
vec_init(v) )
|
||||
|
||||
|
||||
#define vec_push(v, val)\
|
||||
( vec_expand_(vec_unpack_(v)) ? -1 :\
|
||||
((v)->data[(v)->length++] = (val), 0) )
|
||||
|
||||
|
||||
#define vec_pop(v)\
|
||||
(v)->data[--(v)->length]
|
||||
|
||||
|
||||
#define vec_splice(v, start, count)\
|
||||
( vec_splice_(vec_unpack_(v), start, count),\
|
||||
(v)->length -= (count) )
|
||||
|
||||
|
||||
#define vec_swapsplice(v, start, count)\
|
||||
( vec_swapsplice_(vec_unpack_(v), start, count),\
|
||||
(v)->length -= (count) )
|
||||
|
||||
|
||||
#define vec_insert(v, idx, val)\
|
||||
( vec_insert_(vec_unpack_(v), idx) ? -1 :\
|
||||
((v)->data[idx] = (val), 0), (v)->length++, 0 )
|
||||
|
||||
|
||||
#define vec_sort(v, fn)\
|
||||
qsort((v)->data, (v)->length, sizeof(*(v)->data), fn)
|
||||
|
||||
|
||||
#define vec_swap(v, idx1, idx2)\
|
||||
vec_swap_(vec_unpack_(v), idx1, idx2)
|
||||
|
||||
|
||||
#define vec_truncate(v, len)\
|
||||
((v)->length = (len) < (v)->length ? (len) : (v)->length)
|
||||
|
||||
|
||||
#define vec_clear(v)\
|
||||
((v)->length = 0)
|
||||
|
||||
|
||||
#define vec_first(v)\
|
||||
(v)->data[0]
|
||||
|
||||
|
||||
#define vec_last(v)\
|
||||
(v)->data[(v)->length - 1]
|
||||
|
||||
|
||||
#define vec_reserve(v, n)\
|
||||
vec_reserve_(vec_unpack_(v), n)
|
||||
|
||||
|
||||
#define vec_compact(v)\
|
||||
vec_compact_(vec_unpack_(v))
|
||||
|
||||
|
||||
#define vec_pusharr(v, arr, count)\
|
||||
do {\
|
||||
int i__, n__ = (count);\
|
||||
if (vec_reserve_po2_(vec_unpack_(v), (v)->length + n__) != 0) break;\
|
||||
for (i__ = 0; i__ < n__; i__++) {\
|
||||
(v)->data[(v)->length++] = (arr)[i__];\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
|
||||
#define vec_extend(v, v2)\
|
||||
vec_pusharr((v), (v2)->data, (v2)->length)
|
||||
|
||||
|
||||
#define vec_find(v, val, idx)\
|
||||
do {\
|
||||
for ((idx) = 0; (idx) < (v)->length; (idx)++) {\
|
||||
if ((v)->data[(idx)] == (val)) break;\
|
||||
}\
|
||||
if ((idx) == (v)->length) (idx) = -1;\
|
||||
} while (0)
|
||||
|
||||
|
||||
#define vec_remove(v, val)\
|
||||
do {\
|
||||
int idx__;\
|
||||
vec_find(v, val, idx__);\
|
||||
if (idx__ != -1) vec_splice(v, idx__, 1);\
|
||||
} while (0)
|
||||
|
||||
|
||||
#define vec_reverse(v)\
|
||||
do {\
|
||||
int i__ = (v)->length / 2;\
|
||||
while (i__--) {\
|
||||
vec_swap((v), i__, (v)->length - (i__ + 1));\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
|
||||
#define vec_foreach(v, var, iter)\
|
||||
if ( (v)->length > 0 )\
|
||||
for ( (iter) = 0;\
|
||||
(iter) < (v)->length && (((var) = (v)->data[(iter)]), 1);\
|
||||
++(iter))
|
||||
|
||||
|
||||
#define vec_foreach_rev(v, var, iter)\
|
||||
if ( (v)->length > 0 )\
|
||||
for ( (iter) = (v)->length - 1;\
|
||||
(iter) >= 0 && (((var) = (v)->data[(iter)]), 1);\
|
||||
--(iter))
|
||||
|
||||
|
||||
#define vec_foreach_ptr(v, var, iter)\
|
||||
if ( (v)->length > 0 )\
|
||||
for ( (iter) = 0;\
|
||||
(iter) < (v)->length && (((var) = &(v)->data[(iter)]), 1);\
|
||||
++(iter))
|
||||
|
||||
|
||||
#define vec_foreach_ptr_rev(v, var, iter)\
|
||||
if ( (v)->length > 0 )\
|
||||
for ( (iter) = (v)->length - 1;\
|
||||
(iter) >= 0 && (((var) = &(v)->data[(iter)]), 1);\
|
||||
--(iter))
|
||||
|
||||
|
||||
|
||||
int vec_expand_(char **data, int *length, int *capacity, int memsz);
|
||||
int vec_reserve_(char **data, int *length, int *capacity, int memsz, int n);
|
||||
int vec_reserve_po2_(char **data, int *length, int *capacity, int memsz,
|
||||
int n);
|
||||
int vec_compact_(char **data, int *length, int *capacity, int memsz);
|
||||
int vec_insert_(char **data, int *length, int *capacity, int memsz,
|
||||
int idx);
|
||||
void vec_splice_(char **data, int *length, int *capacity, int memsz,
|
||||
int start, int count);
|
||||
void vec_swapsplice_(char **data, int *length, int *capacity, int memsz,
|
||||
int start, int count);
|
||||
void vec_swap_(char **data, int *length, int *capacity, int memsz,
|
||||
int idx1, int idx2);
|
||||
|
||||
|
||||
typedef vec_t(void*) vec_void_t;
|
||||
typedef vec_t(char*) vec_str_t;
|
||||
typedef vec_t(int) vec_int_t;
|
||||
typedef vec_t(char) vec_char_t;
|
||||
typedef vec_t(float) vec_float_t;
|
||||
typedef vec_t(double) vec_double_t;
|
||||
|
||||
#endif
|
|
@ -1,10 +1,10 @@
|
|||
#include "audio/audio.h"
|
||||
#include "audio/source.h"
|
||||
#include "data/audioStream.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/maf.h"
|
||||
#include "core/ref.h"
|
||||
#include "util.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdlib.h>
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
|
@ -15,10 +15,10 @@ static struct {
|
|||
bool spatialized;
|
||||
ALCdevice* device;
|
||||
ALCcontext* context;
|
||||
vec_void_t sources;
|
||||
float LOVR_ALIGN(16) orientation[4];
|
||||
float LOVR_ALIGN(16) position[4];
|
||||
float LOVR_ALIGN(16) velocity[4];
|
||||
arr_t(Source*, 32) sources;
|
||||
} state;
|
||||
|
||||
ALenum lovrAudioConvertFormat(uint32_t bitDepth, uint32_t channelCount) {
|
||||
|
@ -58,7 +58,7 @@ bool lovrAudioInit() {
|
|||
|
||||
state.device = device;
|
||||
state.context = context;
|
||||
vec_init(&state.sources);
|
||||
arr_init(&state.sources);
|
||||
return state.initialized = true;
|
||||
}
|
||||
|
||||
|
@ -67,16 +67,17 @@ void lovrAudioDestroy() {
|
|||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(state.context);
|
||||
alcCloseDevice(state.device);
|
||||
for (int i = 0; i < state.sources.length; i++) {
|
||||
for (size_t i = 0; i < state.sources.length; i++) {
|
||||
lovrRelease(Source, state.sources.data[i]);
|
||||
}
|
||||
vec_deinit(&state.sources);
|
||||
arr_free(&state.sources);
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
void lovrAudioUpdate() {
|
||||
int i; Source* source;
|
||||
vec_foreach_rev(&state.sources, source, i) {
|
||||
for (size_t i = state.sources.length; i-- > 0;) {
|
||||
Source* source = state.sources.data[i];
|
||||
|
||||
if (lovrSourceGetType(source) == SOURCE_STATIC) {
|
||||
continue;
|
||||
}
|
||||
|
@ -95,7 +96,7 @@ void lovrAudioUpdate() {
|
|||
}
|
||||
} else if (isStopped) {
|
||||
lovrAudioStreamRewind(lovrSourceGetStream(source));
|
||||
vec_splice(&state.sources, i, 1);
|
||||
arr_splice(&state.sources, i, 1);
|
||||
lovrRelease(Source, source);
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +105,7 @@ void lovrAudioUpdate() {
|
|||
void lovrAudioAdd(Source* source) {
|
||||
if (!lovrAudioHas(source)) {
|
||||
lovrRetain(source);
|
||||
vec_push(&state.sources, source);
|
||||
arr_push(&state.sources, source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,9 +142,13 @@ float lovrAudioGetVolume() {
|
|||
}
|
||||
|
||||
bool lovrAudioHas(Source* source) {
|
||||
int index;
|
||||
vec_find(&state.sources, source, index);
|
||||
return index >= 0;
|
||||
for (size_t i = 0; i < state.sources.length; i++) {
|
||||
if (state.sources.data[i] == source) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lovrAudioIsSpatialized() {
|
||||
|
@ -151,23 +156,20 @@ bool lovrAudioIsSpatialized() {
|
|||
}
|
||||
|
||||
void lovrAudioPause() {
|
||||
int i; Source* source;
|
||||
vec_foreach(&state.sources, source, i) {
|
||||
lovrSourcePause(source);
|
||||
for (size_t i = 0; i < state.sources.length; i++) {
|
||||
lovrSourcePause(state.sources.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrAudioResume() {
|
||||
int i; Source* source;
|
||||
vec_foreach(&state.sources, source, i) {
|
||||
lovrSourceResume(source);
|
||||
for (size_t i = 0; i < state.sources.length; i++) {
|
||||
lovrSourceResume(state.sources.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void lovrAudioRewind() {
|
||||
int i; Source* source;
|
||||
vec_foreach(&state.sources, source, i) {
|
||||
lovrSourceRewind(source);
|
||||
for (size_t i = 0; i < state.sources.length; i++) {
|
||||
lovrSourceRewind(state.sources.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,8 +207,7 @@ void lovrAudioSetVolume(float volume) {
|
|||
}
|
||||
|
||||
void lovrAudioStop() {
|
||||
int i; Source* source;
|
||||
vec_foreach(&state.sources, source, i) {
|
||||
lovrSourceStop(source);
|
||||
for (size_t i = 0; i < state.sources.length; i++) {
|
||||
lovrSourceStop(state.sources.data[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,27 +2,27 @@
|
|||
#include "data/blob.h"
|
||||
#include "data/textureData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/maf.h"
|
||||
#include "core/ref.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
typedef vec_t(ModelMaterial) vec_material_t;
|
||||
|
||||
typedef struct {
|
||||
int material;
|
||||
int start;
|
||||
int count;
|
||||
} objGroup;
|
||||
|
||||
typedef vec_t(objGroup) vec_group_t;
|
||||
typedef arr_t(ModelMaterial, 1) arr_material_t;
|
||||
typedef arr_t(TextureData*, 1) arr_texturedata_t;
|
||||
typedef arr_t(objGroup, 1) arr_group_t;
|
||||
|
||||
#define STARTS_WITH(a, b) !strncmp(a, b, strlen(b))
|
||||
|
||||
static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials, map_int_t* names, char* base) {
|
||||
static void parseMtl(char* path, arr_texturedata_t* textures, arr_material_t* materials, map_int_t* names, char* base) {
|
||||
size_t length = 0;
|
||||
char* data = lovrFilesystemRead(path, -1, &length);
|
||||
lovrAssert(data && length > 0, "Unable to read mtl from '%s'", path);
|
||||
|
@ -36,18 +36,18 @@ static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials
|
|||
bool hasName = sscanf(s + 7, "%s\n%n", name, &lineLength);
|
||||
lovrAssert(hasName, "Bad OBJ: Expected a material name");
|
||||
map_set(names, name, materials->length);
|
||||
vec_push(materials, ((ModelMaterial) {
|
||||
arr_push(materials, ((ModelMaterial) {
|
||||
.scalars[SCALAR_METALNESS] = 1.f,
|
||||
.scalars[SCALAR_ROUGHNESS] = 1.f,
|
||||
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
|
||||
.colors[COLOR_EMISSIVE] = { 0.f, 0.f, 0.f, 0.f }
|
||||
}));
|
||||
memset(&vec_last(materials).textures, 0xff, MAX_MATERIAL_TEXTURES * sizeof(int));
|
||||
memset(&materials->data[materials->length - 1].textures, 0xff, MAX_MATERIAL_TEXTURES * sizeof(int));
|
||||
} else if (STARTS_WITH(s, "Kd")) {
|
||||
float r, g, b;
|
||||
int count = sscanf(s + 2, "%f %f %f\n%n", &r, &g, &b, &lineLength);
|
||||
lovrAssert(count == 3, "Bad OBJ: Expected 3 components for diffuse color");
|
||||
ModelMaterial* material = &vec_last(materials);
|
||||
ModelMaterial* material = &materials->data[materials->length - 1];
|
||||
material->colors[COLOR_DIFFUSE] = (Color) { r, g, b, 1.f };
|
||||
} else if (STARTS_WITH(s, "map_Kd")) {
|
||||
|
||||
|
@ -56,7 +56,7 @@ static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials
|
|||
bool hasFilename = sscanf(s + 7, "%s\n%n", filename, &lineLength);
|
||||
lovrAssert(hasFilename, "Bad OBJ: Expected a texture filename");
|
||||
char path[1024];
|
||||
snprintf(path, 1023, "%s%s", base, filename);
|
||||
snprintf(path, sizeof(path), "%s%s", base, filename);
|
||||
size_t size = 0;
|
||||
void* data = lovrFilesystemRead(path, -1, &size);
|
||||
lovrAssert(data && size > 0, "Unable to read texture from %s", path);
|
||||
|
@ -65,11 +65,11 @@ static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials
|
|||
// Load texture, assign to material
|
||||
TextureData* texture = lovrTextureDataCreateFromBlob(blob, true);
|
||||
lovrAssert(materials->length > 0, "Tried to set a material property without declaring a material first");
|
||||
ModelMaterial* material = &vec_last(materials);
|
||||
ModelMaterial* material = &materials->data[materials->length - 1];
|
||||
material->textures[TEXTURE_DIFFUSE] = textures->length;
|
||||
material->filters[TEXTURE_DIFFUSE].mode = FILTER_TRILINEAR;
|
||||
material->wraps[TEXTURE_DIFFUSE] = (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT };
|
||||
vec_push(textures, texture);
|
||||
arr_push(textures, texture);
|
||||
lovrRelease(Blob, blob);
|
||||
} else {
|
||||
char* newline = memchr(s, '\n', length);
|
||||
|
@ -92,29 +92,29 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
vec_group_t groups;
|
||||
vec_void_t textures;
|
||||
vec_material_t materials;
|
||||
arr_group_t groups;
|
||||
arr_texturedata_t textures;
|
||||
arr_material_t materials;
|
||||
map_int_t materialNames;
|
||||
vec_float_t vertexBlob;
|
||||
vec_int_t indexBlob;
|
||||
arr_t(float, 1) vertexBlob;
|
||||
arr_t(int, 1) indexBlob;
|
||||
map_int_t vertexMap;
|
||||
vec_float_t positions;
|
||||
vec_float_t normals;
|
||||
vec_float_t uvs;
|
||||
arr_t(float, 1) positions;
|
||||
arr_t(float, 1) normals;
|
||||
arr_t(float, 1) uvs;
|
||||
|
||||
vec_init(&groups);
|
||||
vec_init(&textures);
|
||||
vec_init(&materials);
|
||||
arr_init(&groups);
|
||||
arr_init(&textures);
|
||||
arr_init(&materials);
|
||||
map_init(&materialNames);
|
||||
vec_init(&vertexBlob);
|
||||
vec_init(&indexBlob);
|
||||
arr_init(&vertexBlob);
|
||||
arr_init(&indexBlob);
|
||||
map_init(&vertexMap);
|
||||
vec_init(&positions);
|
||||
vec_init(&normals);
|
||||
vec_init(&uvs);
|
||||
arr_init(&positions);
|
||||
arr_init(&normals);
|
||||
arr_init(&uvs);
|
||||
|
||||
vec_push(&groups, ((objGroup) { .material = -1 }));
|
||||
arr_push(&groups, ((objGroup) { .material = -1 }));
|
||||
|
||||
char base[1024];
|
||||
lovrAssert(strlen(source->name) < sizeof(base), "OBJ filename is too long");
|
||||
|
@ -130,17 +130,17 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
float x, y, z;
|
||||
int count = sscanf(data + 2, "%f %f %f\n%n", &x, &y, &z, &lineLength);
|
||||
lovrAssert(count == 3, "Bad OBJ: Expected 3 coordinates for vertex position");
|
||||
vec_pusharr(&positions, ((float[3]) { x, y, z }), 3);
|
||||
arr_append(&positions, ((float[3]) { x, y, z }), 3);
|
||||
} else if (STARTS_WITH(data, "vn ")) {
|
||||
float x, y, z;
|
||||
int count = sscanf(data + 3, "%f %f %f\n%n", &x, &y, &z, &lineLength);
|
||||
lovrAssert(count == 3, "Bad OBJ: Expected 3 coordinates for vertex normal");
|
||||
vec_pusharr(&normals, ((float[3]) { x, y, z }), 3);
|
||||
arr_append(&normals, ((float[3]) { x, y, z }), 3);
|
||||
} else if (STARTS_WITH(data, "vt ")) {
|
||||
float u, v;
|
||||
int count = sscanf(data + 3, "%f %f\n%n", &u, &v, &lineLength);
|
||||
lovrAssert(count == 2, "Bad OBJ: Expected 2 coordinates for texture coordinate");
|
||||
vec_pusharr(&uvs, ((float[2]) { u, v }), 2);
|
||||
arr_append(&uvs, ((float[2]) { u, v }), 2);
|
||||
} else if (STARTS_WITH(data, "f ")) {
|
||||
char* s = data + 2;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
@ -150,29 +150,29 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
*space = '\0'; // I'll be back
|
||||
int* index = map_get(&vertexMap, s);
|
||||
if (index) {
|
||||
vec_push(&indexBlob, *index);
|
||||
arr_push(&indexBlob, *index);
|
||||
} else {
|
||||
int v, vt, vn;
|
||||
int newIndex = vertexBlob.length / 8;
|
||||
vec_push(&indexBlob, newIndex);
|
||||
arr_push(&indexBlob, newIndex);
|
||||
map_set(&vertexMap, s, newIndex);
|
||||
|
||||
// Can be improved
|
||||
if (sscanf(s, "%d/%d/%d", &v, &vt, &vn) == 3) {
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
arr_append(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||
arr_append(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||
} else if (sscanf(s, "%d//%d", &v, &vn) == 2) {
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||
vec_pusharr(&vertexBlob, ((float[2]) { 0 }), 2);
|
||||
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
arr_append(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||
arr_append(&vertexBlob, ((float[2]) { 0 }), 2);
|
||||
} else if (sscanf(s, "%d/%d", &v, &vt) == 2) {
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, ((float[3]) { 0 }), 3);
|
||||
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
arr_append(&vertexBlob, ((float[3]) { 0 }), 3);
|
||||
arr_append(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||
} else if (sscanf(s, "%d", &v) == 1) {
|
||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
vec_pusharr(&vertexBlob, ((float[5]) { 0 }), 5);
|
||||
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||
arr_append(&vertexBlob, ((float[5]) { 0 }), 5);
|
||||
} else {
|
||||
lovrThrow("Bad OBJ: Unknown face format");
|
||||
}
|
||||
|
@ -181,14 +181,14 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
s = space + 1;
|
||||
}
|
||||
}
|
||||
vec_last(&groups).count += 3;
|
||||
groups.data[groups.length - 1].count += 3;
|
||||
lineLength = s - data;
|
||||
} else if (STARTS_WITH(data, "mtllib ")) {
|
||||
char filename[1024];
|
||||
bool hasName = sscanf(data + 7, "%1024s\n%n", filename, &lineLength);
|
||||
lovrAssert(hasName, "Bad OBJ: Expected filename after mtllib");
|
||||
char path[1024];
|
||||
snprintf(path, 1023, "%s%s", base, filename);
|
||||
snprintf(path, sizeof(path), "%s%s", base, filename);
|
||||
parseMtl(path, &textures, &materials, &materialNames, base);
|
||||
} else if (STARTS_WITH(data, "usemtl ")) {
|
||||
char name[128];
|
||||
|
@ -197,10 +197,10 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
lovrAssert(hasName, "Bad OBJ: Expected a material name");
|
||||
|
||||
// If the last group didn't have any faces, just reuse it, otherwise make a new group
|
||||
objGroup* group = &vec_last(&groups);
|
||||
objGroup* group = &groups.data[groups.length - 1];
|
||||
if (group->count > 0) {
|
||||
int start = group->start + group->count; // Don't put this in the compound literal (realloc)
|
||||
vec_push(&groups, ((objGroup) {
|
||||
arr_push(&groups, ((objGroup) {
|
||||
.material = material ? *material : -1,
|
||||
.start = start,
|
||||
.count = 0
|
||||
|
@ -276,7 +276,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
.components = 2
|
||||
};
|
||||
|
||||
for (int i = 0; i < groups.length; i++) {
|
||||
for (size_t i = 0; i < groups.length; i++) {
|
||||
objGroup* group = &groups.data[i];
|
||||
model->attributes[3 + i] = (ModelAttribute) {
|
||||
.buffer = 1,
|
||||
|
@ -287,7 +287,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
};
|
||||
}
|
||||
|
||||
for (int i = 0; i < groups.length; i++) {
|
||||
for (size_t i = 0; i < groups.length; i++) {
|
||||
objGroup* group = &groups.data[i];
|
||||
model->primitives[i] = (ModelPrimitive) {
|
||||
.mode = DRAW_TRIANGLES,
|
||||
|
@ -307,13 +307,13 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
.primitiveCount = groups.length
|
||||
};
|
||||
|
||||
vec_deinit(&groups);
|
||||
vec_deinit(&textures);
|
||||
vec_deinit(&materials);
|
||||
arr_free(&groups);
|
||||
arr_free(&textures);
|
||||
arr_free(&materials);
|
||||
map_deinit(&materialNames);
|
||||
map_deinit(&vertexMap);
|
||||
vec_deinit(&positions);
|
||||
vec_deinit(&normals);
|
||||
vec_deinit(&uvs);
|
||||
arr_free(&positions);
|
||||
arr_free(&normals);
|
||||
arr_free(&uvs);
|
||||
return model;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "lib/stb/stb_truetype.h"
|
||||
#include <msdfgen-c.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
Rasterizer* lovrRasterizerInit(Rasterizer* rasterizer, Blob* blob, float size) {
|
||||
|
|
|
@ -285,7 +285,8 @@ static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) {
|
|||
|
||||
uint32_t width = textureData->width = header->width;
|
||||
uint32_t height = textureData->height = header->height;
|
||||
uint32_t mipmapCount = MAX(header->mipMapCount, 1);
|
||||
uint32_t mipmapCount = textureData->mipmapCount = MAX(header->mipMapCount, 1);
|
||||
textureData->mipmaps = malloc(mipmapCount * sizeof(Mipmap));
|
||||
size_t blockBytes = 0;
|
||||
|
||||
switch (textureData->format) {
|
||||
|
@ -303,12 +304,11 @@ static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) {
|
|||
|
||||
// Overflow check
|
||||
if (mipmapSize == 0 || (offset + mipmapSize) > size) {
|
||||
vec_deinit(&textureData->mipmaps);
|
||||
free(textureData->mipmaps);
|
||||
return false;
|
||||
}
|
||||
|
||||
Mipmap mipmap = { .width = width, .height = height, .data = &data[offset], .size = mipmapSize };
|
||||
vec_push(&textureData->mipmaps, mipmap);
|
||||
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = &data[offset], .size = mipmapSize };
|
||||
offset += mipmapSize;
|
||||
width = MAX(width >> 1, 1);
|
||||
height = MAX(height >> 1, 1);
|
||||
|
@ -363,18 +363,12 @@ static bool parseKTX(uint8_t* bytes, size_t size, TextureData* textureData) {
|
|||
|
||||
uint32_t width = textureData->width = data.ktx->pixelWidth;
|
||||
uint32_t height = textureData->height = data.ktx->pixelHeight;
|
||||
uint32_t mipmapCount = data.ktx->numberOfMipmapLevels;
|
||||
vec_reserve(&textureData->mipmaps, mipmapCount);
|
||||
uint32_t mipmapCount = textureData->mipmapCount = data.ktx->numberOfMipmapLevels;
|
||||
textureData->mipmaps = malloc(mipmapCount * sizeof(Mipmap));
|
||||
|
||||
data.u8 += sizeof(KTXHeader) + data.ktx->bytesOfKeyValueData;
|
||||
for (uint32_t i = 0; i < mipmapCount; i++) {
|
||||
vec_push(&textureData->mipmaps, ((Mipmap) {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.data = data.u8 + sizeof(uint32_t),
|
||||
.size = *data.u32
|
||||
}));
|
||||
|
||||
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = data.u8 + sizeof(uint32_t), .size = *data.u32 };
|
||||
width = MAX(width >> 1, 1u);
|
||||
height = MAX(height >> 1, 1u);
|
||||
data.u8 = (uint8_t*) ALIGN(data.u8 + sizeof(uint32_t) + *data.u32 + 3, 4);
|
||||
|
@ -425,13 +419,13 @@ static bool parseASTC(uint8_t* bytes, size_t size, TextureData* textureData) {
|
|||
|
||||
textureData->width = data.astc->width[0] + (data.astc->width[1] << 8) + (data.astc->width[2] << 16);
|
||||
textureData->height = data.astc->height[0] + (data.astc->height[1] << 8) + (data.astc->height[2] << 16);
|
||||
|
||||
vec_push(&textureData->mipmaps, ((Mipmap) {
|
||||
textureData->mipmaps = malloc(sizeof(Mipmap));
|
||||
textureData->mipmaps[0] = (Mipmap) {
|
||||
.width = textureData->width,
|
||||
.height = textureData->height,
|
||||
.data = data.astc + 1,
|
||||
.size = size - sizeof(*data.astc)
|
||||
}));
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -448,13 +442,10 @@ TextureData* lovrTextureDataInit(TextureData* textureData, uint32_t width, uint3
|
|||
textureData->blob.data = malloc(size);
|
||||
lovrAssert(textureData->blob.data, "Out of memory");
|
||||
memset(textureData->blob.data, value, size);
|
||||
vec_init(&textureData->mipmaps);
|
||||
return textureData;
|
||||
}
|
||||
|
||||
TextureData* lovrTextureDataInitFromBlob(TextureData* textureData, Blob* blob, bool flip) {
|
||||
vec_init(&textureData->mipmaps);
|
||||
|
||||
if (parseDDS(blob->data, blob->size, textureData)) {
|
||||
textureData->source = blob;
|
||||
lovrRetain(blob);
|
||||
|
@ -488,6 +479,7 @@ TextureData* lovrTextureDataInitFromBlob(TextureData* textureData, Blob* blob, b
|
|||
|
||||
textureData->width = width;
|
||||
textureData->height = height;
|
||||
textureData->mipmapCount = 0;
|
||||
return textureData;
|
||||
}
|
||||
|
||||
|
@ -574,6 +566,6 @@ bool lovrTextureDataEncode(TextureData* textureData, const char* filename) {
|
|||
void lovrTextureDataDestroy(void* ref) {
|
||||
TextureData* textureData = ref;
|
||||
lovrRelease(Blob, textureData->source);
|
||||
vec_deinit(&textureData->mipmaps);
|
||||
free(textureData->mipmaps);
|
||||
lovrBlobDestroy(ref);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "data/blob.h"
|
||||
#include "util.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -48,15 +47,14 @@ typedef struct {
|
|||
void* data;
|
||||
} Mipmap;
|
||||
|
||||
typedef vec_t(Mipmap) vec_mipmap_t;
|
||||
|
||||
typedef struct TextureData {
|
||||
Blob blob;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
Blob* source;
|
||||
TextureFormat format;
|
||||
vec_mipmap_t mipmaps;
|
||||
Mipmap* mipmaps;
|
||||
uint32_t mipmapCount;
|
||||
} TextureData;
|
||||
|
||||
TextureData* lovrTextureDataInit(TextureData* textureData, uint32_t width, uint32_t height, uint8_t value, TextureFormat format);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include "event/event.h"
|
||||
#include "platform.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/ref.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct {
|
||||
bool initialized;
|
||||
vec_t(EventPump) pumps;
|
||||
vec_t(Event) events;
|
||||
arr_t(Event, 8) events;
|
||||
size_t head;
|
||||
} state;
|
||||
|
||||
void lovrVariantDestroy(Variant* variant) {
|
||||
|
@ -21,47 +21,35 @@ void lovrVariantDestroy(Variant* variant) {
|
|||
|
||||
bool lovrEventInit() {
|
||||
if (state.initialized) return false;
|
||||
vec_init(&state.pumps);
|
||||
vec_init(&state.events);
|
||||
lovrEventAddPump(lovrPlatformPollEvents);
|
||||
arr_init(&state.events);
|
||||
return state.initialized = true;
|
||||
}
|
||||
|
||||
void lovrEventDestroy() {
|
||||
if (!state.initialized) return;
|
||||
vec_deinit(&state.pumps);
|
||||
vec_deinit(&state.events);
|
||||
arr_free(&state.events);
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
void lovrEventAddPump(EventPump pump) {
|
||||
vec_push(&state.pumps, pump);
|
||||
}
|
||||
|
||||
void lovrEventRemovePump(EventPump pump) {
|
||||
vec_remove(&state.pumps, pump);
|
||||
}
|
||||
|
||||
void lovrEventPump() {
|
||||
int i; EventPump pump;
|
||||
vec_foreach(&state.pumps, pump, i) {
|
||||
pump();
|
||||
}
|
||||
lovrPlatformPollEvents();
|
||||
}
|
||||
|
||||
void lovrEventPush(Event event) {
|
||||
vec_insert(&state.events, 0, event);
|
||||
arr_push(&state.events, event);
|
||||
}
|
||||
|
||||
bool lovrEventPoll(Event* event) {
|
||||
if (state.events.length == 0) {
|
||||
if (state.head == state.events.length) {
|
||||
state.head = state.events.length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
*event = vec_pop(&state.events);
|
||||
*event = state.events.data[state.head++];
|
||||
return true;
|
||||
}
|
||||
|
||||
void lovrEventClear() {
|
||||
vec_clear(&state.events);
|
||||
arr_clear(&state.events);
|
||||
state.head = 0;
|
||||
}
|
||||
|
|
|
@ -70,14 +70,10 @@ typedef struct {
|
|||
EventData data;
|
||||
} Event;
|
||||
|
||||
typedef void (*EventPump)(void);
|
||||
|
||||
void lovrVariantDestroy(Variant* variant);
|
||||
|
||||
bool lovrEventInit(void);
|
||||
void lovrEventDestroy(void);
|
||||
void lovrEventAddPump(EventPump pump);
|
||||
void lovrEventRemovePump(EventPump pump);
|
||||
void lovrEventPump(void);
|
||||
void lovrEventPush(Event event);
|
||||
bool lovrEventPoll(Event* event);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
File* lovrFileInit(File* file ,const char* path) {
|
||||
file->path = path;
|
||||
file->handle = NULL;
|
||||
file->mode = 0;
|
||||
return file;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,13 +31,12 @@ const char lovrDirSep = '/';
|
|||
|
||||
static struct {
|
||||
bool initialized;
|
||||
bool fused;
|
||||
char* source;
|
||||
const char* identity;
|
||||
char* savePathRelative;
|
||||
char* savePathFull;
|
||||
bool isFused;
|
||||
char* requirePath[2];
|
||||
vec_str_t requirePattern[2];
|
||||
char requirePath[2][1024];
|
||||
} state;
|
||||
|
||||
bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot) {
|
||||
|
@ -52,16 +51,14 @@ bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* arg
|
|||
state.source = malloc(LOVR_PATH_MAX * sizeof(char));
|
||||
lovrAssert(state.source, "Out of memory");
|
||||
state.identity = NULL;
|
||||
state.isFused = true;
|
||||
vec_init(&state.requirePattern[0]);
|
||||
vec_init(&state.requirePattern[1]);
|
||||
state.fused = true;
|
||||
lovrFilesystemSetRequirePath("?.lua;?/init.lua;lua_modules/?.lua;lua_modules/?/init.lua;deps/?.lua;deps/?/init.lua");
|
||||
lovrFilesystemSetCRequirePath("??;lua_modules/??;deps/??");
|
||||
|
||||
// Try to mount either an archive fused to the executable or an archive from the command line
|
||||
lovrFilesystemGetExecutablePath(state.source, LOVR_PATH_MAX);
|
||||
if (!lovrFilesystemMount(state.source, NULL, 1, argRoot)) { // Attempt to load fused. If that fails...
|
||||
state.isFused = false;
|
||||
state.fused = false;
|
||||
|
||||
if (argGame) {
|
||||
strncpy(state.source, argGame, LOVR_PATH_MAX);
|
||||
|
@ -82,10 +79,6 @@ void lovrFilesystemDestroy() {
|
|||
free(state.source);
|
||||
free(state.savePathFull);
|
||||
free(state.savePathRelative);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
free(state.requirePath[i]);
|
||||
vec_deinit(&state.requirePattern[i]);
|
||||
}
|
||||
PHYSFS_deinit();
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
@ -151,12 +144,12 @@ const char* lovrFilesystemGetRealDirectory(const char* path) {
|
|||
return PHYSFS_getRealDir(path);
|
||||
}
|
||||
|
||||
vec_str_t* lovrFilesystemGetRequirePath() {
|
||||
return &state.requirePattern[0];
|
||||
const char* lovrFilesystemGetRequirePath() {
|
||||
return state.requirePath[0];
|
||||
}
|
||||
|
||||
vec_str_t* lovrFilesystemGetCRequirePath() {
|
||||
return &state.requirePattern[1];
|
||||
const char* lovrFilesystemGetCRequirePath() {
|
||||
return state.requirePath[1];
|
||||
}
|
||||
|
||||
const char* lovrFilesystemGetSaveDirectory() {
|
||||
|
@ -213,7 +206,7 @@ bool lovrFilesystemIsFile(const char* path) {
|
|||
}
|
||||
|
||||
bool lovrFilesystemIsFused() {
|
||||
return state.isFused;
|
||||
return state.fused;
|
||||
}
|
||||
|
||||
// Returns zero on success, nonzero on failure
|
||||
|
@ -227,7 +220,7 @@ bool lovrFilesystemMount(const char* path, const char* mountpoint, bool append,
|
|||
|
||||
void* lovrFilesystemRead(const char* path, size_t bytes, size_t* bytesRead) {
|
||||
File file;
|
||||
lovrFileInit(memset(&file, 0, sizeof(File)), path);
|
||||
lovrFileInit(&file, path);
|
||||
|
||||
if (!lovrFileOpen(&file, OPEN_READ)) {
|
||||
return NULL;
|
||||
|
@ -293,30 +286,12 @@ bool lovrFilesystemSetIdentity(const char* identity) {
|
|||
return PHYSFS_mount(state.savePathFull, NULL, 0);
|
||||
}
|
||||
|
||||
static void setRequirePath(int i, const char* requirePath) {
|
||||
if (state.requirePath[i]) {
|
||||
free(state.requirePath[i]);
|
||||
vec_clear(&state.requirePattern[i]);
|
||||
}
|
||||
|
||||
char* p = state.requirePath[i] = strdup(requirePath);
|
||||
|
||||
while (1) {
|
||||
vec_push(&state.requirePattern[i], p);
|
||||
if ((p = strchr(p, ';')) != NULL) {
|
||||
*p++ = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lovrFilesystemSetRequirePath(const char* requirePath) {
|
||||
setRequirePath(0, requirePath);
|
||||
strncpy(state.requirePath[0], requirePath, sizeof(state.requirePath[0]) - 1);
|
||||
}
|
||||
|
||||
void lovrFilesystemSetCRequirePath(const char* requirePath) {
|
||||
setRequirePath(1, requirePath);
|
||||
strncpy(state.requirePath[1], requirePath, sizeof(state.requirePath[1]) - 1);
|
||||
}
|
||||
|
||||
bool lovrFilesystemUnmount(const char* path) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "lib/vec/vec.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -19,8 +19,8 @@ int lovrFilesystemGetExecutablePath(char* path, uint32_t size);
|
|||
const char* lovrFilesystemGetIdentity(void);
|
||||
long lovrFilesystemGetLastModified(const char* path);
|
||||
const char* lovrFilesystemGetRealDirectory(const char* path);
|
||||
vec_str_t* lovrFilesystemGetRequirePath(void);
|
||||
vec_str_t* lovrFilesystemGetCRequirePath(void);
|
||||
const char* lovrFilesystemGetRequirePath();
|
||||
const char* lovrFilesystemGetCRequirePath();
|
||||
const char* lovrFilesystemGetSaveDirectory(void);
|
||||
size_t lovrFilesystemGetSize(const char* path);
|
||||
const char* lovrFilesystemGetSource(void);
|
||||
|
|
|
@ -13,12 +13,12 @@ Animator* lovrAnimatorInit(Animator* animator, ModelData* data) {
|
|||
lovrRetain(data);
|
||||
animator->data = data;
|
||||
map_init(&animator->animations);
|
||||
vec_init(&animator->tracks);
|
||||
vec_reserve(&animator->tracks, data->animationCount);
|
||||
arr_init(&animator->tracks);
|
||||
arr_reserve(&animator->tracks, data->animationCount);
|
||||
animator->speed = 1.f;
|
||||
|
||||
for (uint32_t i = 0; i < data->animationCount; i++) {
|
||||
vec_push(&animator->tracks, ((Track) {
|
||||
arr_push(&animator->tracks, ((Track) {
|
||||
.time = 0.f,
|
||||
.speed = 1.f,
|
||||
.alpha = 1.f,
|
||||
|
@ -38,12 +38,12 @@ Animator* lovrAnimatorInit(Animator* animator, ModelData* data) {
|
|||
void lovrAnimatorDestroy(void* ref) {
|
||||
Animator* animator = ref;
|
||||
lovrRelease(ModelData, animator->data);
|
||||
vec_deinit(&animator->tracks);
|
||||
arr_free(&animator->tracks);
|
||||
}
|
||||
|
||||
void lovrAnimatorReset(Animator* animator) {
|
||||
Track* track; int i;
|
||||
vec_foreach_ptr(&animator->tracks, track, i) {
|
||||
for (size_t i = 0; i < animator->tracks.length; i++) {
|
||||
Track* track = &animator->tracks.data[i];
|
||||
track->time = 0.f;
|
||||
track->speed = 1.f;
|
||||
track->playing = false;
|
||||
|
@ -53,8 +53,8 @@ void lovrAnimatorReset(Animator* animator) {
|
|||
}
|
||||
|
||||
void lovrAnimatorUpdate(Animator* animator, float dt) {
|
||||
Track* track; int i;
|
||||
vec_foreach_ptr(&animator->tracks, track, i) {
|
||||
for (size_t i = 0; i < animator->tracks.length; i++) {
|
||||
Track* track = &animator->tracks.data[i];
|
||||
if (track->playing) {
|
||||
track->time += dt * track->speed * animator->speed;
|
||||
float duration = animator->data->animations[i].duration;
|
||||
|
@ -247,7 +247,7 @@ int32_t lovrAnimatorGetPriority(Animator* animator, uint32_t animation) {
|
|||
void lovrAnimatorSetPriority(Animator* animator, uint32_t animation, int32_t priority) {
|
||||
Track* track = &animator->tracks.data[animation];
|
||||
track->priority = priority;
|
||||
vec_sort(&animator->tracks, trackSortCallback);
|
||||
qsort(animator->tracks.data, animator->tracks.length, sizeof(Track), trackSortCallback);
|
||||
}
|
||||
|
||||
float lovrAnimatorGetSpeed(Animator* animator, uint32_t animation) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "core/arr.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -16,12 +16,10 @@ typedef struct {
|
|||
bool looping;
|
||||
} Track;
|
||||
|
||||
typedef vec_t(Track) vec_track_t;
|
||||
|
||||
typedef struct Animator {
|
||||
struct ModelData* data;
|
||||
map_t(uint32_t) animations;
|
||||
vec_track_t tracks;
|
||||
arr_t(Track, 1) tracks;
|
||||
float speed;
|
||||
} Animator;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "graphics/font.h"
|
||||
#include "graphics/shader.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/maf.h"
|
||||
#include "util.h"
|
||||
#include "platform.h"
|
||||
|
@ -307,7 +308,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
int shaderSwitches;
|
||||
int drawCalls;
|
||||
vec_t(GpuTimer) timers;
|
||||
arr_t(GpuTimer, 4) timers;
|
||||
} GpuStats;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "data/modelData.h"
|
||||
#include "core/ref.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
@ -82,7 +81,7 @@ static struct {
|
|||
Image images[MAX_IMAGES];
|
||||
float viewports[2][4];
|
||||
uint32_t viewportCount;
|
||||
vec_void_t incoherents[MAX_BARRIERS];
|
||||
arr_t(void*, 2) incoherents[MAX_BARRIERS];
|
||||
map_t(TimerList) timers;
|
||||
GpuFeatures features;
|
||||
GpuLimits limits;
|
||||
|
@ -420,18 +419,18 @@ static void lovrGpuSync(uint8_t flags) {
|
|||
}
|
||||
|
||||
if (i == BARRIER_BLOCK) {
|
||||
for (int j = 0; j < state.incoherents[i].length; j++) {
|
||||
for (size_t j = 0; j < state.incoherents[i].length; j++) {
|
||||
Buffer* buffer = state.incoherents[i].data[j];
|
||||
buffer->incoherent &= ~(1 << i);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < state.incoherents[i].length; j++) {
|
||||
for (size_t j = 0; j < state.incoherents[i].length; j++) {
|
||||
Texture* texture = state.incoherents[i].data[j];
|
||||
texture->incoherent &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
vec_clear(&state.incoherents[i]);
|
||||
arr_clear(&state.incoherents[i]);
|
||||
|
||||
switch (i) {
|
||||
case BARRIER_BLOCK: bits |= GL_SHADER_STORAGE_BARRIER_BIT; break;
|
||||
|
@ -453,11 +452,11 @@ static void lovrGpuDestroySyncResource(void* resource, uint8_t incoherent) {
|
|||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_BARRIERS; i++) {
|
||||
for (uint32_t i = 0; i < MAX_BARRIERS; i++) {
|
||||
if (incoherent & (1 << i)) {
|
||||
for (int j = 0; j < state.incoherents[i].length; j++) {
|
||||
for (size_t j = 0; j < state.incoherents[i].length; j++) {
|
||||
if (state.incoherents[i].data[j] == resource) {
|
||||
vec_swapsplice(&state.incoherents[i], j, 1);
|
||||
arr_splice(&state.incoherents[i], j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -839,23 +838,21 @@ static void lovrGpuBindPipeline(Pipeline* pipeline) {
|
|||
}
|
||||
|
||||
static void lovrGpuBindShader(Shader* shader) {
|
||||
UniformBlock* block;
|
||||
Uniform* uniform;
|
||||
int i;
|
||||
|
||||
lovrGpuUseProgram(shader->program);
|
||||
|
||||
// Figure out if we need to wait for pending writes on resources to complete
|
||||
#ifndef LOVR_WEBGL
|
||||
uint8_t flags = 0;
|
||||
vec_foreach_ptr(&shader->blocks[BLOCK_COMPUTE], block, i) {
|
||||
for (size_t i = 0; i < shader->blocks[BLOCK_COMPUTE].length; i++) {
|
||||
UniformBlock* block = &shader->blocks[BLOCK_COMPUTE].data[i];
|
||||
if (block->source && (block->source->incoherent >> BARRIER_BLOCK) & 1) {
|
||||
flags |= 1 << BARRIER_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vec_foreach_ptr(&shader->uniforms, uniform, i) {
|
||||
for (size_t i = 0; i < shader->uniforms.length; i++) {
|
||||
Uniform* uniform = &shader->uniforms.data[i];
|
||||
if (uniform->type == UNIFORM_SAMPLER) {
|
||||
for (int i = 0; i < uniform->count; i++) {
|
||||
Texture* texture = uniform->value.textures[i];
|
||||
|
@ -883,7 +880,9 @@ static void lovrGpuBindShader(Shader* shader) {
|
|||
#endif
|
||||
|
||||
// Bind uniforms
|
||||
vec_foreach_ptr(&shader->uniforms, uniform, i) {
|
||||
for (size_t i = 0; i < shader->uniforms.length; i++) {
|
||||
Uniform* uniform = &shader->uniforms.data[i];
|
||||
|
||||
if (uniform->type != UNIFORM_SAMPLER && uniform->type != UNIFORM_IMAGE && !uniform->dirty) {
|
||||
continue;
|
||||
}
|
||||
|
@ -930,7 +929,7 @@ static void lovrGpuBindShader(Shader* shader) {
|
|||
if (texture && image->access != ACCESS_READ) {
|
||||
for (Barrier barrier = BARRIER_BLOCK + 1; barrier < MAX_BARRIERS; barrier++) {
|
||||
texture->incoherent |= 1 << barrier;
|
||||
vec_push(&state.incoherents[barrier], texture);
|
||||
arr_push(&state.incoherents[barrier], texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -951,11 +950,12 @@ static void lovrGpuBindShader(Shader* shader) {
|
|||
|
||||
// Bind uniform blocks
|
||||
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_COMPUTE; type++) {
|
||||
vec_foreach_ptr(&shader->blocks[type], block, i) {
|
||||
for (size_t i = 0; i < shader->blocks[type].length; i++) {
|
||||
UniformBlock* block = &shader->blocks[type].data[i];
|
||||
if (block->source) {
|
||||
if (type == BLOCK_COMPUTE && block->access != ACCESS_READ) {
|
||||
block->source->incoherent |= (1 << BARRIER_BLOCK);
|
||||
vec_push(&state.incoherents[BARRIER_BLOCK], block->source);
|
||||
arr_push(&state.incoherents[BARRIER_BLOCK], block->source);
|
||||
}
|
||||
|
||||
lovrBufferUnmap(block->source);
|
||||
|
@ -1059,7 +1059,7 @@ void lovrGpuInit(getProcAddressProc getProcAddress) {
|
|||
#endif
|
||||
|
||||
for (int i = 0; i < MAX_BARRIERS; i++) {
|
||||
vec_init(&state.incoherents[i]);
|
||||
arr_init(&state.incoherents[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1072,7 +1072,7 @@ void lovrGpuDestroy() {
|
|||
lovrRelease(Texture, state.images[i].texture);
|
||||
}
|
||||
for (int i = 0; i < MAX_BARRIERS; i++) {
|
||||
vec_deinit(&state.incoherents[i]);
|
||||
arr_free(&state.incoherents[i]);
|
||||
}
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
@ -1183,7 +1183,7 @@ void lovrGpuDraw(DrawCommand* draw) {
|
|||
|
||||
void lovrGpuPresent() {
|
||||
state.stats.drawCalls = state.stats.shaderSwitches = 0;
|
||||
vec_clear(&state.stats.timers);
|
||||
arr_clear(&state.stats.timers);
|
||||
#ifdef __APPLE__
|
||||
// For some reason instancing doesn't work on macOS unless you reset the shader every frame
|
||||
lovrGpuUseProgram(0);
|
||||
|
@ -1284,7 +1284,7 @@ void lovrGpuTock(const char* label) {
|
|||
}
|
||||
|
||||
glGetQueryObjectui64v(timer->timers[timer->oldest], GL_QUERY_RESULT, &timer->ns);
|
||||
vec_push(&state.stats.timers, ((GpuTimer) { .label = label, .time = timer->ns / 1e9 }));
|
||||
arr_push(&state.stats.timers, ((GpuTimer) { .label = label, .time = timer->ns / 1e9 }));
|
||||
timer->oldest = (timer->oldest + 1) % 4;
|
||||
}
|
||||
}
|
||||
|
@ -1445,16 +1445,16 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, uint32
|
|||
if (isTextureFormatCompressed(textureData->format)) {
|
||||
lovrAssert(width == maxWidth && height == maxHeight, "Compressed texture pixels must be fully replaced");
|
||||
lovrAssert(mipmap == 0, "Unable to replace a specific mipmap of a compressed texture");
|
||||
Mipmap m; int i;
|
||||
vec_foreach(&textureData->mipmaps, m, i) {
|
||||
for (uint32_t i = 0; i < textureData->mipmapCount; i++) {
|
||||
Mipmap* m = textureData->mipmaps + i;
|
||||
switch (texture->type) {
|
||||
case TEXTURE_2D:
|
||||
case TEXTURE_CUBE:
|
||||
glCompressedTexImage2D(binding, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
|
||||
glCompressedTexImage2D(binding, i, glInternalFormat, m->width, m->height, 0, m->size, m->data);
|
||||
break;
|
||||
case TEXTURE_ARRAY:
|
||||
case TEXTURE_VOLUME:
|
||||
glCompressedTexSubImage3D(binding, i, x, y, slice, m.width, m.height, 1, glInternalFormat, m.size, m.data);
|
||||
glCompressedTexSubImage3D(binding, i, x, y, slice, m->width, m->height, 1, glInternalFormat, m->size, m->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1795,42 +1795,42 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
|||
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount);
|
||||
lovrAssert(blockCount <= MAX_BLOCK_BUFFERS, "Shader has too many uniform blocks (%d) the max is %d", blockCount, MAX_BLOCK_BUFFERS);
|
||||
map_init(&shader->blockMap);
|
||||
vec_block_t* uniformBlocks = &shader->blocks[BLOCK_UNIFORM];
|
||||
vec_init(uniformBlocks);
|
||||
vec_reserve(uniformBlocks, blockCount);
|
||||
arr_block_t* uniformBlocks = &shader->blocks[BLOCK_UNIFORM];
|
||||
arr_init(uniformBlocks);
|
||||
arr_reserve(uniformBlocks, (size_t) blockCount);
|
||||
for (int i = 0; i < blockCount; i++) {
|
||||
UniformBlock block = { .slot = i, .source = NULL };
|
||||
glUniformBlockBinding(program, i, block.slot);
|
||||
vec_init(&block.uniforms);
|
||||
arr_init(&block.uniforms);
|
||||
|
||||
char name[LOVR_MAX_UNIFORM_LENGTH];
|
||||
glGetActiveUniformBlockName(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
|
||||
int blockId = (i << 1) + BLOCK_UNIFORM;
|
||||
map_set(&shader->blockMap, name, blockId);
|
||||
vec_push(uniformBlocks, block);
|
||||
arr_push(uniformBlocks, block);
|
||||
}
|
||||
|
||||
// Shader storage buffers and their buffer variables
|
||||
vec_block_t* computeBlocks = &shader->blocks[BLOCK_COMPUTE];
|
||||
vec_init(computeBlocks);
|
||||
arr_block_t* computeBlocks = &shader->blocks[BLOCK_COMPUTE];
|
||||
arr_init(computeBlocks);
|
||||
#ifndef LOVR_WEBGL
|
||||
if (GLAD_GL_ARB_shader_storage_buffer_object && GLAD_GL_ARB_program_interface_query) {
|
||||
|
||||
// Iterate over compute blocks, setting their binding and pushing them onto the block vector
|
||||
int computeBlockCount;
|
||||
int32_t computeBlockCount;
|
||||
glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &computeBlockCount);
|
||||
lovrAssert(computeBlockCount <= MAX_BLOCK_BUFFERS, "Shader has too many compute blocks (%d) the max is %d", computeBlockCount, MAX_BLOCK_BUFFERS);
|
||||
vec_reserve(computeBlocks, computeBlockCount);
|
||||
arr_reserve(computeBlocks, (size_t) computeBlockCount);
|
||||
for (int i = 0; i < computeBlockCount; i++) {
|
||||
UniformBlock block = { .slot = i, .source = NULL };
|
||||
glShaderStorageBlockBinding(program, i, block.slot);
|
||||
vec_init(&block.uniforms);
|
||||
arr_init(&block.uniforms);
|
||||
|
||||
char name[LOVR_MAX_UNIFORM_LENGTH];
|
||||
glGetProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
|
||||
int blockId = (i << 1) + BLOCK_COMPUTE;
|
||||
map_set(&shader->blockMap, name, blockId);
|
||||
vec_push(computeBlocks, block);
|
||||
arr_push(computeBlocks, block);
|
||||
}
|
||||
|
||||
// Iterate over buffer variables, pushing them onto the uniform list of the correct block
|
||||
|
@ -1854,7 +1854,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
|||
} else {
|
||||
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
|
||||
}
|
||||
vec_push(&computeBlocks->data[values[blockIndex]].uniforms, uniform);
|
||||
arr_push(&computeBlocks->data[values[blockIndex]].uniforms, uniform);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1864,7 +1864,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
|||
int textureSlot = 0;
|
||||
int imageSlot = 0;
|
||||
map_init(&shader->uniformMap);
|
||||
vec_init(&shader->uniforms);
|
||||
arr_init(&shader->uniforms);
|
||||
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount);
|
||||
for (uint32_t i = 0; i < (uint32_t) uniformCount; i++) {
|
||||
Uniform uniform;
|
||||
|
@ -1910,7 +1910,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
|||
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
|
||||
}
|
||||
|
||||
vec_push(&block->uniforms, uniform);
|
||||
arr_push(&block->uniforms, uniform);
|
||||
continue;
|
||||
} else if (uniform.location == -1) {
|
||||
continue;
|
||||
|
@ -1971,7 +1971,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
|||
}
|
||||
|
||||
map_set(&shader->uniformMap, uniform.name, shader->uniforms.length);
|
||||
vec_push(&shader->uniforms, uniform);
|
||||
arr_push(&shader->uniforms, uniform);
|
||||
textureSlot += uniform.type == UNIFORM_SAMPLER ? uniform.count : 0;
|
||||
imageSlot += uniform.type == UNIFORM_IMAGE ? uniform.count : 0;
|
||||
}
|
||||
|
@ -2115,18 +2115,17 @@ void lovrShaderDestroy(void* ref) {
|
|||
Shader* shader = ref;
|
||||
lovrGraphicsFlushShader(shader);
|
||||
glDeleteProgram(shader->program);
|
||||
for (int i = 0; i < shader->uniforms.length; i++) {
|
||||
for (size_t i = 0; i < shader->uniforms.length; i++) {
|
||||
free(shader->uniforms.data[i].value.data);
|
||||
}
|
||||
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_COMPUTE; type++) {
|
||||
UniformBlock* block; int i;
|
||||
vec_foreach_ptr(&shader->blocks[type], block, i) {
|
||||
lovrRelease(Buffer, block->source);
|
||||
for (size_t i = 0; i < shader->blocks[type].length; i++) {
|
||||
lovrRelease(Buffer, shader->blocks[type].data[i].source);
|
||||
}
|
||||
}
|
||||
vec_deinit(&shader->uniforms);
|
||||
vec_deinit(&shader->blocks[BLOCK_UNIFORM]);
|
||||
vec_deinit(&shader->blocks[BLOCK_COMPUTE]);
|
||||
arr_free(&shader->uniforms);
|
||||
arr_free(&shader->blocks[BLOCK_UNIFORM]);
|
||||
arr_free(&shader->blocks[BLOCK_COMPUTE]);
|
||||
map_deinit(&shader->attributes);
|
||||
map_deinit(&shader->uniformMap);
|
||||
map_deinit(&shader->blockMap);
|
||||
|
|
|
@ -159,11 +159,11 @@ void lovrShaderSetBlock(Shader* shader, const char* name, Buffer* buffer, size_t
|
|||
// ShaderBlock
|
||||
|
||||
// Calculates uniform size and byte offsets using std140 rules, returning the total buffer size
|
||||
size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms) {
|
||||
size_t lovrShaderComputeUniformLayout(arr_uniform_t* uniforms) {
|
||||
size_t size = 0;
|
||||
Uniform* uniform; int i;
|
||||
vec_foreach_ptr(uniforms, uniform, i) {
|
||||
for (size_t i = 0; i < uniforms->length; i++) {
|
||||
int align;
|
||||
Uniform* uniform = &uniforms->data[i];
|
||||
if (uniform->count > 1 || uniform->type == UNIFORM_MATRIX) {
|
||||
align = 16 * (uniform->type == UNIFORM_MATRIX ? uniform->components : 1);
|
||||
uniform->size = align * uniform->count;
|
||||
|
@ -177,14 +177,14 @@ size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms) {
|
|||
return size;
|
||||
}
|
||||
|
||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, vec_uniform_t* uniforms) {
|
||||
vec_init(&block->uniforms);
|
||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, arr_uniform_t* uniforms) {
|
||||
arr_init(&block->uniforms);
|
||||
map_init(&block->uniformMap);
|
||||
|
||||
Uniform* uniform; int i;
|
||||
vec_extend(&block->uniforms, uniforms);
|
||||
vec_foreach_ptr(&block->uniforms, uniform, i) {
|
||||
map_set(&block->uniformMap, uniform->name, i);
|
||||
arr_append(&block->uniforms, uniforms->data, uniforms->length);
|
||||
|
||||
for (size_t i = 0; i < block->uniforms.length; i++) {
|
||||
map_set(&block->uniformMap, block->uniforms.data[i].name, i);
|
||||
}
|
||||
|
||||
block->type = type;
|
||||
|
@ -196,7 +196,7 @@ ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buf
|
|||
void lovrShaderBlockDestroy(void* ref) {
|
||||
ShaderBlock* block = ref;
|
||||
lovrRelease(Buffer, block->buffer);
|
||||
vec_deinit(&block->uniforms);
|
||||
arr_free(&block->uniforms);
|
||||
map_deinit(&block->uniformMap);
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, si
|
|||
size += 1; // " "
|
||||
size += strlen(blockName);
|
||||
size += 3; // " {\n"
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
for (size_t i = 0; i < block->uniforms.length; i++) {
|
||||
size += tab;
|
||||
size += getUniformTypeLength(&block->uniforms.data[i]);
|
||||
size += 1; // " "
|
||||
|
@ -231,7 +231,7 @@ char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, si
|
|||
// Concatenate
|
||||
char* s = code;
|
||||
s += sprintf(s, "layout(std140) %s %s {\n", block->type == BLOCK_UNIFORM ? "uniform" : "buffer", blockName);
|
||||
for (int i = 0; i < block->uniforms.length; i++) {
|
||||
for (size_t i = 0; i < block->uniforms.length; i++) {
|
||||
const Uniform* uniform = &block->uniforms.data[i];
|
||||
if (uniform->count > 1) {
|
||||
s += sprintf(s, " %s %s[%d];\n", getUniformTypeName(uniform), uniform->name, uniform->count);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "graphics/texture.h"
|
||||
#include "graphics/opengl.h"
|
||||
#include "core/arr.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma once
|
||||
|
@ -89,17 +89,17 @@ typedef struct Uniform {
|
|||
bool dirty;
|
||||
} Uniform;
|
||||
|
||||
typedef vec_t(Uniform) vec_uniform_t;
|
||||
typedef arr_t(Uniform, 8) arr_uniform_t;
|
||||
|
||||
typedef struct {
|
||||
BlockType type;
|
||||
vec_uniform_t uniforms;
|
||||
arr_uniform_t uniforms;
|
||||
map_int_t uniformMap;
|
||||
struct Buffer* buffer;
|
||||
} ShaderBlock;
|
||||
|
||||
typedef struct {
|
||||
vec_uniform_t uniforms;
|
||||
arr_uniform_t uniforms;
|
||||
UniformAccess access;
|
||||
struct Buffer* source;
|
||||
size_t offset;
|
||||
|
@ -107,12 +107,12 @@ typedef struct {
|
|||
int slot;
|
||||
} UniformBlock;
|
||||
|
||||
typedef vec_t(UniformBlock) vec_block_t;
|
||||
typedef arr_t(UniformBlock, 1) arr_block_t;
|
||||
|
||||
typedef struct Shader {
|
||||
ShaderType type;
|
||||
vec_uniform_t uniforms;
|
||||
vec_block_t blocks[2];
|
||||
arr_uniform_t uniforms;
|
||||
arr_block_t blocks[2];
|
||||
map_int_t attributes;
|
||||
map_int_t uniformMap;
|
||||
map_int_t blockMap;
|
||||
|
@ -142,9 +142,9 @@ void lovrShaderSetBlock(Shader* shader, const char* name, struct Buffer* buffer,
|
|||
|
||||
// ShaderBlock
|
||||
|
||||
size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms);
|
||||
size_t lovrShaderComputeUniformLayout(arr_uniform_t* uniforms);
|
||||
|
||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, struct Buffer* buffer, vec_uniform_t* uniforms);
|
||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, struct Buffer* buffer, arr_uniform_t* uniforms);
|
||||
#define lovrShaderBlockCreate(...) lovrShaderBlockInit(lovrAlloc(ShaderBlock), __VA_ARGS__)
|
||||
void lovrShaderBlockDestroy(void* ref);
|
||||
BlockType lovrShaderBlockGetType(ShaderBlock* block);
|
||||
|
|
|
@ -86,7 +86,7 @@ static struct {
|
|||
RenderModel_t* deviceModels[16];
|
||||
RenderModel_TextureMap_t* deviceTextures[16];
|
||||
Canvas* canvas;
|
||||
vec_float_t boundsGeometry;
|
||||
float boundsGeometry[16];
|
||||
float clipNear;
|
||||
float clipFar;
|
||||
float offset;
|
||||
|
@ -205,7 +205,6 @@ static bool openvr_init(float offset, uint32_t msaa) {
|
|||
state.offset = state.compositor->GetTrackingSpace() == ETrackingUniverseOrigin_TrackingUniverseStanding ? 0. : offset;
|
||||
state.msaa = msaa;
|
||||
|
||||
vec_init(&state.boundsGeometry);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -221,7 +220,6 @@ static void openvr_destroy(void) {
|
|||
state.deviceModels[i] = NULL;
|
||||
state.deviceTextures[i] = NULL;
|
||||
}
|
||||
vec_deinit(&state.boundsGeometry);
|
||||
VR_ShutdownInternal();
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
@ -272,16 +270,13 @@ static void openvr_getBoundsDimensions(float* width, float* depth) {
|
|||
static const float* openvr_getBoundsGeometry(uint32_t* count) {
|
||||
struct HmdQuad_t quad;
|
||||
if (state.chaperone->GetPlayAreaRect(&quad)) {
|
||||
vec_clear(&state.boundsGeometry);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vec_push(&state.boundsGeometry, quad.vCorners[i].v[0]);
|
||||
vec_push(&state.boundsGeometry, quad.vCorners[i].v[1]);
|
||||
vec_push(&state.boundsGeometry, quad.vCorners[i].v[2]);
|
||||
state.boundsGeometry[4 * i + 0] = quad.vCorners[i].v[0];
|
||||
state.boundsGeometry[4 * i + 1] = quad.vCorners[i].v[1];
|
||||
state.boundsGeometry[4 * i + 2] = quad.vCorners[i].v[2];
|
||||
}
|
||||
|
||||
*count = state.boundsGeometry.length;
|
||||
return state.boundsGeometry.data;
|
||||
return *count = 16, state.boundsGeometry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <math.h>
|
||||
|
||||
// Explicit curve evaluation, unroll simple cases to avoid pow overhead
|
||||
static void evaluate(float* P, int n, float t, vec3 p) {
|
||||
static void evaluate(float* P, size_t n, float t, vec3 p) {
|
||||
if (n == 2) {
|
||||
p[0] = P[0] + (P[4] - P[0]) * t;
|
||||
p[1] = P[1] + (P[5] - P[1]) * t;
|
||||
|
@ -32,7 +32,7 @@ static void evaluate(float* P, int n, float t, vec3 p) {
|
|||
} else {
|
||||
float b = 1.f;
|
||||
p[0] = p[1] = p[2] = p[3] = 0.f;
|
||||
for (int i = 0; i < n; i++, b *= (float) (n - i) / i) {
|
||||
for (size_t i = 0; i < n; i++, b *= (float) (n - i) / i) {
|
||||
float c1 = powf(1 - t, n - (i + 1));
|
||||
float c2 = powf(t, i);
|
||||
p[0] += b * c1 * c2 * P[i * 4 + 0];
|
||||
|
@ -43,15 +43,14 @@ static void evaluate(float* P, int n, float t, vec3 p) {
|
|||
}
|
||||
}
|
||||
|
||||
Curve* lovrCurveInit(Curve* curve, int sizeHint) {
|
||||
vec_init(&curve->points);
|
||||
lovrAssert(!vec_reserve(&curve->points, sizeHint * 4), "Out of memory");
|
||||
Curve* lovrCurveInit(Curve* curve) {
|
||||
arr_init(&curve->points);
|
||||
return curve;
|
||||
}
|
||||
|
||||
void lovrCurveDestroy(void* ref) {
|
||||
Curve* curve = ref;
|
||||
vec_deinit(&curve->points);
|
||||
arr_free(&curve->points);
|
||||
}
|
||||
|
||||
void lovrCurveEvaluate(Curve* curve, float t, vec3 p) {
|
||||
|
@ -62,18 +61,18 @@ void lovrCurveEvaluate(Curve* curve, float t, vec3 p) {
|
|||
|
||||
void lovrCurveGetTangent(Curve* curve, float t, vec3 p) {
|
||||
float q[4];
|
||||
int n = curve->points.length / 4;
|
||||
size_t n = curve->points.length / 4;
|
||||
evaluate(curve->points.data, n - 1, t, q);
|
||||
evaluate(curve->points.data + 4, n - 1, t, p);
|
||||
vec3_add(p, vec3_scale(q, -1.f));
|
||||
vec3_normalize(p);
|
||||
}
|
||||
|
||||
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, int n) {
|
||||
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, uint32_t n) {
|
||||
lovrAssert(curve->points.length >= 8, "Need at least 2 points to render a Curve");
|
||||
lovrAssert(t1 >= 0.f && t2 <= 1.f, "Curve render interval must be within [0, 1]");
|
||||
float step = 1.f / (n - 1);
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
evaluate(curve->points.data, curve->points.length / 4, t1 + (t2 - t1) * i * step, points + 4 * i);
|
||||
}
|
||||
}
|
||||
|
@ -82,13 +81,14 @@ Curve* lovrCurveSlice(Curve* curve, float t1, float t2) {
|
|||
lovrAssert(curve->points.length >= 8, "Need at least 2 points to slice a Curve");
|
||||
lovrAssert(t1 >= 0.f && t2 <= 1.f, "Curve slice interval must be within [0, 1]");
|
||||
|
||||
Curve* new = lovrCurveCreate(curve->points.length / 4);
|
||||
Curve* new = lovrCurveCreate();
|
||||
arr_reserve(&new->points, curve->points.length);
|
||||
new->points.length = curve->points.length;
|
||||
|
||||
int n = curve->points.length / 4;
|
||||
size_t n = curve->points.length / 4;
|
||||
|
||||
// Right half of split at t1
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
for (size_t i = 0; i < n - 1; i++) {
|
||||
evaluate(curve->points.data + 4 * i, n - i, t1, new->points.data + 4 * i);
|
||||
}
|
||||
|
||||
|
@ -96,29 +96,29 @@ Curve* lovrCurveSlice(Curve* curve, float t1, float t2) {
|
|||
|
||||
// Split segment at t2, taking left half
|
||||
float t = (t2 - t1) / (1.f - t1);
|
||||
for (int i = n - 1; i >= 1; i--) {
|
||||
for (size_t i = n - 1; i >= 1; i--) {
|
||||
evaluate(new->points.data, i + 1, t, new->points.data + 4 * i);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
int lovrCurveGetPointCount(Curve* curve) {
|
||||
size_t lovrCurveGetPointCount(Curve* curve) {
|
||||
return curve->points.length / 4;
|
||||
}
|
||||
|
||||
void lovrCurveGetPoint(Curve* curve, int index, vec3 point) {
|
||||
void lovrCurveGetPoint(Curve* curve, size_t index, vec3 point) {
|
||||
vec3_init(point, curve->points.data + 4 * index);
|
||||
}
|
||||
|
||||
void lovrCurveSetPoint(Curve* curve, int index, vec3 point) {
|
||||
void lovrCurveSetPoint(Curve* curve, size_t index, vec3 point) {
|
||||
vec3_init(curve->points.data + 4 * index, point);
|
||||
}
|
||||
|
||||
void lovrCurveAddPoint(Curve* curve, vec3 point, int index) {
|
||||
void lovrCurveAddPoint(Curve* curve, vec3 point, size_t index) {
|
||||
|
||||
// Reserve enough memory for 4 more floats, then record destination once memory is allocated
|
||||
lovrAssert(!vec_reserve(&curve->points, curve->points.length + 4), "Out of memory");
|
||||
arr_reserve(&curve->points, curve->points.length + 4);
|
||||
float* dest = curve->points.data + index * 4;
|
||||
|
||||
// Shift remaining points over (if any) to create empty space
|
||||
|
@ -131,6 +131,6 @@ void lovrCurveAddPoint(Curve* curve, vec3 point, int index) {
|
|||
memcpy(dest, point, 4 * sizeof(float));
|
||||
}
|
||||
|
||||
void lovrCurveRemovePoint(Curve* curve, int index) {
|
||||
vec_swapsplice(&curve->points, index * 4, 4);
|
||||
void lovrCurveRemovePoint(Curve* curve, size_t index) {
|
||||
arr_splice(&curve->points, index * 4, 4);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#include "core/arr.h"
|
||||
#include "core/maf.h"
|
||||
#include "lib/vec/vec.h"
|
||||
|
||||
typedef struct {
|
||||
vec_float_t points;
|
||||
arr_t(float, 16) points;
|
||||
} Curve;
|
||||
|
||||
Curve* lovrCurveInit(Curve* curve, int sizeHint);
|
||||
#define lovrCurveCreate(...) lovrCurveInit(lovrAlloc(Curve), __VA_ARGS__)
|
||||
Curve* lovrCurveInit(Curve* curve);
|
||||
#define lovrCurveCreate(...) lovrCurveInit(lovrAlloc(Curve))
|
||||
void lovrCurveDestroy(void* ref);
|
||||
void lovrCurveEvaluate(Curve* curve, float t, vec3 point);
|
||||
void lovrCurveGetTangent(Curve* curve, float t, vec3 point);
|
||||
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, int n);
|
||||
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, uint32_t n);
|
||||
Curve* lovrCurveSlice(Curve* curve, float t1, float t2);
|
||||
int lovrCurveGetPointCount(Curve* curve);
|
||||
void lovrCurveGetPoint(Curve* curve, int index, vec3 point);
|
||||
void lovrCurveSetPoint(Curve* curve, int index, vec3 point);
|
||||
void lovrCurveAddPoint(Curve* curve, vec3 point, int index);
|
||||
void lovrCurveRemovePoint(Curve* curve, int index);
|
||||
size_t lovrCurveGetPointCount(Curve* curve);
|
||||
void lovrCurveGetPoint(Curve* curve, size_t index, vec3 point);
|
||||
void lovrCurveSetPoint(Curve* curve, size_t index, vec3 point);
|
||||
void lovrCurveAddPoint(Curve* curve, vec3 point, size_t index);
|
||||
void lovrCurveRemovePoint(Curve* curve, size_t index);
|
||||
|
|
|
@ -11,8 +11,8 @@ static void defaultNearCallback(void* data, dGeomID a, dGeomID b) {
|
|||
|
||||
static void customNearCallback(void* data, dGeomID shapeA, dGeomID shapeB) {
|
||||
World* world = data;
|
||||
vec_push(&world->overlaps, dGeomGetData(shapeA));
|
||||
vec_push(&world->overlaps, dGeomGetData(shapeB));
|
||||
arr_push(&world->overlaps, dGeomGetData(shapeA));
|
||||
arr_push(&world->overlaps, dGeomGetData(shapeB));
|
||||
}
|
||||
|
||||
static void raycastCallback(void* data, dGeomID a, dGeomID b) {
|
||||
|
@ -50,7 +50,7 @@ World* lovrWorldInit(World* world, float xg, float yg, float zg, bool allowSleep
|
|||
world->space = dHashSpaceCreate(0);
|
||||
dHashSpaceSetLevels(world->space, -4, 8);
|
||||
world->contactGroup = dJointGroupCreate(0);
|
||||
vec_init(&world->overlaps);
|
||||
arr_init(&world->overlaps);
|
||||
lovrWorldSetGravity(world, xg, yg, zg);
|
||||
lovrWorldSetSleepingAllowed(world, allowSleep);
|
||||
map_init(&world->tags);
|
||||
|
@ -68,7 +68,7 @@ World* lovrWorldInit(World* world, float xg, float yg, float zg, bool allowSleep
|
|||
void lovrWorldDestroy(void* ref) {
|
||||
World* world = ref;
|
||||
lovrWorldDestroyData(world);
|
||||
vec_deinit(&world->overlaps);
|
||||
arr_free(&world->overlaps);
|
||||
map_deinit(&world->tags);
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* u
|
|||
}
|
||||
|
||||
void lovrWorldComputeOverlaps(World* world) {
|
||||
vec_clear(&world->overlaps);
|
||||
arr_clear(&world->overlaps);
|
||||
dSpaceCollide(world->space, world, customNearCallback);
|
||||
}
|
||||
|
||||
|
@ -120,8 +120,8 @@ int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
*a = vec_pop(&world->overlaps);
|
||||
*b = vec_pop(&world->overlaps);
|
||||
*a = arr_pop(&world->overlaps);
|
||||
*b = arr_pop(&world->overlaps);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -278,8 +278,8 @@ Collider* lovrColliderInit(Collider* collider, World* world, float x, float y, f
|
|||
collider->restitution = 0;
|
||||
collider->tag = NO_TAG;
|
||||
dBodySetData(collider->body, collider);
|
||||
vec_init(&collider->shapes);
|
||||
vec_init(&collider->joints);
|
||||
arr_init(&collider->shapes);
|
||||
arr_init(&collider->joints);
|
||||
|
||||
lovrColliderSetPosition(collider, x, y, z);
|
||||
|
||||
|
@ -300,8 +300,8 @@ Collider* lovrColliderInit(Collider* collider, World* world, float x, float y, f
|
|||
void lovrColliderDestroy(void* ref) {
|
||||
Collider* collider = ref;
|
||||
lovrColliderDestroyData(collider);
|
||||
vec_deinit(&collider->shapes);
|
||||
vec_deinit(&collider->joints);
|
||||
arr_free(&collider->shapes);
|
||||
arr_free(&collider->joints);
|
||||
}
|
||||
|
||||
void lovrColliderDestroyData(Collider* collider) {
|
||||
|
@ -309,16 +309,16 @@ void lovrColliderDestroyData(Collider* collider) {
|
|||
return;
|
||||
}
|
||||
|
||||
vec_void_t* shapes = lovrColliderGetShapes(collider);
|
||||
Shape* shape; int i;
|
||||
vec_foreach(shapes, shape, i) {
|
||||
lovrColliderRemoveShape(collider, shape);
|
||||
size_t count;
|
||||
|
||||
Shape** shapes = lovrColliderGetShapes(collider, &count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
lovrColliderRemoveShape(collider, shapes[i]);
|
||||
}
|
||||
|
||||
vec_void_t* joints = lovrColliderGetJoints(collider);
|
||||
Joint* joint; int j;
|
||||
vec_foreach(joints, joint, j) {
|
||||
lovrRelease(Joint, joint);
|
||||
Joint** joints = lovrColliderGetJoints(collider, &count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
lovrRelease(Joint, joints[i]);
|
||||
}
|
||||
|
||||
dBodyDestroy(collider->body);
|
||||
|
@ -359,27 +359,27 @@ void lovrColliderRemoveShape(Collider* collider, Shape* shape) {
|
|||
}
|
||||
}
|
||||
|
||||
vec_void_t* lovrColliderGetShapes(Collider* collider) {
|
||||
vec_clear(&collider->shapes);
|
||||
Shape** lovrColliderGetShapes(Collider* collider, size_t* count) {
|
||||
arr_clear(&collider->shapes);
|
||||
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) {
|
||||
Shape* shape = dGeomGetData(geom);
|
||||
if (shape) {
|
||||
vec_push(&collider->shapes, shape);
|
||||
arr_push(&collider->shapes, shape);
|
||||
}
|
||||
}
|
||||
return &collider->shapes;
|
||||
return *count = collider->shapes.length, collider->shapes.data;
|
||||
}
|
||||
|
||||
vec_void_t* lovrColliderGetJoints(Collider* collider) {
|
||||
vec_clear(&collider->joints);
|
||||
Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
|
||||
arr_clear(&collider->joints);
|
||||
int jointCount = dBodyGetNumJoints(collider->body);
|
||||
for (int i = 0; i < jointCount; i++) {
|
||||
Joint* joint = dJointGetData(dBodyGetJoint(collider->body, i));
|
||||
if (joint) {
|
||||
vec_push(&collider->joints, joint);
|
||||
arr_push(&collider->joints, joint);
|
||||
}
|
||||
}
|
||||
return &collider->joints;
|
||||
return *count = collider->joints.length, collider->joints.data;
|
||||
}
|
||||
|
||||
void* lovrColliderGetUserData(Collider* collider) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "lib/vec/vec.h"
|
||||
#include "core/arr.h"
|
||||
#include "lib/map/map.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -25,12 +25,14 @@ typedef enum {
|
|||
} JointType;
|
||||
|
||||
typedef struct Collider Collider;
|
||||
typedef struct Shape Shape;
|
||||
typedef struct Joint Joint;
|
||||
|
||||
typedef struct {
|
||||
dWorldID id;
|
||||
dSpaceID space;
|
||||
dJointGroupID contactGroup;
|
||||
vec_void_t overlaps;
|
||||
arr_t(Shape*, 8) overlaps;
|
||||
map_int_t tags;
|
||||
uint16_t masks[MAX_TAGS];
|
||||
Collider* head;
|
||||
|
@ -43,29 +45,29 @@ struct Collider {
|
|||
Collider* next;
|
||||
void* userdata;
|
||||
int tag;
|
||||
vec_void_t shapes;
|
||||
vec_void_t joints;
|
||||
arr_t(Shape*, 2) shapes;
|
||||
arr_t(Joint*, 2) joints;
|
||||
float friction;
|
||||
float restitution;
|
||||
};
|
||||
|
||||
typedef struct Shape {
|
||||
struct Shape {
|
||||
ShapeType type;
|
||||
dGeomID id;
|
||||
Collider* collider;
|
||||
void* userdata;
|
||||
} Shape;
|
||||
};
|
||||
|
||||
typedef Shape SphereShape;
|
||||
typedef Shape BoxShape;
|
||||
typedef Shape CapsuleShape;
|
||||
typedef Shape CylinderShape;
|
||||
|
||||
typedef struct Joint {
|
||||
struct Joint {
|
||||
JointType type;
|
||||
dJointID id;
|
||||
void* userdata;
|
||||
} Joint;
|
||||
};
|
||||
|
||||
typedef Joint BallJoint;
|
||||
typedef Joint DistanceJoint;
|
||||
|
@ -112,8 +114,8 @@ void lovrColliderDestroyData(Collider* collider);
|
|||
World* lovrColliderGetWorld(Collider* collider);
|
||||
void lovrColliderAddShape(Collider* collider, Shape* shape);
|
||||
void lovrColliderRemoveShape(Collider* collider, Shape* shape);
|
||||
vec_void_t* lovrColliderGetShapes(Collider* collider);
|
||||
vec_void_t* lovrColliderGetJoints(Collider* collider);
|
||||
Shape** lovrColliderGetShapes(Collider* collider, size_t* count);
|
||||
Joint** lovrColliderGetJoints(Collider* collider, size_t* count);
|
||||
void* lovrColliderGetUserData(Collider* collider);
|
||||
void lovrColliderSetUserData(Collider* collider, void* data);
|
||||
const char* lovrColliderGetTag(Collider* collider);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <math.h>
|
||||
|
||||
Channel* lovrChannelInit(Channel* channel) {
|
||||
vec_init(&channel->messages);
|
||||
arr_init(&channel->messages);
|
||||
mtx_init(&channel->lock, mtx_plain | mtx_timed);
|
||||
cnd_init(&channel->cond);
|
||||
return channel;
|
||||
|
@ -14,7 +14,7 @@ Channel* lovrChannelInit(Channel* channel) {
|
|||
void lovrChannelDestroy(void* ref) {
|
||||
Channel* channel = ref;
|
||||
lovrChannelClear(channel);
|
||||
vec_deinit(&channel->messages);
|
||||
arr_free(&channel->messages);
|
||||
mtx_destroy(&channel->lock);
|
||||
cnd_destroy(&channel->cond);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ bool lovrChannelPush(Channel* channel, Variant variant, double timeout, uint64_t
|
|||
if (channel->messages.length == 0) {
|
||||
lovrRetain(channel);
|
||||
}
|
||||
vec_insert(&channel->messages, 0, variant);
|
||||
arr_push(&channel->messages, variant);
|
||||
*id = ++channel->sent;
|
||||
cnd_broadcast(&channel->cond);
|
||||
|
||||
|
@ -47,7 +47,7 @@ bool lovrChannelPush(Channel* channel, Variant variant, double timeout, uint64_t
|
|||
until.tv_nsec = start.tv_nsec + fraction * 1e9;
|
||||
cnd_timedwait(&channel->cond, &channel->lock, &until);
|
||||
timespec_get(&stop, TIME_UTC);
|
||||
timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / (double) 1e9;
|
||||
timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,9 +60,10 @@ bool lovrChannelPop(Channel* channel, Variant* variant, double timeout) {
|
|||
mtx_lock(&channel->lock);
|
||||
|
||||
do {
|
||||
if (channel->messages.length > 0) {
|
||||
*variant = vec_pop(&channel->messages);
|
||||
if (channel->messages.length == 0) {
|
||||
if (channel->head < channel->messages.length) {
|
||||
*variant = channel->messages.data[channel->head++];
|
||||
if (channel->head == channel->messages.length) {
|
||||
channel->head = channel->messages.length = 0;
|
||||
lovrRelease(Channel, channel);
|
||||
}
|
||||
channel->received++;
|
||||
|
@ -89,14 +90,14 @@ bool lovrChannelPop(Channel* channel, Variant* variant, double timeout) {
|
|||
timespec_get(&stop, TIME_UTC);
|
||||
timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / (double) 1e9;
|
||||
}
|
||||
} while (true);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
bool lovrChannelPeek(Channel* channel, Variant* variant) {
|
||||
mtx_lock(&channel->lock);
|
||||
|
||||
if (channel->messages.length > 0) {
|
||||
*variant = vec_last(&channel->messages);
|
||||
if (channel->head < channel->messages.length) {
|
||||
*variant = channel->messages.data[channel->head];
|
||||
mtx_unlock(&channel->lock);
|
||||
return true;
|
||||
}
|
||||
|
@ -107,18 +108,19 @@ bool lovrChannelPeek(Channel* channel, Variant* variant) {
|
|||
|
||||
void lovrChannelClear(Channel* channel) {
|
||||
mtx_lock(&channel->lock);
|
||||
for (int i = 0; i < channel->messages.length; i++) {
|
||||
for (size_t i = channel->head; i < channel->messages.length; i++) {
|
||||
lovrVariantDestroy(&channel->messages.data[i]);
|
||||
}
|
||||
channel->received = channel->sent;
|
||||
vec_clear(&channel->messages);
|
||||
arr_clear(&channel->messages);
|
||||
channel->head = 0;
|
||||
cnd_broadcast(&channel->cond);
|
||||
mtx_unlock(&channel->lock);
|
||||
}
|
||||
|
||||
uint64_t lovrChannelGetCount(Channel* channel) {
|
||||
mtx_lock(&channel->lock);
|
||||
uint64_t length = channel->messages.length;
|
||||
uint64_t length = channel->messages.length - channel->head;
|
||||
mtx_unlock(&channel->lock);
|
||||
return length;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
#include "event/event.h"
|
||||
#include "core/arr.h"
|
||||
#include "lib/tinycthread/tinycthread.h"
|
||||
#include "lib/vec/vec.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct Channel {
|
||||
mtx_t lock;
|
||||
cnd_t cond;
|
||||
vec_t(Variant) messages;
|
||||
arr_t(Variant, 1) messages;
|
||||
size_t head;
|
||||
uint64_t sent;
|
||||
uint64_t received;
|
||||
} Channel;
|
||||
|
|
Loading…
Reference in New Issue