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:
bjorn 2019-06-08 03:45:03 -07:00
parent f8f6d98df4
commit eb1e257209
37 changed files with 558 additions and 788 deletions

View File

@ -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
) )

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

22
src/core/arr.c Normal file
View File

@ -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");
}
}

42
src/core/arr.h Normal file
View File

@ -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);

View File

@ -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.

View File

@ -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++;
}
}

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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;
} }

View File

@ -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) {

View File

@ -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);
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;
} }

View 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) {

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;