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
|
set(LOVR_SRC
|
||||||
src/main.c
|
src/main.c
|
||||||
|
src/core/arr.c
|
||||||
src/core/luax.c
|
src/core/luax.c
|
||||||
src/core/maf.c
|
src/core/maf.c
|
||||||
src/core/platform.c
|
src/core/platform.c
|
||||||
|
@ -324,7 +325,6 @@ set(LOVR_SRC
|
||||||
src/core/util.c
|
src/core/util.c
|
||||||
src/api/l_lovr.c
|
src/api/l_lovr.c
|
||||||
src/lib/map/map.c
|
src/lib/map/map.c
|
||||||
src/lib/vec/vec.c
|
|
||||||
src/lib/sds/sds.c
|
src/lib/sds/sds.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,11 @@ static int l_lovrColliderRemoveShape(lua_State* L) {
|
||||||
|
|
||||||
static int l_lovrColliderGetShapes(lua_State* L) {
|
static int l_lovrColliderGetShapes(lua_State* L) {
|
||||||
Collider* collider = luax_checktype(L, 1, Collider);
|
Collider* collider = luax_checktype(L, 1, Collider);
|
||||||
lua_newtable(L);
|
size_t count;
|
||||||
vec_void_t* shapes = lovrColliderGetShapes(collider);
|
Shape** shapes = lovrColliderGetShapes(collider, &count);
|
||||||
for (int i = 0; i < shapes->length; i++) {
|
lua_createtable(L, count, 0);
|
||||||
luax_pushshape(L, shapes->data[i]);
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
luax_pushshape(L, shapes[i]);
|
||||||
lua_rawseti(L, -2, i + 1);
|
lua_rawseti(L, -2, i + 1);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -42,10 +43,11 @@ static int l_lovrColliderGetShapes(lua_State* L) {
|
||||||
|
|
||||||
static int l_lovrColliderGetJoints(lua_State* L) {
|
static int l_lovrColliderGetJoints(lua_State* L) {
|
||||||
Collider* collider = luax_checktype(L, 1, Collider);
|
Collider* collider = luax_checktype(L, 1, Collider);
|
||||||
lua_newtable(L);
|
size_t count;
|
||||||
vec_void_t* joints = lovrColliderGetJoints(collider);
|
Joint** joints = lovrColliderGetJoints(collider, &count);
|
||||||
for (int i = 0; i < joints->length; i++) {
|
lua_createtable(L, count, 0);
|
||||||
luax_pushjoint(L, joints->data[i]);
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
luax_pushjoint(L, joints[i]);
|
||||||
lua_rawseti(L, -2, i + 1);
|
lua_rawseti(L, -2, i + 1);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -33,13 +33,14 @@ static int l_lovrCurveRender(lua_State* L) {
|
||||||
lovrAssert(points, "Out of memory");
|
lovrAssert(points, "Out of memory");
|
||||||
lovrCurveRender(curve, t1, t2, points, n);
|
lovrCurveRender(curve, t1, t2, points, n);
|
||||||
lua_createtable(L, n, 0);
|
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_pushnumber(L, points[i + 0]);
|
||||||
lua_rawseti(L, -2, i + 1);
|
lua_rawseti(L, -2, j++);
|
||||||
lua_pushnumber(L, points[i + 1]);
|
lua_pushnumber(L, points[i + 1]);
|
||||||
lua_rawseti(L, -2, i + 2);;
|
lua_rawseti(L, -2, j++);
|
||||||
lua_pushnumber(L, points[i + 2]);
|
lua_pushnumber(L, points[i + 2]);
|
||||||
lua_rawseti(L, -2, i + 3);
|
lua_rawseti(L, -2, j++);
|
||||||
}
|
}
|
||||||
free(points);
|
free(points);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -62,7 +63,7 @@ static int l_lovrCurveGetPointCount(lua_State* L) {
|
||||||
|
|
||||||
static int l_lovrCurveGetPoint(lua_State* L) {
|
static int l_lovrCurveGetPoint(lua_State* L) {
|
||||||
Curve* curve = luax_checktype(L, 1, Curve);
|
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);
|
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||||
float point[4];
|
float point[4];
|
||||||
lovrCurveGetPoint(curve, index, point);
|
lovrCurveGetPoint(curve, index, point);
|
||||||
|
@ -74,7 +75,7 @@ static int l_lovrCurveGetPoint(lua_State* L) {
|
||||||
|
|
||||||
static int l_lovrCurveSetPoint(lua_State* L) {
|
static int l_lovrCurveSetPoint(lua_State* L) {
|
||||||
Curve* curve = luax_checktype(L, 1, Curve);
|
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);
|
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||||
float point[4];
|
float point[4];
|
||||||
luax_readvec3(L, 3, point, NULL);
|
luax_readvec3(L, 3, point, NULL);
|
||||||
|
@ -86,7 +87,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
|
||||||
Curve* curve = luax_checktype(L, 1, Curve);
|
Curve* curve = luax_checktype(L, 1, Curve);
|
||||||
float point[4];
|
float point[4];
|
||||||
int i = luax_readvec3(L, 2, point, NULL);
|
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);
|
lovrAssert(index >= 0 && index <= lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||||
lovrCurveAddPoint(curve, point, index);
|
lovrCurveAddPoint(curve, point, index);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -94,7 +95,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
|
||||||
|
|
||||||
static int l_lovrCurveRemovePoint(lua_State* L) {
|
static int l_lovrCurveRemovePoint(lua_State* L) {
|
||||||
Curve* curve = luax_checktype(L, 1, Curve);
|
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);
|
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
|
||||||
lovrCurveRemovePoint(curve, index);
|
lovrCurveRemovePoint(curve, index);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "data/textureData.h"
|
#include "data/textureData.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static int l_lovrDataNewBlob(lua_State* L) {
|
static int l_lovrDataNewBlob(lua_State* L) {
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "filesystem/filesystem.h"
|
#include "filesystem/filesystem.h"
|
||||||
|
#include "filesystem/file.h"
|
||||||
#include "data/blob.h"
|
#include "data/blob.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
// Returns a Blob, leaving stack unchanged. The Blob must be released when finished.
|
// 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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrFilesystemLoad(lua_State* L);
|
typedef struct {
|
||||||
|
File file;
|
||||||
|
char buffer[4096];
|
||||||
|
} luax_Reader;
|
||||||
|
|
||||||
static int moduleLoader(lua_State* L) {
|
static const char* readCallback(lua_State* L, void* data, size_t* size) {
|
||||||
const char* module = luaL_gsub(L, lua_tostring(L, -1), ".", "/");
|
luax_Reader* reader = data;
|
||||||
lua_pop(L, 2);
|
*size = lovrFileRead(&reader->file, reader->buffer, sizeof(reader->buffer));
|
||||||
|
return *size == 0 ? NULL : reader->buffer;
|
||||||
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* libraryExtensions[] = {
|
static int luax_loadfile(lua_State* L, const char* path, const char* debug) {
|
||||||
#ifdef _WIN32
|
luax_Reader reader;
|
||||||
".dll", NULL
|
lovrFileInit(&reader.file, path);
|
||||||
#elif __APPLE__
|
lovrAssert(lovrFileOpen(&reader.file, OPEN_READ), "Could not open file %s", path);
|
||||||
".so", ".dylib", NULL
|
int status = lua_load(L, readCallback, &reader, debug);
|
||||||
#else
|
lovrFileDestroy(&reader.file);
|
||||||
".so", NULL
|
switch (status) {
|
||||||
#endif
|
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;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrFilesystemAppend(lua_State* L) {
|
static int l_lovrFilesystemAppend(lua_State* L) {
|
||||||
|
@ -167,19 +132,9 @@ static int l_lovrFilesystemGetRealDirectory(lua_State* L) {
|
||||||
return 1;
|
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) {
|
static int l_lovrFilesystemGetRequirePath(lua_State* L) {
|
||||||
pushRequirePath(L, lovrFilesystemGetRequirePath());
|
lua_pushstring(L, lovrFilesystemGetRequirePath());
|
||||||
pushRequirePath(L, lovrFilesystemGetCRequirePath());
|
lua_pushstring(L, lovrFilesystemGetCRequirePath());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,23 +201,9 @@ static int l_lovrFilesystemIsFused(lua_State* L) {
|
||||||
|
|
||||||
static int l_lovrFilesystemLoad(lua_State* L) {
|
static int l_lovrFilesystemLoad(lua_State* L) {
|
||||||
const char* path = luaL_checkstring(L, 1);
|
const char* path = luaL_checkstring(L, 1);
|
||||||
size_t size;
|
lua_pushfstring(L, "@%s", path);
|
||||||
char* content = lovrFilesystemRead(path, -1, &size);
|
const char* debug = lua_tostring(L, -1);
|
||||||
|
return luax_loadfile(L, path, debug);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrFilesystemMount(lua_State* L) {
|
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) {
|
static int l_lovrFilesystemSetRequirePath(lua_State* L) {
|
||||||
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(luaL_checkstring(L, 1));
|
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(lua_tostring(L, 1));
|
||||||
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(luaL_checkstring(L, 2));
|
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(lua_tostring(L, 2));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,6 +320,129 @@ static const luaL_Reg lovrFilesystem[] = {
|
||||||
{ NULL, NULL }
|
{ 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) {
|
int luaopen_lovr_filesystem(lua_State* L) {
|
||||||
lua_getglobal(L, "arg");
|
lua_getglobal(L, "arg");
|
||||||
if (lua_istable(L, -1)) {
|
if (lua_istable(L, -1)) {
|
||||||
|
@ -401,7 +465,7 @@ int luaopen_lovr_filesystem(lua_State* L) {
|
||||||
|
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
luaL_register(L, NULL, lovrFilesystem);
|
luaL_register(L, NULL, lovrFilesystem);
|
||||||
luax_registerloader(L, moduleLoader, 2);
|
luax_registerloader(L, luaLoader, 2);
|
||||||
luax_registerloader(L, libraryLoader, 3);
|
luax_registerloader(L, libLoader, 3);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "data/rasterizer.h"
|
#include "data/rasterizer.h"
|
||||||
#include "data/textureData.h"
|
#include "data/textureData.h"
|
||||||
#include "filesystem/filesystem.h"
|
#include "filesystem/filesystem.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -443,7 +444,7 @@ static int l_lovrGraphicsGetStats(lua_State* L) {
|
||||||
lua_pushinteger(L, stats->shaderSwitches);
|
lua_pushinteger(L, stats->shaderSwitches);
|
||||||
lua_setfield(L, 1, "shaderswitches");
|
lua_setfield(L, 1, "shaderswitches");
|
||||||
lua_createtable(L, 0, stats->timers.length);
|
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_pushstring(L, stats->timers.data[i].label);
|
||||||
lua_pushnumber(L, stats->timers.data[i].time);
|
lua_pushnumber(L, stats->timers.data[i].time);
|
||||||
lua_settable(L, -3);
|
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) {
|
static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
|
||||||
vec_uniform_t uniforms;
|
arr_uniform_t uniforms;
|
||||||
vec_init(&uniforms);
|
arr_init(&uniforms);
|
||||||
|
|
||||||
BlockType type = luaL_checkoption(L, 1, NULL, BlockTypes);
|
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);
|
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
|
// Pop the table, leaving the key for lua_next to nom
|
||||||
lua_pop(L, 1);
|
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);
|
Buffer* buffer = lovrBufferCreate(size, NULL, type == BLOCK_COMPUTE ? BUFFER_SHADER_STORAGE : BUFFER_UNIFORM, usage, readable);
|
||||||
ShaderBlock* block = lovrShaderBlockCreate(type, buffer, &uniforms);
|
ShaderBlock* block = lovrShaderBlockCreate(type, buffer, &uniforms);
|
||||||
luax_pushtype(L, ShaderBlock, block);
|
luax_pushtype(L, ShaderBlock, block);
|
||||||
vec_deinit(&uniforms);
|
arr_free(&uniforms);
|
||||||
lovrRelease(Buffer, buffer);
|
lovrRelease(Buffer, buffer);
|
||||||
lovrRelease(ShaderBlock, block);
|
lovrRelease(ShaderBlock, block);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "data/modelData.h"
|
#include "data/modelData.h"
|
||||||
#include "graphics/model.h"
|
#include "graphics/model.h"
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "core/maf.h"
|
#include "core/maf.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -230,12 +231,17 @@ static int l_lovrHeadsetGetBoundsGeometry(lua_State* L) {
|
||||||
lua_settop(L, 1);
|
lua_settop(L, 1);
|
||||||
} else {
|
} else {
|
||||||
lua_settop(L, 0);
|
lua_settop(L, 0);
|
||||||
lua_createtable(L, count, 0);
|
lua_createtable(L, count / 4, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
int j = 1;
|
||||||
lua_pushnumber(L, points[i]);
|
for (uint32_t i = 0; i < count; i += 4) {
|
||||||
lua_rawseti(L, 1, i + 1);
|
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;
|
return 1;
|
||||||
|
@ -608,8 +614,8 @@ int luaopen_lovr_headset(lua_State* L) {
|
||||||
luax_pushconf(L);
|
luax_pushconf(L);
|
||||||
lua_getfield(L, -1, "headset");
|
lua_getfield(L, -1, "headset");
|
||||||
|
|
||||||
vec_t(HeadsetDriver) drivers;
|
arr_t(HeadsetDriver, 8) drivers;
|
||||||
vec_init(&drivers);
|
arr_init(&drivers);
|
||||||
float offset = 1.7f;
|
float offset = 1.7f;
|
||||||
int msaa = 4;
|
int msaa = 4;
|
||||||
|
|
||||||
|
@ -620,7 +626,7 @@ int luaopen_lovr_headset(lua_State* L) {
|
||||||
int n = luax_len(L, -1);
|
int n = luax_len(L, -1);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
lua_rawgeti(L, -1, i + 1);
|
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);
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
@ -640,7 +646,7 @@ int luaopen_lovr_headset(lua_State* L) {
|
||||||
luax_atexit(L, lovrHeadsetDestroy);
|
luax_atexit(L, lovrHeadsetDestroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_deinit(&drivers);
|
arr_free(&drivers);
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
|
|
||||||
headsetRenderData.ref = LUA_NOREF;
|
headsetRenderData.ref = LUA_NOREF;
|
||||||
|
|
|
@ -79,16 +79,9 @@ float* luax_newmathtype(lua_State* L, MathType type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrMathNewCurve(lua_State* L) {
|
static int l_lovrMathNewCurve(lua_State* L) {
|
||||||
|
Curve* curve = lovrCurveCreate();
|
||||||
int top = lua_gettop(L);
|
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)) {
|
if (lua_istable(L, 1)) {
|
||||||
int pointIndex = 0;
|
int pointIndex = 0;
|
||||||
int length = luax_len(L, 1);
|
int length = luax_len(L, 1);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "thread/channel.h"
|
#include "thread/channel.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static int threadRunner(void* data) {
|
static int threadRunner(void* data) {
|
||||||
Thread* thread = (Thread*) 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/audio.h"
|
||||||
#include "audio/source.h"
|
#include "audio/source.h"
|
||||||
#include "data/audioStream.h"
|
#include "data/audioStream.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "core/maf.h"
|
#include "core/maf.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#include <AL/alc.h>
|
#include <AL/alc.h>
|
||||||
|
@ -15,10 +15,10 @@ static struct {
|
||||||
bool spatialized;
|
bool spatialized;
|
||||||
ALCdevice* device;
|
ALCdevice* device;
|
||||||
ALCcontext* context;
|
ALCcontext* context;
|
||||||
vec_void_t sources;
|
|
||||||
float LOVR_ALIGN(16) orientation[4];
|
float LOVR_ALIGN(16) orientation[4];
|
||||||
float LOVR_ALIGN(16) position[4];
|
float LOVR_ALIGN(16) position[4];
|
||||||
float LOVR_ALIGN(16) velocity[4];
|
float LOVR_ALIGN(16) velocity[4];
|
||||||
|
arr_t(Source*, 32) sources;
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
ALenum lovrAudioConvertFormat(uint32_t bitDepth, uint32_t channelCount) {
|
ALenum lovrAudioConvertFormat(uint32_t bitDepth, uint32_t channelCount) {
|
||||||
|
@ -58,7 +58,7 @@ bool lovrAudioInit() {
|
||||||
|
|
||||||
state.device = device;
|
state.device = device;
|
||||||
state.context = context;
|
state.context = context;
|
||||||
vec_init(&state.sources);
|
arr_init(&state.sources);
|
||||||
return state.initialized = true;
|
return state.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,16 +67,17 @@ void lovrAudioDestroy() {
|
||||||
alcMakeContextCurrent(NULL);
|
alcMakeContextCurrent(NULL);
|
||||||
alcDestroyContext(state.context);
|
alcDestroyContext(state.context);
|
||||||
alcCloseDevice(state.device);
|
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]);
|
lovrRelease(Source, state.sources.data[i]);
|
||||||
}
|
}
|
||||||
vec_deinit(&state.sources);
|
arr_free(&state.sources);
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioUpdate() {
|
void lovrAudioUpdate() {
|
||||||
int i; Source* source;
|
for (size_t i = state.sources.length; i-- > 0;) {
|
||||||
vec_foreach_rev(&state.sources, source, i) {
|
Source* source = state.sources.data[i];
|
||||||
|
|
||||||
if (lovrSourceGetType(source) == SOURCE_STATIC) {
|
if (lovrSourceGetType(source) == SOURCE_STATIC) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ void lovrAudioUpdate() {
|
||||||
}
|
}
|
||||||
} else if (isStopped) {
|
} else if (isStopped) {
|
||||||
lovrAudioStreamRewind(lovrSourceGetStream(source));
|
lovrAudioStreamRewind(lovrSourceGetStream(source));
|
||||||
vec_splice(&state.sources, i, 1);
|
arr_splice(&state.sources, i, 1);
|
||||||
lovrRelease(Source, source);
|
lovrRelease(Source, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +105,7 @@ void lovrAudioUpdate() {
|
||||||
void lovrAudioAdd(Source* source) {
|
void lovrAudioAdd(Source* source) {
|
||||||
if (!lovrAudioHas(source)) {
|
if (!lovrAudioHas(source)) {
|
||||||
lovrRetain(source);
|
lovrRetain(source);
|
||||||
vec_push(&state.sources, source);
|
arr_push(&state.sources, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +142,13 @@ float lovrAudioGetVolume() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrAudioHas(Source* source) {
|
bool lovrAudioHas(Source* source) {
|
||||||
int index;
|
for (size_t i = 0; i < state.sources.length; i++) {
|
||||||
vec_find(&state.sources, source, index);
|
if (state.sources.data[i] == source) {
|
||||||
return index >= 0;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrAudioIsSpatialized() {
|
bool lovrAudioIsSpatialized() {
|
||||||
|
@ -151,23 +156,20 @@ bool lovrAudioIsSpatialized() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioPause() {
|
void lovrAudioPause() {
|
||||||
int i; Source* source;
|
for (size_t i = 0; i < state.sources.length; i++) {
|
||||||
vec_foreach(&state.sources, source, i) {
|
lovrSourcePause(state.sources.data[i]);
|
||||||
lovrSourcePause(source);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioResume() {
|
void lovrAudioResume() {
|
||||||
int i; Source* source;
|
for (size_t i = 0; i < state.sources.length; i++) {
|
||||||
vec_foreach(&state.sources, source, i) {
|
lovrSourceResume(state.sources.data[i]);
|
||||||
lovrSourceResume(source);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioRewind() {
|
void lovrAudioRewind() {
|
||||||
int i; Source* source;
|
for (size_t i = 0; i < state.sources.length; i++) {
|
||||||
vec_foreach(&state.sources, source, i) {
|
lovrSourceRewind(state.sources.data[i]);
|
||||||
lovrSourceRewind(source);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,8 +207,7 @@ void lovrAudioSetVolume(float volume) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioStop() {
|
void lovrAudioStop() {
|
||||||
int i; Source* source;
|
for (size_t i = 0; i < state.sources.length; i++) {
|
||||||
vec_foreach(&state.sources, source, i) {
|
lovrSourceStop(state.sources.data[i]);
|
||||||
lovrSourceStop(source);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,27 @@
|
||||||
#include "data/blob.h"
|
#include "data/blob.h"
|
||||||
#include "data/textureData.h"
|
#include "data/textureData.h"
|
||||||
#include "filesystem/filesystem.h"
|
#include "filesystem/filesystem.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "core/maf.h"
|
#include "core/maf.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include "lib/map/map.h"
|
#include "lib/map/map.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
typedef vec_t(ModelMaterial) vec_material_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int material;
|
int material;
|
||||||
int start;
|
int start;
|
||||||
int count;
|
int count;
|
||||||
} objGroup;
|
} 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))
|
#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;
|
size_t length = 0;
|
||||||
char* data = lovrFilesystemRead(path, -1, &length);
|
char* data = lovrFilesystemRead(path, -1, &length);
|
||||||
lovrAssert(data && length > 0, "Unable to read mtl from '%s'", path);
|
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);
|
bool hasName = sscanf(s + 7, "%s\n%n", name, &lineLength);
|
||||||
lovrAssert(hasName, "Bad OBJ: Expected a material name");
|
lovrAssert(hasName, "Bad OBJ: Expected a material name");
|
||||||
map_set(names, name, materials->length);
|
map_set(names, name, materials->length);
|
||||||
vec_push(materials, ((ModelMaterial) {
|
arr_push(materials, ((ModelMaterial) {
|
||||||
.scalars[SCALAR_METALNESS] = 1.f,
|
.scalars[SCALAR_METALNESS] = 1.f,
|
||||||
.scalars[SCALAR_ROUGHNESS] = 1.f,
|
.scalars[SCALAR_ROUGHNESS] = 1.f,
|
||||||
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
|
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
|
||||||
.colors[COLOR_EMISSIVE] = { 0.f, 0.f, 0.f, 0.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")) {
|
} else if (STARTS_WITH(s, "Kd")) {
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
int count = sscanf(s + 2, "%f %f %f\n%n", &r, &g, &b, &lineLength);
|
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");
|
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 };
|
material->colors[COLOR_DIFFUSE] = (Color) { r, g, b, 1.f };
|
||||||
} else if (STARTS_WITH(s, "map_Kd")) {
|
} 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);
|
bool hasFilename = sscanf(s + 7, "%s\n%n", filename, &lineLength);
|
||||||
lovrAssert(hasFilename, "Bad OBJ: Expected a texture filename");
|
lovrAssert(hasFilename, "Bad OBJ: Expected a texture filename");
|
||||||
char path[1024];
|
char path[1024];
|
||||||
snprintf(path, 1023, "%s%s", base, filename);
|
snprintf(path, sizeof(path), "%s%s", base, filename);
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
void* data = lovrFilesystemRead(path, -1, &size);
|
void* data = lovrFilesystemRead(path, -1, &size);
|
||||||
lovrAssert(data && size > 0, "Unable to read texture from %s", path);
|
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
|
// Load texture, assign to material
|
||||||
TextureData* texture = lovrTextureDataCreateFromBlob(blob, true);
|
TextureData* texture = lovrTextureDataCreateFromBlob(blob, true);
|
||||||
lovrAssert(materials->length > 0, "Tried to set a material property without declaring a material first");
|
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->textures[TEXTURE_DIFFUSE] = textures->length;
|
||||||
material->filters[TEXTURE_DIFFUSE].mode = FILTER_TRILINEAR;
|
material->filters[TEXTURE_DIFFUSE].mode = FILTER_TRILINEAR;
|
||||||
material->wraps[TEXTURE_DIFFUSE] = (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT };
|
material->wraps[TEXTURE_DIFFUSE] = (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT };
|
||||||
vec_push(textures, texture);
|
arr_push(textures, texture);
|
||||||
lovrRelease(Blob, blob);
|
lovrRelease(Blob, blob);
|
||||||
} else {
|
} else {
|
||||||
char* newline = memchr(s, '\n', length);
|
char* newline = memchr(s, '\n', length);
|
||||||
|
@ -92,29 +92,29 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_group_t groups;
|
arr_group_t groups;
|
||||||
vec_void_t textures;
|
arr_texturedata_t textures;
|
||||||
vec_material_t materials;
|
arr_material_t materials;
|
||||||
map_int_t materialNames;
|
map_int_t materialNames;
|
||||||
vec_float_t vertexBlob;
|
arr_t(float, 1) vertexBlob;
|
||||||
vec_int_t indexBlob;
|
arr_t(int, 1) indexBlob;
|
||||||
map_int_t vertexMap;
|
map_int_t vertexMap;
|
||||||
vec_float_t positions;
|
arr_t(float, 1) positions;
|
||||||
vec_float_t normals;
|
arr_t(float, 1) normals;
|
||||||
vec_float_t uvs;
|
arr_t(float, 1) uvs;
|
||||||
|
|
||||||
vec_init(&groups);
|
arr_init(&groups);
|
||||||
vec_init(&textures);
|
arr_init(&textures);
|
||||||
vec_init(&materials);
|
arr_init(&materials);
|
||||||
map_init(&materialNames);
|
map_init(&materialNames);
|
||||||
vec_init(&vertexBlob);
|
arr_init(&vertexBlob);
|
||||||
vec_init(&indexBlob);
|
arr_init(&indexBlob);
|
||||||
map_init(&vertexMap);
|
map_init(&vertexMap);
|
||||||
vec_init(&positions);
|
arr_init(&positions);
|
||||||
vec_init(&normals);
|
arr_init(&normals);
|
||||||
vec_init(&uvs);
|
arr_init(&uvs);
|
||||||
|
|
||||||
vec_push(&groups, ((objGroup) { .material = -1 }));
|
arr_push(&groups, ((objGroup) { .material = -1 }));
|
||||||
|
|
||||||
char base[1024];
|
char base[1024];
|
||||||
lovrAssert(strlen(source->name) < sizeof(base), "OBJ filename is too long");
|
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;
|
float x, y, z;
|
||||||
int count = sscanf(data + 2, "%f %f %f\n%n", &x, &y, &z, &lineLength);
|
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");
|
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 ")) {
|
} else if (STARTS_WITH(data, "vn ")) {
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
int count = sscanf(data + 3, "%f %f %f\n%n", &x, &y, &z, &lineLength);
|
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");
|
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 ")) {
|
} else if (STARTS_WITH(data, "vt ")) {
|
||||||
float u, v;
|
float u, v;
|
||||||
int count = sscanf(data + 3, "%f %f\n%n", &u, &v, &lineLength);
|
int count = sscanf(data + 3, "%f %f\n%n", &u, &v, &lineLength);
|
||||||
lovrAssert(count == 2, "Bad OBJ: Expected 2 coordinates for texture coordinate");
|
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 ")) {
|
} else if (STARTS_WITH(data, "f ")) {
|
||||||
char* s = data + 2;
|
char* s = data + 2;
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
|
@ -150,29 +150,29 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||||
*space = '\0'; // I'll be back
|
*space = '\0'; // I'll be back
|
||||||
int* index = map_get(&vertexMap, s);
|
int* index = map_get(&vertexMap, s);
|
||||||
if (index) {
|
if (index) {
|
||||||
vec_push(&indexBlob, *index);
|
arr_push(&indexBlob, *index);
|
||||||
} else {
|
} else {
|
||||||
int v, vt, vn;
|
int v, vt, vn;
|
||||||
int newIndex = vertexBlob.length / 8;
|
int newIndex = vertexBlob.length / 8;
|
||||||
vec_push(&indexBlob, newIndex);
|
arr_push(&indexBlob, newIndex);
|
||||||
map_set(&vertexMap, s, newIndex);
|
map_set(&vertexMap, s, newIndex);
|
||||||
|
|
||||||
// Can be improved
|
// Can be improved
|
||||||
if (sscanf(s, "%d/%d/%d", &v, &vt, &vn) == 3) {
|
if (sscanf(s, "%d/%d/%d", &v, &vt, &vn) == 3) {
|
||||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||||
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
arr_append(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||||
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
arr_append(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||||
} else if (sscanf(s, "%d//%d", &v, &vn) == 2) {
|
} else if (sscanf(s, "%d//%d", &v, &vn) == 2) {
|
||||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||||
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
arr_append(&vertexBlob, normals.data + 3 * (vn - 1), 3);
|
||||||
vec_pusharr(&vertexBlob, ((float[2]) { 0 }), 2);
|
arr_append(&vertexBlob, ((float[2]) { 0 }), 2);
|
||||||
} else if (sscanf(s, "%d/%d", &v, &vt) == 2) {
|
} else if (sscanf(s, "%d/%d", &v, &vt) == 2) {
|
||||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||||
vec_pusharr(&vertexBlob, ((float[3]) { 0 }), 3);
|
arr_append(&vertexBlob, ((float[3]) { 0 }), 3);
|
||||||
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
arr_append(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
|
||||||
} else if (sscanf(s, "%d", &v) == 1) {
|
} else if (sscanf(s, "%d", &v) == 1) {
|
||||||
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
|
||||||
vec_pusharr(&vertexBlob, ((float[5]) { 0 }), 5);
|
arr_append(&vertexBlob, ((float[5]) { 0 }), 5);
|
||||||
} else {
|
} else {
|
||||||
lovrThrow("Bad OBJ: Unknown face format");
|
lovrThrow("Bad OBJ: Unknown face format");
|
||||||
}
|
}
|
||||||
|
@ -181,14 +181,14 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||||
s = space + 1;
|
s = space + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vec_last(&groups).count += 3;
|
groups.data[groups.length - 1].count += 3;
|
||||||
lineLength = s - data;
|
lineLength = s - data;
|
||||||
} else if (STARTS_WITH(data, "mtllib ")) {
|
} else if (STARTS_WITH(data, "mtllib ")) {
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
bool hasName = sscanf(data + 7, "%1024s\n%n", filename, &lineLength);
|
bool hasName = sscanf(data + 7, "%1024s\n%n", filename, &lineLength);
|
||||||
lovrAssert(hasName, "Bad OBJ: Expected filename after mtllib");
|
lovrAssert(hasName, "Bad OBJ: Expected filename after mtllib");
|
||||||
char path[1024];
|
char path[1024];
|
||||||
snprintf(path, 1023, "%s%s", base, filename);
|
snprintf(path, sizeof(path), "%s%s", base, filename);
|
||||||
parseMtl(path, &textures, &materials, &materialNames, base);
|
parseMtl(path, &textures, &materials, &materialNames, base);
|
||||||
} else if (STARTS_WITH(data, "usemtl ")) {
|
} else if (STARTS_WITH(data, "usemtl ")) {
|
||||||
char name[128];
|
char name[128];
|
||||||
|
@ -197,10 +197,10 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||||
lovrAssert(hasName, "Bad OBJ: Expected a material name");
|
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
|
// 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) {
|
if (group->count > 0) {
|
||||||
int start = group->start + group->count; // Don't put this in the compound literal (realloc)
|
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,
|
.material = material ? *material : -1,
|
||||||
.start = start,
|
.start = start,
|
||||||
.count = 0
|
.count = 0
|
||||||
|
@ -276,7 +276,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||||
.components = 2
|
.components = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < groups.length; i++) {
|
for (size_t i = 0; i < groups.length; i++) {
|
||||||
objGroup* group = &groups.data[i];
|
objGroup* group = &groups.data[i];
|
||||||
model->attributes[3 + i] = (ModelAttribute) {
|
model->attributes[3 + i] = (ModelAttribute) {
|
||||||
.buffer = 1,
|
.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];
|
objGroup* group = &groups.data[i];
|
||||||
model->primitives[i] = (ModelPrimitive) {
|
model->primitives[i] = (ModelPrimitive) {
|
||||||
.mode = DRAW_TRIANGLES,
|
.mode = DRAW_TRIANGLES,
|
||||||
|
@ -307,13 +307,13 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||||
.primitiveCount = groups.length
|
.primitiveCount = groups.length
|
||||||
};
|
};
|
||||||
|
|
||||||
vec_deinit(&groups);
|
arr_free(&groups);
|
||||||
vec_deinit(&textures);
|
arr_free(&textures);
|
||||||
vec_deinit(&materials);
|
arr_free(&materials);
|
||||||
map_deinit(&materialNames);
|
map_deinit(&materialNames);
|
||||||
map_deinit(&vertexMap);
|
map_deinit(&vertexMap);
|
||||||
vec_deinit(&positions);
|
arr_free(&positions);
|
||||||
vec_deinit(&normals);
|
arr_free(&normals);
|
||||||
vec_deinit(&uvs);
|
arr_free(&uvs);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "lib/stb/stb_truetype.h"
|
#include "lib/stb/stb_truetype.h"
|
||||||
#include <msdfgen-c.h>
|
#include <msdfgen-c.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
Rasterizer* lovrRasterizerInit(Rasterizer* rasterizer, Blob* blob, float size) {
|
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 width = textureData->width = header->width;
|
||||||
uint32_t height = textureData->height = header->height;
|
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;
|
size_t blockBytes = 0;
|
||||||
|
|
||||||
switch (textureData->format) {
|
switch (textureData->format) {
|
||||||
|
@ -303,12 +304,11 @@ static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) {
|
||||||
|
|
||||||
// Overflow check
|
// Overflow check
|
||||||
if (mipmapSize == 0 || (offset + mipmapSize) > size) {
|
if (mipmapSize == 0 || (offset + mipmapSize) > size) {
|
||||||
vec_deinit(&textureData->mipmaps);
|
free(textureData->mipmaps);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mipmap mipmap = { .width = width, .height = height, .data = &data[offset], .size = mipmapSize };
|
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = &data[offset], .size = mipmapSize };
|
||||||
vec_push(&textureData->mipmaps, mipmap);
|
|
||||||
offset += mipmapSize;
|
offset += mipmapSize;
|
||||||
width = MAX(width >> 1, 1);
|
width = MAX(width >> 1, 1);
|
||||||
height = MAX(height >> 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 width = textureData->width = data.ktx->pixelWidth;
|
||||||
uint32_t height = textureData->height = data.ktx->pixelHeight;
|
uint32_t height = textureData->height = data.ktx->pixelHeight;
|
||||||
uint32_t mipmapCount = data.ktx->numberOfMipmapLevels;
|
uint32_t mipmapCount = textureData->mipmapCount = data.ktx->numberOfMipmapLevels;
|
||||||
vec_reserve(&textureData->mipmaps, mipmapCount);
|
textureData->mipmaps = malloc(mipmapCount * sizeof(Mipmap));
|
||||||
|
|
||||||
data.u8 += sizeof(KTXHeader) + data.ktx->bytesOfKeyValueData;
|
data.u8 += sizeof(KTXHeader) + data.ktx->bytesOfKeyValueData;
|
||||||
for (uint32_t i = 0; i < mipmapCount; i++) {
|
for (uint32_t i = 0; i < mipmapCount; i++) {
|
||||||
vec_push(&textureData->mipmaps, ((Mipmap) {
|
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = data.u8 + sizeof(uint32_t), .size = *data.u32 };
|
||||||
.width = width,
|
|
||||||
.height = height,
|
|
||||||
.data = data.u8 + sizeof(uint32_t),
|
|
||||||
.size = *data.u32
|
|
||||||
}));
|
|
||||||
|
|
||||||
width = MAX(width >> 1, 1u);
|
width = MAX(width >> 1, 1u);
|
||||||
height = MAX(height >> 1, 1u);
|
height = MAX(height >> 1, 1u);
|
||||||
data.u8 = (uint8_t*) ALIGN(data.u8 + sizeof(uint32_t) + *data.u32 + 3, 4);
|
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->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);
|
textureData->height = data.astc->height[0] + (data.astc->height[1] << 8) + (data.astc->height[2] << 16);
|
||||||
|
textureData->mipmaps = malloc(sizeof(Mipmap));
|
||||||
vec_push(&textureData->mipmaps, ((Mipmap) {
|
textureData->mipmaps[0] = (Mipmap) {
|
||||||
.width = textureData->width,
|
.width = textureData->width,
|
||||||
.height = textureData->height,
|
.height = textureData->height,
|
||||||
.data = data.astc + 1,
|
.data = data.astc + 1,
|
||||||
.size = size - sizeof(*data.astc)
|
.size = size - sizeof(*data.astc)
|
||||||
}));
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -448,13 +442,10 @@ TextureData* lovrTextureDataInit(TextureData* textureData, uint32_t width, uint3
|
||||||
textureData->blob.data = malloc(size);
|
textureData->blob.data = malloc(size);
|
||||||
lovrAssert(textureData->blob.data, "Out of memory");
|
lovrAssert(textureData->blob.data, "Out of memory");
|
||||||
memset(textureData->blob.data, value, size);
|
memset(textureData->blob.data, value, size);
|
||||||
vec_init(&textureData->mipmaps);
|
|
||||||
return textureData;
|
return textureData;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureData* lovrTextureDataInitFromBlob(TextureData* textureData, Blob* blob, bool flip) {
|
TextureData* lovrTextureDataInitFromBlob(TextureData* textureData, Blob* blob, bool flip) {
|
||||||
vec_init(&textureData->mipmaps);
|
|
||||||
|
|
||||||
if (parseDDS(blob->data, blob->size, textureData)) {
|
if (parseDDS(blob->data, blob->size, textureData)) {
|
||||||
textureData->source = blob;
|
textureData->source = blob;
|
||||||
lovrRetain(blob);
|
lovrRetain(blob);
|
||||||
|
@ -488,6 +479,7 @@ TextureData* lovrTextureDataInitFromBlob(TextureData* textureData, Blob* blob, b
|
||||||
|
|
||||||
textureData->width = width;
|
textureData->width = width;
|
||||||
textureData->height = height;
|
textureData->height = height;
|
||||||
|
textureData->mipmapCount = 0;
|
||||||
return textureData;
|
return textureData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,6 +566,6 @@ bool lovrTextureDataEncode(TextureData* textureData, const char* filename) {
|
||||||
void lovrTextureDataDestroy(void* ref) {
|
void lovrTextureDataDestroy(void* ref) {
|
||||||
TextureData* textureData = ref;
|
TextureData* textureData = ref;
|
||||||
lovrRelease(Blob, textureData->source);
|
lovrRelease(Blob, textureData->source);
|
||||||
vec_deinit(&textureData->mipmaps);
|
free(textureData->mipmaps);
|
||||||
lovrBlobDestroy(ref);
|
lovrBlobDestroy(ref);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "data/blob.h"
|
#include "data/blob.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
@ -48,15 +47,14 @@ typedef struct {
|
||||||
void* data;
|
void* data;
|
||||||
} Mipmap;
|
} Mipmap;
|
||||||
|
|
||||||
typedef vec_t(Mipmap) vec_mipmap_t;
|
|
||||||
|
|
||||||
typedef struct TextureData {
|
typedef struct TextureData {
|
||||||
Blob blob;
|
Blob blob;
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
Blob* source;
|
Blob* source;
|
||||||
TextureFormat format;
|
TextureFormat format;
|
||||||
vec_mipmap_t mipmaps;
|
Mipmap* mipmaps;
|
||||||
|
uint32_t mipmapCount;
|
||||||
} TextureData;
|
} TextureData;
|
||||||
|
|
||||||
TextureData* lovrTextureDataInit(TextureData* textureData, uint32_t width, uint32_t height, uint8_t value, TextureFormat format);
|
TextureData* lovrTextureDataInit(TextureData* textureData, uint32_t width, uint32_t height, uint8_t value, TextureFormat format);
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
vec_t(EventPump) pumps;
|
arr_t(Event, 8) events;
|
||||||
vec_t(Event) events;
|
size_t head;
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
void lovrVariantDestroy(Variant* variant) {
|
void lovrVariantDestroy(Variant* variant) {
|
||||||
|
@ -21,47 +21,35 @@ void lovrVariantDestroy(Variant* variant) {
|
||||||
|
|
||||||
bool lovrEventInit() {
|
bool lovrEventInit() {
|
||||||
if (state.initialized) return false;
|
if (state.initialized) return false;
|
||||||
vec_init(&state.pumps);
|
arr_init(&state.events);
|
||||||
vec_init(&state.events);
|
|
||||||
lovrEventAddPump(lovrPlatformPollEvents);
|
|
||||||
return state.initialized = true;
|
return state.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrEventDestroy() {
|
void lovrEventDestroy() {
|
||||||
if (!state.initialized) return;
|
if (!state.initialized) return;
|
||||||
vec_deinit(&state.pumps);
|
arr_free(&state.events);
|
||||||
vec_deinit(&state.events);
|
|
||||||
memset(&state, 0, sizeof(state));
|
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() {
|
void lovrEventPump() {
|
||||||
int i; EventPump pump;
|
lovrPlatformPollEvents();
|
||||||
vec_foreach(&state.pumps, pump, i) {
|
|
||||||
pump();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrEventPush(Event event) {
|
void lovrEventPush(Event event) {
|
||||||
vec_insert(&state.events, 0, event);
|
arr_push(&state.events, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrEventPoll(Event* event) {
|
bool lovrEventPoll(Event* event) {
|
||||||
if (state.events.length == 0) {
|
if (state.head == state.events.length) {
|
||||||
|
state.head = state.events.length = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*event = vec_pop(&state.events);
|
*event = state.events.data[state.head++];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrEventClear() {
|
void lovrEventClear() {
|
||||||
vec_clear(&state.events);
|
arr_clear(&state.events);
|
||||||
|
state.head = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,14 +70,10 @@ typedef struct {
|
||||||
EventData data;
|
EventData data;
|
||||||
} Event;
|
} Event;
|
||||||
|
|
||||||
typedef void (*EventPump)(void);
|
|
||||||
|
|
||||||
void lovrVariantDestroy(Variant* variant);
|
void lovrVariantDestroy(Variant* variant);
|
||||||
|
|
||||||
bool lovrEventInit(void);
|
bool lovrEventInit(void);
|
||||||
void lovrEventDestroy(void);
|
void lovrEventDestroy(void);
|
||||||
void lovrEventAddPump(EventPump pump);
|
|
||||||
void lovrEventRemovePump(EventPump pump);
|
|
||||||
void lovrEventPump(void);
|
void lovrEventPump(void);
|
||||||
void lovrEventPush(Event event);
|
void lovrEventPush(Event event);
|
||||||
bool lovrEventPoll(Event* event);
|
bool lovrEventPoll(Event* event);
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
File* lovrFileInit(File* file ,const char* path) {
|
File* lovrFileInit(File* file ,const char* path) {
|
||||||
file->path = path;
|
file->path = path;
|
||||||
|
file->handle = NULL;
|
||||||
|
file->mode = 0;
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,12 @@ const char lovrDirSep = '/';
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
bool fused;
|
||||||
char* source;
|
char* source;
|
||||||
const char* identity;
|
const char* identity;
|
||||||
char* savePathRelative;
|
char* savePathRelative;
|
||||||
char* savePathFull;
|
char* savePathFull;
|
||||||
bool isFused;
|
char requirePath[2][1024];
|
||||||
char* requirePath[2];
|
|
||||||
vec_str_t requirePattern[2];
|
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot) {
|
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));
|
state.source = malloc(LOVR_PATH_MAX * sizeof(char));
|
||||||
lovrAssert(state.source, "Out of memory");
|
lovrAssert(state.source, "Out of memory");
|
||||||
state.identity = NULL;
|
state.identity = NULL;
|
||||||
state.isFused = true;
|
state.fused = true;
|
||||||
vec_init(&state.requirePattern[0]);
|
|
||||||
vec_init(&state.requirePattern[1]);
|
|
||||||
lovrFilesystemSetRequirePath("?.lua;?/init.lua;lua_modules/?.lua;lua_modules/?/init.lua;deps/?.lua;deps/?/init.lua");
|
lovrFilesystemSetRequirePath("?.lua;?/init.lua;lua_modules/?.lua;lua_modules/?/init.lua;deps/?.lua;deps/?/init.lua");
|
||||||
lovrFilesystemSetCRequirePath("??;lua_modules/??;deps/??");
|
lovrFilesystemSetCRequirePath("??;lua_modules/??;deps/??");
|
||||||
|
|
||||||
// Try to mount either an archive fused to the executable or an archive from the command line
|
// Try to mount either an archive fused to the executable or an archive from the command line
|
||||||
lovrFilesystemGetExecutablePath(state.source, LOVR_PATH_MAX);
|
lovrFilesystemGetExecutablePath(state.source, LOVR_PATH_MAX);
|
||||||
if (!lovrFilesystemMount(state.source, NULL, 1, argRoot)) { // Attempt to load fused. If that fails...
|
if (!lovrFilesystemMount(state.source, NULL, 1, argRoot)) { // Attempt to load fused. If that fails...
|
||||||
state.isFused = false;
|
state.fused = false;
|
||||||
|
|
||||||
if (argGame) {
|
if (argGame) {
|
||||||
strncpy(state.source, argGame, LOVR_PATH_MAX);
|
strncpy(state.source, argGame, LOVR_PATH_MAX);
|
||||||
|
@ -82,10 +79,6 @@ void lovrFilesystemDestroy() {
|
||||||
free(state.source);
|
free(state.source);
|
||||||
free(state.savePathFull);
|
free(state.savePathFull);
|
||||||
free(state.savePathRelative);
|
free(state.savePathRelative);
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
free(state.requirePath[i]);
|
|
||||||
vec_deinit(&state.requirePattern[i]);
|
|
||||||
}
|
|
||||||
PHYSFS_deinit();
|
PHYSFS_deinit();
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
}
|
}
|
||||||
|
@ -151,12 +144,12 @@ const char* lovrFilesystemGetRealDirectory(const char* path) {
|
||||||
return PHYSFS_getRealDir(path);
|
return PHYSFS_getRealDir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_str_t* lovrFilesystemGetRequirePath() {
|
const char* lovrFilesystemGetRequirePath() {
|
||||||
return &state.requirePattern[0];
|
return state.requirePath[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_str_t* lovrFilesystemGetCRequirePath() {
|
const char* lovrFilesystemGetCRequirePath() {
|
||||||
return &state.requirePattern[1];
|
return state.requirePath[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* lovrFilesystemGetSaveDirectory() {
|
const char* lovrFilesystemGetSaveDirectory() {
|
||||||
|
@ -213,7 +206,7 @@ bool lovrFilesystemIsFile(const char* path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrFilesystemIsFused() {
|
bool lovrFilesystemIsFused() {
|
||||||
return state.isFused;
|
return state.fused;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns zero on success, nonzero on failure
|
// 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) {
|
void* lovrFilesystemRead(const char* path, size_t bytes, size_t* bytesRead) {
|
||||||
File file;
|
File file;
|
||||||
lovrFileInit(memset(&file, 0, sizeof(File)), path);
|
lovrFileInit(&file, path);
|
||||||
|
|
||||||
if (!lovrFileOpen(&file, OPEN_READ)) {
|
if (!lovrFileOpen(&file, OPEN_READ)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -293,30 +286,12 @@ bool lovrFilesystemSetIdentity(const char* identity) {
|
||||||
return PHYSFS_mount(state.savePathFull, NULL, 0);
|
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) {
|
void lovrFilesystemSetRequirePath(const char* requirePath) {
|
||||||
setRequirePath(0, requirePath);
|
strncpy(state.requirePath[0], requirePath, sizeof(state.requirePath[0]) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrFilesystemSetCRequirePath(const char* requirePath) {
|
void lovrFilesystemSetCRequirePath(const char* requirePath) {
|
||||||
setRequirePath(1, requirePath);
|
strncpy(state.requirePath[1], requirePath, sizeof(state.requirePath[1]) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrFilesystemUnmount(const char* path) {
|
bool lovrFilesystemUnmount(const char* path) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ int lovrFilesystemGetExecutablePath(char* path, uint32_t size);
|
||||||
const char* lovrFilesystemGetIdentity(void);
|
const char* lovrFilesystemGetIdentity(void);
|
||||||
long lovrFilesystemGetLastModified(const char* path);
|
long lovrFilesystemGetLastModified(const char* path);
|
||||||
const char* lovrFilesystemGetRealDirectory(const char* path);
|
const char* lovrFilesystemGetRealDirectory(const char* path);
|
||||||
vec_str_t* lovrFilesystemGetRequirePath(void);
|
const char* lovrFilesystemGetRequirePath();
|
||||||
vec_str_t* lovrFilesystemGetCRequirePath(void);
|
const char* lovrFilesystemGetCRequirePath();
|
||||||
const char* lovrFilesystemGetSaveDirectory(void);
|
const char* lovrFilesystemGetSaveDirectory(void);
|
||||||
size_t lovrFilesystemGetSize(const char* path);
|
size_t lovrFilesystemGetSize(const char* path);
|
||||||
const char* lovrFilesystemGetSource(void);
|
const char* lovrFilesystemGetSource(void);
|
||||||
|
|
|
@ -13,12 +13,12 @@ Animator* lovrAnimatorInit(Animator* animator, ModelData* data) {
|
||||||
lovrRetain(data);
|
lovrRetain(data);
|
||||||
animator->data = data;
|
animator->data = data;
|
||||||
map_init(&animator->animations);
|
map_init(&animator->animations);
|
||||||
vec_init(&animator->tracks);
|
arr_init(&animator->tracks);
|
||||||
vec_reserve(&animator->tracks, data->animationCount);
|
arr_reserve(&animator->tracks, data->animationCount);
|
||||||
animator->speed = 1.f;
|
animator->speed = 1.f;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < data->animationCount; i++) {
|
for (uint32_t i = 0; i < data->animationCount; i++) {
|
||||||
vec_push(&animator->tracks, ((Track) {
|
arr_push(&animator->tracks, ((Track) {
|
||||||
.time = 0.f,
|
.time = 0.f,
|
||||||
.speed = 1.f,
|
.speed = 1.f,
|
||||||
.alpha = 1.f,
|
.alpha = 1.f,
|
||||||
|
@ -38,12 +38,12 @@ Animator* lovrAnimatorInit(Animator* animator, ModelData* data) {
|
||||||
void lovrAnimatorDestroy(void* ref) {
|
void lovrAnimatorDestroy(void* ref) {
|
||||||
Animator* animator = ref;
|
Animator* animator = ref;
|
||||||
lovrRelease(ModelData, animator->data);
|
lovrRelease(ModelData, animator->data);
|
||||||
vec_deinit(&animator->tracks);
|
arr_free(&animator->tracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAnimatorReset(Animator* animator) {
|
void lovrAnimatorReset(Animator* animator) {
|
||||||
Track* track; int i;
|
for (size_t i = 0; i < animator->tracks.length; i++) {
|
||||||
vec_foreach_ptr(&animator->tracks, track, i) {
|
Track* track = &animator->tracks.data[i];
|
||||||
track->time = 0.f;
|
track->time = 0.f;
|
||||||
track->speed = 1.f;
|
track->speed = 1.f;
|
||||||
track->playing = false;
|
track->playing = false;
|
||||||
|
@ -53,8 +53,8 @@ void lovrAnimatorReset(Animator* animator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAnimatorUpdate(Animator* animator, float dt) {
|
void lovrAnimatorUpdate(Animator* animator, float dt) {
|
||||||
Track* track; int i;
|
for (size_t i = 0; i < animator->tracks.length; i++) {
|
||||||
vec_foreach_ptr(&animator->tracks, track, i) {
|
Track* track = &animator->tracks.data[i];
|
||||||
if (track->playing) {
|
if (track->playing) {
|
||||||
track->time += dt * track->speed * animator->speed;
|
track->time += dt * track->speed * animator->speed;
|
||||||
float duration = animator->data->animations[i].duration;
|
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) {
|
void lovrAnimatorSetPriority(Animator* animator, uint32_t animation, int32_t priority) {
|
||||||
Track* track = &animator->tracks.data[animation];
|
Track* track = &animator->tracks.data[animation];
|
||||||
track->priority = priority;
|
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) {
|
float lovrAnimatorGetSpeed(Animator* animator, uint32_t animation) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
#include "core/arr.h"
|
||||||
#include "lib/map/map.h"
|
#include "lib/map/map.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -16,12 +16,10 @@ typedef struct {
|
||||||
bool looping;
|
bool looping;
|
||||||
} Track;
|
} Track;
|
||||||
|
|
||||||
typedef vec_t(Track) vec_track_t;
|
|
||||||
|
|
||||||
typedef struct Animator {
|
typedef struct Animator {
|
||||||
struct ModelData* data;
|
struct ModelData* data;
|
||||||
map_t(uint32_t) animations;
|
map_t(uint32_t) animations;
|
||||||
vec_track_t tracks;
|
arr_t(Track, 1) tracks;
|
||||||
float speed;
|
float speed;
|
||||||
} Animator;
|
} Animator;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "graphics/font.h"
|
#include "graphics/font.h"
|
||||||
#include "graphics/shader.h"
|
#include "graphics/shader.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "core/maf.h"
|
#include "core/maf.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
@ -307,7 +308,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int shaderSwitches;
|
int shaderSwitches;
|
||||||
int drawCalls;
|
int drawCalls;
|
||||||
vec_t(GpuTimer) timers;
|
arr_t(GpuTimer, 4) timers;
|
||||||
} GpuStats;
|
} GpuStats;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include "data/modelData.h"
|
#include "data/modelData.h"
|
||||||
#include "core/ref.h"
|
#include "core/ref.h"
|
||||||
#include "lib/map/map.h"
|
#include "lib/map/map.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -82,7 +81,7 @@ static struct {
|
||||||
Image images[MAX_IMAGES];
|
Image images[MAX_IMAGES];
|
||||||
float viewports[2][4];
|
float viewports[2][4];
|
||||||
uint32_t viewportCount;
|
uint32_t viewportCount;
|
||||||
vec_void_t incoherents[MAX_BARRIERS];
|
arr_t(void*, 2) incoherents[MAX_BARRIERS];
|
||||||
map_t(TimerList) timers;
|
map_t(TimerList) timers;
|
||||||
GpuFeatures features;
|
GpuFeatures features;
|
||||||
GpuLimits limits;
|
GpuLimits limits;
|
||||||
|
@ -420,18 +419,18 @@ static void lovrGpuSync(uint8_t flags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == BARRIER_BLOCK) {
|
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* buffer = state.incoherents[i].data[j];
|
||||||
buffer->incoherent &= ~(1 << i);
|
buffer->incoherent &= ~(1 << i);
|
||||||
}
|
}
|
||||||
} else {
|
} 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* texture = state.incoherents[i].data[j];
|
||||||
texture->incoherent &= ~(1 << i);
|
texture->incoherent &= ~(1 << i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_clear(&state.incoherents[i]);
|
arr_clear(&state.incoherents[i]);
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case BARRIER_BLOCK: bits |= GL_SHADER_STORAGE_BARRIER_BIT; break;
|
case BARRIER_BLOCK: bits |= GL_SHADER_STORAGE_BARRIER_BIT; break;
|
||||||
|
@ -453,11 +452,11 @@ static void lovrGpuDestroySyncResource(void* resource, uint8_t incoherent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_BARRIERS; i++) {
|
for (uint32_t i = 0; i < MAX_BARRIERS; i++) {
|
||||||
if (incoherent & (1 << 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) {
|
if (state.incoherents[i].data[j] == resource) {
|
||||||
vec_swapsplice(&state.incoherents[i], j, 1);
|
arr_splice(&state.incoherents[i], j, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -839,23 +838,21 @@ static void lovrGpuBindPipeline(Pipeline* pipeline) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lovrGpuBindShader(Shader* shader) {
|
static void lovrGpuBindShader(Shader* shader) {
|
||||||
UniformBlock* block;
|
|
||||||
Uniform* uniform;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
lovrGpuUseProgram(shader->program);
|
lovrGpuUseProgram(shader->program);
|
||||||
|
|
||||||
// Figure out if we need to wait for pending writes on resources to complete
|
// Figure out if we need to wait for pending writes on resources to complete
|
||||||
#ifndef LOVR_WEBGL
|
#ifndef LOVR_WEBGL
|
||||||
uint8_t flags = 0;
|
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) {
|
if (block->source && (block->source->incoherent >> BARRIER_BLOCK) & 1) {
|
||||||
flags |= 1 << BARRIER_BLOCK;
|
flags |= 1 << BARRIER_BLOCK;
|
||||||
break;
|
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) {
|
if (uniform->type == UNIFORM_SAMPLER) {
|
||||||
for (int i = 0; i < uniform->count; i++) {
|
for (int i = 0; i < uniform->count; i++) {
|
||||||
Texture* texture = uniform->value.textures[i];
|
Texture* texture = uniform->value.textures[i];
|
||||||
|
@ -883,7 +880,9 @@ static void lovrGpuBindShader(Shader* shader) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Bind uniforms
|
// 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) {
|
if (uniform->type != UNIFORM_SAMPLER && uniform->type != UNIFORM_IMAGE && !uniform->dirty) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -930,7 +929,7 @@ static void lovrGpuBindShader(Shader* shader) {
|
||||||
if (texture && image->access != ACCESS_READ) {
|
if (texture && image->access != ACCESS_READ) {
|
||||||
for (Barrier barrier = BARRIER_BLOCK + 1; barrier < MAX_BARRIERS; barrier++) {
|
for (Barrier barrier = BARRIER_BLOCK + 1; barrier < MAX_BARRIERS; barrier++) {
|
||||||
texture->incoherent |= 1 << 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
|
// Bind uniform blocks
|
||||||
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_COMPUTE; type++) {
|
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 (block->source) {
|
||||||
if (type == BLOCK_COMPUTE && block->access != ACCESS_READ) {
|
if (type == BLOCK_COMPUTE && block->access != ACCESS_READ) {
|
||||||
block->source->incoherent |= (1 << BARRIER_BLOCK);
|
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);
|
lovrBufferUnmap(block->source);
|
||||||
|
@ -1059,7 +1059,7 @@ void lovrGpuInit(getProcAddressProc getProcAddress) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < MAX_BARRIERS; i++) {
|
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);
|
lovrRelease(Texture, state.images[i].texture);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < MAX_BARRIERS; i++) {
|
for (int i = 0; i < MAX_BARRIERS; i++) {
|
||||||
vec_deinit(&state.incoherents[i]);
|
arr_free(&state.incoherents[i]);
|
||||||
}
|
}
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
}
|
}
|
||||||
|
@ -1183,7 +1183,7 @@ void lovrGpuDraw(DrawCommand* draw) {
|
||||||
|
|
||||||
void lovrGpuPresent() {
|
void lovrGpuPresent() {
|
||||||
state.stats.drawCalls = state.stats.shaderSwitches = 0;
|
state.stats.drawCalls = state.stats.shaderSwitches = 0;
|
||||||
vec_clear(&state.stats.timers);
|
arr_clear(&state.stats.timers);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// For some reason instancing doesn't work on macOS unless you reset the shader every frame
|
// For some reason instancing doesn't work on macOS unless you reset the shader every frame
|
||||||
lovrGpuUseProgram(0);
|
lovrGpuUseProgram(0);
|
||||||
|
@ -1284,7 +1284,7 @@ void lovrGpuTock(const char* label) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glGetQueryObjectui64v(timer->timers[timer->oldest], GL_QUERY_RESULT, &timer->ns);
|
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;
|
timer->oldest = (timer->oldest + 1) % 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1445,16 +1445,16 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, uint32
|
||||||
if (isTextureFormatCompressed(textureData->format)) {
|
if (isTextureFormatCompressed(textureData->format)) {
|
||||||
lovrAssert(width == maxWidth && height == maxHeight, "Compressed texture pixels must be fully replaced");
|
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");
|
lovrAssert(mipmap == 0, "Unable to replace a specific mipmap of a compressed texture");
|
||||||
Mipmap m; int i;
|
for (uint32_t i = 0; i < textureData->mipmapCount; i++) {
|
||||||
vec_foreach(&textureData->mipmaps, m, i) {
|
Mipmap* m = textureData->mipmaps + i;
|
||||||
switch (texture->type) {
|
switch (texture->type) {
|
||||||
case TEXTURE_2D:
|
case TEXTURE_2D:
|
||||||
case TEXTURE_CUBE:
|
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;
|
break;
|
||||||
case TEXTURE_ARRAY:
|
case TEXTURE_ARRAY:
|
||||||
case TEXTURE_VOLUME:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1795,42 +1795,42 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
||||||
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount);
|
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);
|
lovrAssert(blockCount <= MAX_BLOCK_BUFFERS, "Shader has too many uniform blocks (%d) the max is %d", blockCount, MAX_BLOCK_BUFFERS);
|
||||||
map_init(&shader->blockMap);
|
map_init(&shader->blockMap);
|
||||||
vec_block_t* uniformBlocks = &shader->blocks[BLOCK_UNIFORM];
|
arr_block_t* uniformBlocks = &shader->blocks[BLOCK_UNIFORM];
|
||||||
vec_init(uniformBlocks);
|
arr_init(uniformBlocks);
|
||||||
vec_reserve(uniformBlocks, blockCount);
|
arr_reserve(uniformBlocks, (size_t) blockCount);
|
||||||
for (int i = 0; i < blockCount; i++) {
|
for (int i = 0; i < blockCount; i++) {
|
||||||
UniformBlock block = { .slot = i, .source = NULL };
|
UniformBlock block = { .slot = i, .source = NULL };
|
||||||
glUniformBlockBinding(program, i, block.slot);
|
glUniformBlockBinding(program, i, block.slot);
|
||||||
vec_init(&block.uniforms);
|
arr_init(&block.uniforms);
|
||||||
|
|
||||||
char name[LOVR_MAX_UNIFORM_LENGTH];
|
char name[LOVR_MAX_UNIFORM_LENGTH];
|
||||||
glGetActiveUniformBlockName(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
|
glGetActiveUniformBlockName(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
|
||||||
int blockId = (i << 1) + BLOCK_UNIFORM;
|
int blockId = (i << 1) + BLOCK_UNIFORM;
|
||||||
map_set(&shader->blockMap, name, blockId);
|
map_set(&shader->blockMap, name, blockId);
|
||||||
vec_push(uniformBlocks, block);
|
arr_push(uniformBlocks, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shader storage buffers and their buffer variables
|
// Shader storage buffers and their buffer variables
|
||||||
vec_block_t* computeBlocks = &shader->blocks[BLOCK_COMPUTE];
|
arr_block_t* computeBlocks = &shader->blocks[BLOCK_COMPUTE];
|
||||||
vec_init(computeBlocks);
|
arr_init(computeBlocks);
|
||||||
#ifndef LOVR_WEBGL
|
#ifndef LOVR_WEBGL
|
||||||
if (GLAD_GL_ARB_shader_storage_buffer_object && GLAD_GL_ARB_program_interface_query) {
|
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
|
// 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);
|
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);
|
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++) {
|
for (int i = 0; i < computeBlockCount; i++) {
|
||||||
UniformBlock block = { .slot = i, .source = NULL };
|
UniformBlock block = { .slot = i, .source = NULL };
|
||||||
glShaderStorageBlockBinding(program, i, block.slot);
|
glShaderStorageBlockBinding(program, i, block.slot);
|
||||||
vec_init(&block.uniforms);
|
arr_init(&block.uniforms);
|
||||||
|
|
||||||
char name[LOVR_MAX_UNIFORM_LENGTH];
|
char name[LOVR_MAX_UNIFORM_LENGTH];
|
||||||
glGetProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
|
glGetProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
|
||||||
int blockId = (i << 1) + BLOCK_COMPUTE;
|
int blockId = (i << 1) + BLOCK_COMPUTE;
|
||||||
map_set(&shader->blockMap, name, blockId);
|
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
|
// Iterate over buffer variables, pushing them onto the uniform list of the correct block
|
||||||
|
@ -1854,7 +1854,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
||||||
} else {
|
} else {
|
||||||
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
|
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
|
#endif
|
||||||
|
@ -1864,7 +1864,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
||||||
int textureSlot = 0;
|
int textureSlot = 0;
|
||||||
int imageSlot = 0;
|
int imageSlot = 0;
|
||||||
map_init(&shader->uniformMap);
|
map_init(&shader->uniformMap);
|
||||||
vec_init(&shader->uniforms);
|
arr_init(&shader->uniforms);
|
||||||
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount);
|
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount);
|
||||||
for (uint32_t i = 0; i < (uint32_t) uniformCount; i++) {
|
for (uint32_t i = 0; i < (uint32_t) uniformCount; i++) {
|
||||||
Uniform uniform;
|
Uniform uniform;
|
||||||
|
@ -1910,7 +1910,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
||||||
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
|
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_push(&block->uniforms, uniform);
|
arr_push(&block->uniforms, uniform);
|
||||||
continue;
|
continue;
|
||||||
} else if (uniform.location == -1) {
|
} else if (uniform.location == -1) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1971,7 +1971,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
map_set(&shader->uniformMap, uniform.name, shader->uniforms.length);
|
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;
|
textureSlot += uniform.type == UNIFORM_SAMPLER ? uniform.count : 0;
|
||||||
imageSlot += uniform.type == UNIFORM_IMAGE ? uniform.count : 0;
|
imageSlot += uniform.type == UNIFORM_IMAGE ? uniform.count : 0;
|
||||||
}
|
}
|
||||||
|
@ -2115,18 +2115,17 @@ void lovrShaderDestroy(void* ref) {
|
||||||
Shader* shader = ref;
|
Shader* shader = ref;
|
||||||
lovrGraphicsFlushShader(shader);
|
lovrGraphicsFlushShader(shader);
|
||||||
glDeleteProgram(shader->program);
|
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);
|
free(shader->uniforms.data[i].value.data);
|
||||||
}
|
}
|
||||||
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_COMPUTE; type++) {
|
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_COMPUTE; type++) {
|
||||||
UniformBlock* block; int i;
|
for (size_t i = 0; i < shader->blocks[type].length; i++) {
|
||||||
vec_foreach_ptr(&shader->blocks[type], block, i) {
|
lovrRelease(Buffer, shader->blocks[type].data[i].source);
|
||||||
lovrRelease(Buffer, block->source);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vec_deinit(&shader->uniforms);
|
arr_free(&shader->uniforms);
|
||||||
vec_deinit(&shader->blocks[BLOCK_UNIFORM]);
|
arr_free(&shader->blocks[BLOCK_UNIFORM]);
|
||||||
vec_deinit(&shader->blocks[BLOCK_COMPUTE]);
|
arr_free(&shader->blocks[BLOCK_COMPUTE]);
|
||||||
map_deinit(&shader->attributes);
|
map_deinit(&shader->attributes);
|
||||||
map_deinit(&shader->uniformMap);
|
map_deinit(&shader->uniformMap);
|
||||||
map_deinit(&shader->blockMap);
|
map_deinit(&shader->blockMap);
|
||||||
|
|
|
@ -159,11 +159,11 @@ void lovrShaderSetBlock(Shader* shader, const char* name, Buffer* buffer, size_t
|
||||||
// ShaderBlock
|
// ShaderBlock
|
||||||
|
|
||||||
// Calculates uniform size and byte offsets using std140 rules, returning the total buffer size
|
// 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;
|
size_t size = 0;
|
||||||
Uniform* uniform; int i;
|
for (size_t i = 0; i < uniforms->length; i++) {
|
||||||
vec_foreach_ptr(uniforms, uniform, i) {
|
|
||||||
int align;
|
int align;
|
||||||
|
Uniform* uniform = &uniforms->data[i];
|
||||||
if (uniform->count > 1 || uniform->type == UNIFORM_MATRIX) {
|
if (uniform->count > 1 || uniform->type == UNIFORM_MATRIX) {
|
||||||
align = 16 * (uniform->type == UNIFORM_MATRIX ? uniform->components : 1);
|
align = 16 * (uniform->type == UNIFORM_MATRIX ? uniform->components : 1);
|
||||||
uniform->size = align * uniform->count;
|
uniform->size = align * uniform->count;
|
||||||
|
@ -177,14 +177,14 @@ size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms) {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, vec_uniform_t* uniforms) {
|
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, arr_uniform_t* uniforms) {
|
||||||
vec_init(&block->uniforms);
|
arr_init(&block->uniforms);
|
||||||
map_init(&block->uniformMap);
|
map_init(&block->uniformMap);
|
||||||
|
|
||||||
Uniform* uniform; int i;
|
arr_append(&block->uniforms, uniforms->data, uniforms->length);
|
||||||
vec_extend(&block->uniforms, uniforms);
|
|
||||||
vec_foreach_ptr(&block->uniforms, uniform, i) {
|
for (size_t i = 0; i < block->uniforms.length; i++) {
|
||||||
map_set(&block->uniformMap, uniform->name, i);
|
map_set(&block->uniformMap, block->uniforms.data[i].name, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
block->type = type;
|
block->type = type;
|
||||||
|
@ -196,7 +196,7 @@ ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buf
|
||||||
void lovrShaderBlockDestroy(void* ref) {
|
void lovrShaderBlockDestroy(void* ref) {
|
||||||
ShaderBlock* block = ref;
|
ShaderBlock* block = ref;
|
||||||
lovrRelease(Buffer, block->buffer);
|
lovrRelease(Buffer, block->buffer);
|
||||||
vec_deinit(&block->uniforms);
|
arr_free(&block->uniforms);
|
||||||
map_deinit(&block->uniformMap);
|
map_deinit(&block->uniformMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, si
|
||||||
size += 1; // " "
|
size += 1; // " "
|
||||||
size += strlen(blockName);
|
size += strlen(blockName);
|
||||||
size += 3; // " {\n"
|
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 += tab;
|
||||||
size += getUniformTypeLength(&block->uniforms.data[i]);
|
size += getUniformTypeLength(&block->uniforms.data[i]);
|
||||||
size += 1; // " "
|
size += 1; // " "
|
||||||
|
@ -231,7 +231,7 @@ char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, si
|
||||||
// Concatenate
|
// Concatenate
|
||||||
char* s = code;
|
char* s = code;
|
||||||
s += sprintf(s, "layout(std140) %s %s {\n", block->type == BLOCK_UNIFORM ? "uniform" : "buffer", blockName);
|
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];
|
const Uniform* uniform = &block->uniforms.data[i];
|
||||||
if (uniform->count > 1) {
|
if (uniform->count > 1) {
|
||||||
s += sprintf(s, " %s %s[%d];\n", getUniformTypeName(uniform), uniform->name, uniform->count);
|
s += sprintf(s, " %s %s[%d];\n", getUniformTypeName(uniform), uniform->name, uniform->count);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "graphics/opengl.h"
|
#include "graphics/opengl.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "lib/map/map.h"
|
#include "lib/map/map.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -89,17 +89,17 @@ typedef struct Uniform {
|
||||||
bool dirty;
|
bool dirty;
|
||||||
} Uniform;
|
} Uniform;
|
||||||
|
|
||||||
typedef vec_t(Uniform) vec_uniform_t;
|
typedef arr_t(Uniform, 8) arr_uniform_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BlockType type;
|
BlockType type;
|
||||||
vec_uniform_t uniforms;
|
arr_uniform_t uniforms;
|
||||||
map_int_t uniformMap;
|
map_int_t uniformMap;
|
||||||
struct Buffer* buffer;
|
struct Buffer* buffer;
|
||||||
} ShaderBlock;
|
} ShaderBlock;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vec_uniform_t uniforms;
|
arr_uniform_t uniforms;
|
||||||
UniformAccess access;
|
UniformAccess access;
|
||||||
struct Buffer* source;
|
struct Buffer* source;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
@ -107,12 +107,12 @@ typedef struct {
|
||||||
int slot;
|
int slot;
|
||||||
} UniformBlock;
|
} UniformBlock;
|
||||||
|
|
||||||
typedef vec_t(UniformBlock) vec_block_t;
|
typedef arr_t(UniformBlock, 1) arr_block_t;
|
||||||
|
|
||||||
typedef struct Shader {
|
typedef struct Shader {
|
||||||
ShaderType type;
|
ShaderType type;
|
||||||
vec_uniform_t uniforms;
|
arr_uniform_t uniforms;
|
||||||
vec_block_t blocks[2];
|
arr_block_t blocks[2];
|
||||||
map_int_t attributes;
|
map_int_t attributes;
|
||||||
map_int_t uniformMap;
|
map_int_t uniformMap;
|
||||||
map_int_t blockMap;
|
map_int_t blockMap;
|
||||||
|
@ -142,9 +142,9 @@ void lovrShaderSetBlock(Shader* shader, const char* name, struct Buffer* buffer,
|
||||||
|
|
||||||
// ShaderBlock
|
// 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__)
|
#define lovrShaderBlockCreate(...) lovrShaderBlockInit(lovrAlloc(ShaderBlock), __VA_ARGS__)
|
||||||
void lovrShaderBlockDestroy(void* ref);
|
void lovrShaderBlockDestroy(void* ref);
|
||||||
BlockType lovrShaderBlockGetType(ShaderBlock* block);
|
BlockType lovrShaderBlockGetType(ShaderBlock* block);
|
||||||
|
|
|
@ -86,7 +86,7 @@ static struct {
|
||||||
RenderModel_t* deviceModels[16];
|
RenderModel_t* deviceModels[16];
|
||||||
RenderModel_TextureMap_t* deviceTextures[16];
|
RenderModel_TextureMap_t* deviceTextures[16];
|
||||||
Canvas* canvas;
|
Canvas* canvas;
|
||||||
vec_float_t boundsGeometry;
|
float boundsGeometry[16];
|
||||||
float clipNear;
|
float clipNear;
|
||||||
float clipFar;
|
float clipFar;
|
||||||
float offset;
|
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.offset = state.compositor->GetTrackingSpace() == ETrackingUniverseOrigin_TrackingUniverseStanding ? 0. : offset;
|
||||||
state.msaa = msaa;
|
state.msaa = msaa;
|
||||||
|
|
||||||
vec_init(&state.boundsGeometry);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +220,6 @@ static void openvr_destroy(void) {
|
||||||
state.deviceModels[i] = NULL;
|
state.deviceModels[i] = NULL;
|
||||||
state.deviceTextures[i] = NULL;
|
state.deviceTextures[i] = NULL;
|
||||||
}
|
}
|
||||||
vec_deinit(&state.boundsGeometry);
|
|
||||||
VR_ShutdownInternal();
|
VR_ShutdownInternal();
|
||||||
memset(&state, 0, sizeof(state));
|
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) {
|
static const float* openvr_getBoundsGeometry(uint32_t* count) {
|
||||||
struct HmdQuad_t quad;
|
struct HmdQuad_t quad;
|
||||||
if (state.chaperone->GetPlayAreaRect(&quad)) {
|
if (state.chaperone->GetPlayAreaRect(&quad)) {
|
||||||
vec_clear(&state.boundsGeometry);
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
vec_push(&state.boundsGeometry, quad.vCorners[i].v[0]);
|
state.boundsGeometry[4 * i + 0] = quad.vCorners[i].v[0];
|
||||||
vec_push(&state.boundsGeometry, quad.vCorners[i].v[1]);
|
state.boundsGeometry[4 * i + 1] = quad.vCorners[i].v[1];
|
||||||
vec_push(&state.boundsGeometry, quad.vCorners[i].v[2]);
|
state.boundsGeometry[4 * i + 2] = quad.vCorners[i].v[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
*count = state.boundsGeometry.length;
|
return *count = 16, state.boundsGeometry;
|
||||||
return state.boundsGeometry.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
// Explicit curve evaluation, unroll simple cases to avoid pow overhead
|
// 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) {
|
if (n == 2) {
|
||||||
p[0] = P[0] + (P[4] - P[0]) * t;
|
p[0] = P[0] + (P[4] - P[0]) * t;
|
||||||
p[1] = P[1] + (P[5] - P[1]) * 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 {
|
} else {
|
||||||
float b = 1.f;
|
float b = 1.f;
|
||||||
p[0] = p[1] = p[2] = p[3] = 0.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 c1 = powf(1 - t, n - (i + 1));
|
||||||
float c2 = powf(t, i);
|
float c2 = powf(t, i);
|
||||||
p[0] += b * c1 * c2 * P[i * 4 + 0];
|
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) {
|
Curve* lovrCurveInit(Curve* curve) {
|
||||||
vec_init(&curve->points);
|
arr_init(&curve->points);
|
||||||
lovrAssert(!vec_reserve(&curve->points, sizeHint * 4), "Out of memory");
|
|
||||||
return curve;
|
return curve;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrCurveDestroy(void* ref) {
|
void lovrCurveDestroy(void* ref) {
|
||||||
Curve* curve = ref;
|
Curve* curve = ref;
|
||||||
vec_deinit(&curve->points);
|
arr_free(&curve->points);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrCurveEvaluate(Curve* curve, float t, vec3 p) {
|
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) {
|
void lovrCurveGetTangent(Curve* curve, float t, vec3 p) {
|
||||||
float q[4];
|
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, n - 1, t, q);
|
||||||
evaluate(curve->points.data + 4, n - 1, t, p);
|
evaluate(curve->points.data + 4, n - 1, t, p);
|
||||||
vec3_add(p, vec3_scale(q, -1.f));
|
vec3_add(p, vec3_scale(q, -1.f));
|
||||||
vec3_normalize(p);
|
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(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]");
|
lovrAssert(t1 >= 0.f && t2 <= 1.f, "Curve render interval must be within [0, 1]");
|
||||||
float step = 1.f / (n - 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);
|
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(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]");
|
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;
|
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
|
// 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);
|
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
|
// Split segment at t2, taking left half
|
||||||
float t = (t2 - t1) / (1.f - t1);
|
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);
|
evaluate(new->points.data, i + 1, t, new->points.data + 4 * i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lovrCurveGetPointCount(Curve* curve) {
|
size_t lovrCurveGetPointCount(Curve* curve) {
|
||||||
return curve->points.length / 4;
|
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);
|
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);
|
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
|
// 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;
|
float* dest = curve->points.data + index * 4;
|
||||||
|
|
||||||
// Shift remaining points over (if any) to create empty space
|
// 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));
|
memcpy(dest, point, 4 * sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrCurveRemovePoint(Curve* curve, int index) {
|
void lovrCurveRemovePoint(Curve* curve, size_t index) {
|
||||||
vec_swapsplice(&curve->points, index * 4, 4);
|
arr_splice(&curve->points, index * 4, 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
#include "core/arr.h"
|
||||||
#include "core/maf.h"
|
#include "core/maf.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vec_float_t points;
|
arr_t(float, 16) points;
|
||||||
} Curve;
|
} Curve;
|
||||||
|
|
||||||
Curve* lovrCurveInit(Curve* curve, int sizeHint);
|
Curve* lovrCurveInit(Curve* curve);
|
||||||
#define lovrCurveCreate(...) lovrCurveInit(lovrAlloc(Curve), __VA_ARGS__)
|
#define lovrCurveCreate(...) lovrCurveInit(lovrAlloc(Curve))
|
||||||
void lovrCurveDestroy(void* ref);
|
void lovrCurveDestroy(void* ref);
|
||||||
void lovrCurveEvaluate(Curve* curve, float t, vec3 point);
|
void lovrCurveEvaluate(Curve* curve, float t, vec3 point);
|
||||||
void lovrCurveGetTangent(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);
|
Curve* lovrCurveSlice(Curve* curve, float t1, float t2);
|
||||||
int lovrCurveGetPointCount(Curve* curve);
|
size_t lovrCurveGetPointCount(Curve* curve);
|
||||||
void lovrCurveGetPoint(Curve* curve, int index, vec3 point);
|
void lovrCurveGetPoint(Curve* curve, size_t index, vec3 point);
|
||||||
void lovrCurveSetPoint(Curve* curve, int index, vec3 point);
|
void lovrCurveSetPoint(Curve* curve, size_t index, vec3 point);
|
||||||
void lovrCurveAddPoint(Curve* curve, vec3 point, int index);
|
void lovrCurveAddPoint(Curve* curve, vec3 point, size_t index);
|
||||||
void lovrCurveRemovePoint(Curve* curve, int 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) {
|
static void customNearCallback(void* data, dGeomID shapeA, dGeomID shapeB) {
|
||||||
World* world = data;
|
World* world = data;
|
||||||
vec_push(&world->overlaps, dGeomGetData(shapeA));
|
arr_push(&world->overlaps, dGeomGetData(shapeA));
|
||||||
vec_push(&world->overlaps, dGeomGetData(shapeB));
|
arr_push(&world->overlaps, dGeomGetData(shapeB));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raycastCallback(void* data, dGeomID a, dGeomID b) {
|
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);
|
world->space = dHashSpaceCreate(0);
|
||||||
dHashSpaceSetLevels(world->space, -4, 8);
|
dHashSpaceSetLevels(world->space, -4, 8);
|
||||||
world->contactGroup = dJointGroupCreate(0);
|
world->contactGroup = dJointGroupCreate(0);
|
||||||
vec_init(&world->overlaps);
|
arr_init(&world->overlaps);
|
||||||
lovrWorldSetGravity(world, xg, yg, zg);
|
lovrWorldSetGravity(world, xg, yg, zg);
|
||||||
lovrWorldSetSleepingAllowed(world, allowSleep);
|
lovrWorldSetSleepingAllowed(world, allowSleep);
|
||||||
map_init(&world->tags);
|
map_init(&world->tags);
|
||||||
|
@ -68,7 +68,7 @@ World* lovrWorldInit(World* world, float xg, float yg, float zg, bool allowSleep
|
||||||
void lovrWorldDestroy(void* ref) {
|
void lovrWorldDestroy(void* ref) {
|
||||||
World* world = ref;
|
World* world = ref;
|
||||||
lovrWorldDestroyData(world);
|
lovrWorldDestroyData(world);
|
||||||
vec_deinit(&world->overlaps);
|
arr_free(&world->overlaps);
|
||||||
map_deinit(&world->tags);
|
map_deinit(&world->tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* u
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrWorldComputeOverlaps(World* world) {
|
void lovrWorldComputeOverlaps(World* world) {
|
||||||
vec_clear(&world->overlaps);
|
arr_clear(&world->overlaps);
|
||||||
dSpaceCollide(world->space, world, customNearCallback);
|
dSpaceCollide(world->space, world, customNearCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,8 +120,8 @@ int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*a = vec_pop(&world->overlaps);
|
*a = arr_pop(&world->overlaps);
|
||||||
*b = vec_pop(&world->overlaps);
|
*b = arr_pop(&world->overlaps);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,8 +278,8 @@ Collider* lovrColliderInit(Collider* collider, World* world, float x, float y, f
|
||||||
collider->restitution = 0;
|
collider->restitution = 0;
|
||||||
collider->tag = NO_TAG;
|
collider->tag = NO_TAG;
|
||||||
dBodySetData(collider->body, collider);
|
dBodySetData(collider->body, collider);
|
||||||
vec_init(&collider->shapes);
|
arr_init(&collider->shapes);
|
||||||
vec_init(&collider->joints);
|
arr_init(&collider->joints);
|
||||||
|
|
||||||
lovrColliderSetPosition(collider, x, y, z);
|
lovrColliderSetPosition(collider, x, y, z);
|
||||||
|
|
||||||
|
@ -300,8 +300,8 @@ Collider* lovrColliderInit(Collider* collider, World* world, float x, float y, f
|
||||||
void lovrColliderDestroy(void* ref) {
|
void lovrColliderDestroy(void* ref) {
|
||||||
Collider* collider = ref;
|
Collider* collider = ref;
|
||||||
lovrColliderDestroyData(collider);
|
lovrColliderDestroyData(collider);
|
||||||
vec_deinit(&collider->shapes);
|
arr_free(&collider->shapes);
|
||||||
vec_deinit(&collider->joints);
|
arr_free(&collider->joints);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrColliderDestroyData(Collider* collider) {
|
void lovrColliderDestroyData(Collider* collider) {
|
||||||
|
@ -309,16 +309,16 @@ void lovrColliderDestroyData(Collider* collider) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_void_t* shapes = lovrColliderGetShapes(collider);
|
size_t count;
|
||||||
Shape* shape; int i;
|
|
||||||
vec_foreach(shapes, shape, i) {
|
Shape** shapes = lovrColliderGetShapes(collider, &count);
|
||||||
lovrColliderRemoveShape(collider, shape);
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
lovrColliderRemoveShape(collider, shapes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_void_t* joints = lovrColliderGetJoints(collider);
|
Joint** joints = lovrColliderGetJoints(collider, &count);
|
||||||
Joint* joint; int j;
|
for (size_t i = 0; i < count; i++) {
|
||||||
vec_foreach(joints, joint, j) {
|
lovrRelease(Joint, joints[i]);
|
||||||
lovrRelease(Joint, joint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dBodyDestroy(collider->body);
|
dBodyDestroy(collider->body);
|
||||||
|
@ -359,27 +359,27 @@ void lovrColliderRemoveShape(Collider* collider, Shape* shape) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_void_t* lovrColliderGetShapes(Collider* collider) {
|
Shape** lovrColliderGetShapes(Collider* collider, size_t* count) {
|
||||||
vec_clear(&collider->shapes);
|
arr_clear(&collider->shapes);
|
||||||
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) {
|
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) {
|
||||||
Shape* shape = dGeomGetData(geom);
|
Shape* shape = dGeomGetData(geom);
|
||||||
if (shape) {
|
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) {
|
Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
|
||||||
vec_clear(&collider->joints);
|
arr_clear(&collider->joints);
|
||||||
int jointCount = dBodyGetNumJoints(collider->body);
|
int jointCount = dBodyGetNumJoints(collider->body);
|
||||||
for (int i = 0; i < jointCount; i++) {
|
for (int i = 0; i < jointCount; i++) {
|
||||||
Joint* joint = dJointGetData(dBodyGetJoint(collider->body, i));
|
Joint* joint = dJointGetData(dBodyGetJoint(collider->body, i));
|
||||||
if (joint) {
|
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) {
|
void* lovrColliderGetUserData(Collider* collider) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "lib/vec/vec.h"
|
#include "core/arr.h"
|
||||||
#include "lib/map/map.h"
|
#include "lib/map/map.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -25,12 +25,14 @@ typedef enum {
|
||||||
} JointType;
|
} JointType;
|
||||||
|
|
||||||
typedef struct Collider Collider;
|
typedef struct Collider Collider;
|
||||||
|
typedef struct Shape Shape;
|
||||||
|
typedef struct Joint Joint;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
dWorldID id;
|
dWorldID id;
|
||||||
dSpaceID space;
|
dSpaceID space;
|
||||||
dJointGroupID contactGroup;
|
dJointGroupID contactGroup;
|
||||||
vec_void_t overlaps;
|
arr_t(Shape*, 8) overlaps;
|
||||||
map_int_t tags;
|
map_int_t tags;
|
||||||
uint16_t masks[MAX_TAGS];
|
uint16_t masks[MAX_TAGS];
|
||||||
Collider* head;
|
Collider* head;
|
||||||
|
@ -43,29 +45,29 @@ struct Collider {
|
||||||
Collider* next;
|
Collider* next;
|
||||||
void* userdata;
|
void* userdata;
|
||||||
int tag;
|
int tag;
|
||||||
vec_void_t shapes;
|
arr_t(Shape*, 2) shapes;
|
||||||
vec_void_t joints;
|
arr_t(Joint*, 2) joints;
|
||||||
float friction;
|
float friction;
|
||||||
float restitution;
|
float restitution;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Shape {
|
struct Shape {
|
||||||
ShapeType type;
|
ShapeType type;
|
||||||
dGeomID id;
|
dGeomID id;
|
||||||
Collider* collider;
|
Collider* collider;
|
||||||
void* userdata;
|
void* userdata;
|
||||||
} Shape;
|
};
|
||||||
|
|
||||||
typedef Shape SphereShape;
|
typedef Shape SphereShape;
|
||||||
typedef Shape BoxShape;
|
typedef Shape BoxShape;
|
||||||
typedef Shape CapsuleShape;
|
typedef Shape CapsuleShape;
|
||||||
typedef Shape CylinderShape;
|
typedef Shape CylinderShape;
|
||||||
|
|
||||||
typedef struct Joint {
|
struct Joint {
|
||||||
JointType type;
|
JointType type;
|
||||||
dJointID id;
|
dJointID id;
|
||||||
void* userdata;
|
void* userdata;
|
||||||
} Joint;
|
};
|
||||||
|
|
||||||
typedef Joint BallJoint;
|
typedef Joint BallJoint;
|
||||||
typedef Joint DistanceJoint;
|
typedef Joint DistanceJoint;
|
||||||
|
@ -112,8 +114,8 @@ void lovrColliderDestroyData(Collider* collider);
|
||||||
World* lovrColliderGetWorld(Collider* collider);
|
World* lovrColliderGetWorld(Collider* collider);
|
||||||
void lovrColliderAddShape(Collider* collider, Shape* shape);
|
void lovrColliderAddShape(Collider* collider, Shape* shape);
|
||||||
void lovrColliderRemoveShape(Collider* collider, Shape* shape);
|
void lovrColliderRemoveShape(Collider* collider, Shape* shape);
|
||||||
vec_void_t* lovrColliderGetShapes(Collider* collider);
|
Shape** lovrColliderGetShapes(Collider* collider, size_t* count);
|
||||||
vec_void_t* lovrColliderGetJoints(Collider* collider);
|
Joint** lovrColliderGetJoints(Collider* collider, size_t* count);
|
||||||
void* lovrColliderGetUserData(Collider* collider);
|
void* lovrColliderGetUserData(Collider* collider);
|
||||||
void lovrColliderSetUserData(Collider* collider, void* data);
|
void lovrColliderSetUserData(Collider* collider, void* data);
|
||||||
const char* lovrColliderGetTag(Collider* collider);
|
const char* lovrColliderGetTag(Collider* collider);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
Channel* lovrChannelInit(Channel* channel) {
|
Channel* lovrChannelInit(Channel* channel) {
|
||||||
vec_init(&channel->messages);
|
arr_init(&channel->messages);
|
||||||
mtx_init(&channel->lock, mtx_plain | mtx_timed);
|
mtx_init(&channel->lock, mtx_plain | mtx_timed);
|
||||||
cnd_init(&channel->cond);
|
cnd_init(&channel->cond);
|
||||||
return channel;
|
return channel;
|
||||||
|
@ -14,7 +14,7 @@ Channel* lovrChannelInit(Channel* channel) {
|
||||||
void lovrChannelDestroy(void* ref) {
|
void lovrChannelDestroy(void* ref) {
|
||||||
Channel* channel = ref;
|
Channel* channel = ref;
|
||||||
lovrChannelClear(channel);
|
lovrChannelClear(channel);
|
||||||
vec_deinit(&channel->messages);
|
arr_free(&channel->messages);
|
||||||
mtx_destroy(&channel->lock);
|
mtx_destroy(&channel->lock);
|
||||||
cnd_destroy(&channel->cond);
|
cnd_destroy(&channel->cond);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ bool lovrChannelPush(Channel* channel, Variant variant, double timeout, uint64_t
|
||||||
if (channel->messages.length == 0) {
|
if (channel->messages.length == 0) {
|
||||||
lovrRetain(channel);
|
lovrRetain(channel);
|
||||||
}
|
}
|
||||||
vec_insert(&channel->messages, 0, variant);
|
arr_push(&channel->messages, variant);
|
||||||
*id = ++channel->sent;
|
*id = ++channel->sent;
|
||||||
cnd_broadcast(&channel->cond);
|
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;
|
until.tv_nsec = start.tv_nsec + fraction * 1e9;
|
||||||
cnd_timedwait(&channel->cond, &channel->lock, &until);
|
cnd_timedwait(&channel->cond, &channel->lock, &until);
|
||||||
timespec_get(&stop, TIME_UTC);
|
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);
|
mtx_lock(&channel->lock);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (channel->messages.length > 0) {
|
if (channel->head < channel->messages.length) {
|
||||||
*variant = vec_pop(&channel->messages);
|
*variant = channel->messages.data[channel->head++];
|
||||||
if (channel->messages.length == 0) {
|
if (channel->head == channel->messages.length) {
|
||||||
|
channel->head = channel->messages.length = 0;
|
||||||
lovrRelease(Channel, channel);
|
lovrRelease(Channel, channel);
|
||||||
}
|
}
|
||||||
channel->received++;
|
channel->received++;
|
||||||
|
@ -89,14 +90,14 @@ bool lovrChannelPop(Channel* channel, Variant* variant, double timeout) {
|
||||||
timespec_get(&stop, TIME_UTC);
|
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) / (double) 1e9;
|
||||||
}
|
}
|
||||||
} while (true);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrChannelPeek(Channel* channel, Variant* variant) {
|
bool lovrChannelPeek(Channel* channel, Variant* variant) {
|
||||||
mtx_lock(&channel->lock);
|
mtx_lock(&channel->lock);
|
||||||
|
|
||||||
if (channel->messages.length > 0) {
|
if (channel->head < channel->messages.length) {
|
||||||
*variant = vec_last(&channel->messages);
|
*variant = channel->messages.data[channel->head];
|
||||||
mtx_unlock(&channel->lock);
|
mtx_unlock(&channel->lock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -107,18 +108,19 @@ bool lovrChannelPeek(Channel* channel, Variant* variant) {
|
||||||
|
|
||||||
void lovrChannelClear(Channel* channel) {
|
void lovrChannelClear(Channel* channel) {
|
||||||
mtx_lock(&channel->lock);
|
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]);
|
lovrVariantDestroy(&channel->messages.data[i]);
|
||||||
}
|
}
|
||||||
channel->received = channel->sent;
|
channel->received = channel->sent;
|
||||||
vec_clear(&channel->messages);
|
arr_clear(&channel->messages);
|
||||||
|
channel->head = 0;
|
||||||
cnd_broadcast(&channel->cond);
|
cnd_broadcast(&channel->cond);
|
||||||
mtx_unlock(&channel->lock);
|
mtx_unlock(&channel->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t lovrChannelGetCount(Channel* channel) {
|
uint64_t lovrChannelGetCount(Channel* channel) {
|
||||||
mtx_lock(&channel->lock);
|
mtx_lock(&channel->lock);
|
||||||
uint64_t length = channel->messages.length;
|
uint64_t length = channel->messages.length - channel->head;
|
||||||
mtx_unlock(&channel->lock);
|
mtx_unlock(&channel->lock);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
|
#include "core/arr.h"
|
||||||
#include "lib/tinycthread/tinycthread.h"
|
#include "lib/tinycthread/tinycthread.h"
|
||||||
#include "lib/vec/vec.h"
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
typedef struct Channel {
|
typedef struct Channel {
|
||||||
mtx_t lock;
|
mtx_t lock;
|
||||||
cnd_t cond;
|
cnd_t cond;
|
||||||
vec_t(Variant) messages;
|
arr_t(Variant, 1) messages;
|
||||||
|
size_t head;
|
||||||
uint64_t sent;
|
uint64_t sent;
|
||||||
uint64_t received;
|
uint64_t received;
|
||||||
} Channel;
|
} Channel;
|
||||||
|
|
Loading…
Reference in New Issue