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
src/main.c
src/core/arr.c
src/core/luax.c
src/core/maf.c
src/core/platform.c
@ -324,7 +325,6 @@ set(LOVR_SRC
src/core/util.c
src/api/l_lovr.c
src/lib/map/map.c
src/lib/vec/vec.c
src/lib/sds/sds.c
)

View File

@ -31,10 +31,11 @@ static int l_lovrColliderRemoveShape(lua_State* L) {
static int l_lovrColliderGetShapes(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
lua_newtable(L);
vec_void_t* shapes = lovrColliderGetShapes(collider);
for (int i = 0; i < shapes->length; i++) {
luax_pushshape(L, shapes->data[i]);
size_t count;
Shape** shapes = lovrColliderGetShapes(collider, &count);
lua_createtable(L, count, 0);
for (size_t i = 0; i < count; i++) {
luax_pushshape(L, shapes[i]);
lua_rawseti(L, -2, i + 1);
}
return 1;
@ -42,10 +43,11 @@ static int l_lovrColliderGetShapes(lua_State* L) {
static int l_lovrColliderGetJoints(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
lua_newtable(L);
vec_void_t* joints = lovrColliderGetJoints(collider);
for (int i = 0; i < joints->length; i++) {
luax_pushjoint(L, joints->data[i]);
size_t count;
Joint** joints = lovrColliderGetJoints(collider, &count);
lua_createtable(L, count, 0);
for (size_t i = 0; i < count; i++) {
luax_pushjoint(L, joints[i]);
lua_rawseti(L, -2, i + 1);
}
return 1;

View File

@ -33,13 +33,14 @@ static int l_lovrCurveRender(lua_State* L) {
lovrAssert(points, "Out of memory");
lovrCurveRender(curve, t1, t2, points, n);
lua_createtable(L, n, 0);
for (int i = 0; i < n; i += 4) {
int j = 1;
for (int i = 0; i < 4 * n; i += 4) {
lua_pushnumber(L, points[i + 0]);
lua_rawseti(L, -2, i + 1);
lua_rawseti(L, -2, j++);
lua_pushnumber(L, points[i + 1]);
lua_rawseti(L, -2, i + 2);;
lua_rawseti(L, -2, j++);
lua_pushnumber(L, points[i + 2]);
lua_rawseti(L, -2, i + 3);
lua_rawseti(L, -2, j++);
}
free(points);
return 1;
@ -62,7 +63,7 @@ static int l_lovrCurveGetPointCount(lua_State* L) {
static int l_lovrCurveGetPoint(lua_State* L) {
Curve* curve = luax_checktype(L, 1, Curve);
int index = luaL_checkinteger(L, 2) - 1;
size_t index = luaL_checkinteger(L, 2) - 1;
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
float point[4];
lovrCurveGetPoint(curve, index, point);
@ -74,7 +75,7 @@ static int l_lovrCurveGetPoint(lua_State* L) {
static int l_lovrCurveSetPoint(lua_State* L) {
Curve* curve = luax_checktype(L, 1, Curve);
int index = luaL_checkinteger(L, 2) - 1;
size_t index = luaL_checkinteger(L, 2) - 1;
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
float point[4];
luax_readvec3(L, 3, point, NULL);
@ -86,7 +87,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
Curve* curve = luax_checktype(L, 1, Curve);
float point[4];
int i = luax_readvec3(L, 2, point, NULL);
int index = lua_isnoneornil(L, i) ? lovrCurveGetPointCount(curve) : luaL_checkinteger(L, i) - 1;
size_t index = lua_isnoneornil(L, i) ? lovrCurveGetPointCount(curve) : luaL_checkinteger(L, i) - 1;
lovrAssert(index >= 0 && index <= lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
lovrCurveAddPoint(curve, point, index);
return 0;
@ -94,7 +95,7 @@ static int l_lovrCurveAddPoint(lua_State* L) {
static int l_lovrCurveRemovePoint(lua_State* L) {
Curve* curve = luax_checktype(L, 1, Curve);
int index = luaL_checkinteger(L, 2) - 1;
size_t index = luaL_checkinteger(L, 2) - 1;
lovrAssert(index >= 0 && index < lovrCurveGetPointCount(curve), "Invalid Curve point index: %d", index + 1);
lovrCurveRemovePoint(curve, index);
return 0;

View File

@ -7,6 +7,7 @@
#include "data/textureData.h"
#include "core/ref.h"
#include <stdlib.h>
#include <string.h>
static int l_lovrDataNewBlob(lua_State* L) {
size_t size;

View File

@ -1,8 +1,10 @@
#include "api.h"
#include "filesystem/filesystem.h"
#include "filesystem/file.h"
#include "data/blob.h"
#include "core/ref.h"
#include <stdlib.h>
#include <string.h>
#include "platform.h"
// Returns a Blob, leaving stack unchanged. The Blob must be released when finished.
@ -32,65 +34,28 @@ static int pushDirectoryItem(void* userdata, const char* path, const char* filen
return 1;
}
static int l_lovrFilesystemLoad(lua_State* L);
typedef struct {
File file;
char buffer[4096];
} luax_Reader;
static int moduleLoader(lua_State* L) {
const char* module = luaL_gsub(L, lua_tostring(L, -1), ".", "/");
lua_pop(L, 2);
char* path; int i;
vec_foreach(lovrFilesystemGetRequirePath(), path, i) {
const char* filename = luaL_gsub(L, path, "?", module);
if (lovrFilesystemIsFile(filename)) {
return l_lovrFilesystemLoad(L);
}
lua_pop(L, 1);
}
return 0;
static const char* readCallback(lua_State* L, void* data, size_t* size) {
luax_Reader* reader = data;
*size = lovrFileRead(&reader->file, reader->buffer, sizeof(reader->buffer));
return *size == 0 ? NULL : reader->buffer;
}
static const char* libraryExtensions[] = {
#ifdef _WIN32
".dll", NULL
#elif __APPLE__
".so", ".dylib", NULL
#else
".so", NULL
#endif
};
static int libraryLoader(lua_State* L) {
const char* modulePath = luaL_gsub(L, lua_tostring(L, -1), ".", "/");
const char* moduleFunction = luaL_gsub(L, lua_tostring(L, -1), ".", "_");
char* hyphen = strchr(moduleFunction, '-');
moduleFunction = hyphen ? hyphen + 1 : moduleFunction;
lua_pop(L, 3);
char* path; int i;
vec_foreach(lovrFilesystemGetCRequirePath(), path, i) {
for (const char** extension = libraryExtensions; *extension != NULL; extension++) {
char buffer[64];
snprintf(buffer, 63, "%s%s", modulePath, *extension);
const char* filename = luaL_gsub(L, path, "??", buffer);
filename = luaL_gsub(L, filename, "?", modulePath);
lua_pop(L, 2);
if (lovrFilesystemIsFile(filename)) {
char fullPath[LOVR_PATH_MAX];
const char* realPath = lovrFilesystemGetRealDirectory(filename);
snprintf(fullPath, LOVR_PATH_MAX - 1, "%s%c%s", realPath, lovrDirSep, filename);
lua_getglobal(L, "package");
lua_getfield(L, -1, "loadlib");
lua_pushstring(L, fullPath);
lua_pushfstring(L, "luaopen_%s", moduleFunction);
lua_call(L, 2, 1);
return 1;
}
}
static int luax_loadfile(lua_State* L, const char* path, const char* debug) {
luax_Reader reader;
lovrFileInit(&reader.file, path);
lovrAssert(lovrFileOpen(&reader.file, OPEN_READ), "Could not open file %s", path);
int status = lua_load(L, readCallback, &reader, debug);
lovrFileDestroy(&reader.file);
switch (status) {
case LUA_ERRMEM: return luaL_error(L, "Memory allocation error: %s", lua_tostring(L, -1));
case LUA_ERRSYNTAX: return luaL_error(L, "Syntax error: %s", lua_tostring(L, -1));
default: return 1;
}
return 0;
}
static int l_lovrFilesystemAppend(lua_State* L) {
@ -167,19 +132,9 @@ static int l_lovrFilesystemGetRealDirectory(lua_State* L) {
return 1;
}
static void pushRequirePath(lua_State* L, vec_str_t* path) {
char* pattern; int i;
vec_foreach(path, pattern, i) {
lua_pushstring(L, pattern);
lua_pushliteral(L, ";");
}
lua_pop(L, 1);
lua_concat(L, path->length * 2 - 1);
}
static int l_lovrFilesystemGetRequirePath(lua_State* L) {
pushRequirePath(L, lovrFilesystemGetRequirePath());
pushRequirePath(L, lovrFilesystemGetCRequirePath());
lua_pushstring(L, lovrFilesystemGetRequirePath());
lua_pushstring(L, lovrFilesystemGetCRequirePath());
return 2;
}
@ -246,23 +201,9 @@ static int l_lovrFilesystemIsFused(lua_State* L) {
static int l_lovrFilesystemLoad(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
size_t size;
char* content = lovrFilesystemRead(path, -1, &size);
if (!content) {
return luaL_error(L, "Could not read file '%s'", path);
}
char debug[LOVR_PATH_MAX];
snprintf(debug, LOVR_PATH_MAX, "@%s", path);
int status = luaL_loadbuffer(L, content, size, debug);
free(content);
switch (status) {
case LUA_ERRMEM: return luaL_error(L, "Memory allocation error: %s", lua_tostring(L, -1));
case LUA_ERRSYNTAX: return luaL_error(L, "Syntax error: %s", lua_tostring(L, -1));
default: return 1;
}
lua_pushfstring(L, "@%s", path);
const char* debug = lua_tostring(L, -1);
return luax_loadfile(L, path, debug);
}
static int l_lovrFilesystemMount(lua_State* L) {
@ -318,8 +259,8 @@ static int l_lovrFilesystemSetIdentity(lua_State* L) {
}
static int l_lovrFilesystemSetRequirePath(lua_State* L) {
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(luaL_checkstring(L, 1));
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(luaL_checkstring(L, 2));
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(lua_tostring(L, 1));
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(lua_tostring(L, 2));
return 0;
}
@ -379,6 +320,129 @@ static const luaL_Reg lovrFilesystem[] = {
{ NULL, NULL }
};
static int luaLoader(lua_State* L) {
const char* module = lua_tostring(L, 1);
const char* p = lovrFilesystemGetRequirePath();
char buffer[1024] = { '@' };
char* debug = &buffer[0];
char* filename = &buffer[1];
char* f = filename;
size_t n = sizeof(buffer) - 1;
// Loop over the require path, character by character, and:
// - Replace question marks with the module that's being required, converting '.' to '/'.
// - If there's a semicolon/eof, treat it as the end of a potential filename and try to load it.
// The filename buffer has an '@' before it so it can also be used as the debug label for the Lua
// chunk without additional memory allocation.
while (1) {
if (*p == ';' || *p == '\0') {
*f = '\0';
if (lovrFilesystemIsFile(filename)) {
return luax_loadfile(L, filename, debug);
}
if (*p == '\0') {
break;
} else {
p++;
f = filename;
n = sizeof(buffer) - 1;
}
} else if (*p == '?') {
for (const char* m = module; n && *m; n--, m++) {
*f++ = *m == '.' ? '/' : *m;
}
p++;
} else {
*f++ = *p++;
n--;
}
lovrAssert(n > 0, "Tried to require a filename that was too long (%s)", module);
}
return 0;
}
static int libLoader(lua_State* L) {
#ifdef _WIN32
const char* extension = ".dll";
#else
const char* extension = ".so";
#endif
const char* module = lua_tostring(L, 1);
const char* hyphen = strchr(module, '-');
const char* symbol = hyphen ? hyphen + 1 : module;
const char* p = lovrFilesystemGetCRequirePath();
char filename[1024];
char* f = filename;
size_t n = sizeof(filename);
lua_getglobal(L, "package");
while (1) {
if (*p == ';' || *p == '\0') {
*f = '\0';
if (lovrFilesystemIsFile(filename)) {
lua_getfield(L, -1, "loadlib");
// Synthesize the absolute path to the library on disk (outside of physfs)
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
luaL_addstring(&buffer, lovrFilesystemGetRealDirectory(filename));
luaL_addchar(&buffer, lovrDirSep);
luaL_addstring(&buffer, filename);
luaL_pushresult(&buffer);
// Synthesize the symbol to load: luaopen_ followed by the module name with dots converted
// to underscores, starting after the first hyphen (if there is one).
luaL_buffinit(L, &buffer);
luaL_addstring(&buffer, "luaopen_");
for (const char* s = symbol; *s; s++) {
luaL_addchar(&buffer, *s == '.' ? '_' : *s);
}
luaL_pushresult(&buffer);
// Finally call package.loadlib with the library path and symbol name
lua_call(L, 2, 1);
return 1;
}
if (*p == '\0') {
break;
} else {
p++;
f = filename;
n = sizeof(filename);
}
} else if (*p == '?') {
for (const char* m = module; n && *m; n--, m++) {
*f++ = *m == '.' ? lovrDirSep : *m;
}
p++;
if (*p == '?') {
for (const char* e = extension; n && *e; n--, e++) {
*f++ = *e;
}
p++;
}
} else {
*f++ = *p++;
n--;
}
lovrAssert(n > 0, "Tried to require a filename that was too long (%s)", module);
}
return 0;
}
int luaopen_lovr_filesystem(lua_State* L) {
lua_getglobal(L, "arg");
if (lua_istable(L, -1)) {
@ -401,7 +465,7 @@ int luaopen_lovr_filesystem(lua_State* L) {
lua_newtable(L);
luaL_register(L, NULL, lovrFilesystem);
luax_registerloader(L, moduleLoader, 2);
luax_registerloader(L, libraryLoader, 3);
luax_registerloader(L, luaLoader, 2);
luax_registerloader(L, libLoader, 3);
return 1;
}

View File

@ -11,6 +11,7 @@
#include "data/rasterizer.h"
#include "data/textureData.h"
#include "filesystem/filesystem.h"
#include "core/arr.h"
#include "core/ref.h"
#include "util.h"
#include <math.h>
@ -443,7 +444,7 @@ static int l_lovrGraphicsGetStats(lua_State* L) {
lua_pushinteger(L, stats->shaderSwitches);
lua_setfield(L, 1, "shaderswitches");
lua_createtable(L, 0, stats->timers.length);
for (int i = 0; i < stats->timers.length; i++) {
for (size_t i = 0; i < stats->timers.length; i++) {
lua_pushstring(L, stats->timers.data[i].label);
lua_pushnumber(L, stats->timers.data[i].time);
lua_settable(L, -3);
@ -1010,8 +1011,8 @@ static void luax_checkuniformtype(lua_State* L, int index, UniformType* baseType
}
static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
vec_uniform_t uniforms;
vec_init(&uniforms);
arr_uniform_t uniforms;
arr_init(&uniforms);
BlockType type = luaL_checkoption(L, 1, NULL, BlockTypes);
@ -1039,7 +1040,7 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
}
lovrAssert(uniform.count >= 1, "Uniform count must be positive, got %d for '%s'", uniform.count, uniform.name);
vec_push(&uniforms, uniform);
arr_push(&uniforms, uniform);
// Pop the table, leaving the key for lua_next to nom
lua_pop(L, 1);
@ -1063,7 +1064,7 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
Buffer* buffer = lovrBufferCreate(size, NULL, type == BLOCK_COMPUTE ? BUFFER_SHADER_STORAGE : BUFFER_UNIFORM, usage, readable);
ShaderBlock* block = lovrShaderBlockCreate(type, buffer, &uniforms);
luax_pushtype(L, ShaderBlock, block);
vec_deinit(&uniforms);
arr_free(&uniforms);
lovrRelease(Buffer, buffer);
lovrRelease(ShaderBlock, block);
return 1;

View File

@ -3,6 +3,7 @@
#include "data/modelData.h"
#include "graphics/model.h"
#include "graphics/texture.h"
#include "core/arr.h"
#include "core/maf.h"
#include "core/ref.h"
#include <stdlib.h>
@ -230,12 +231,17 @@ static int l_lovrHeadsetGetBoundsGeometry(lua_State* L) {
lua_settop(L, 1);
} else {
lua_settop(L, 0);
lua_createtable(L, count, 0);
lua_createtable(L, count / 4, 0);
}
for (uint32_t i = 0; i < count; i++) {
lua_pushnumber(L, points[i]);
lua_rawseti(L, 1, i + 1);
int j = 1;
for (uint32_t i = 0; i < count; i += 4) {
lua_pushnumber(L, points[i + 0]);
lua_rawseti(L, 1, j++);
lua_pushnumber(L, points[i + 1]);
lua_rawseti(L, 1, j++);
lua_pushnumber(L, points[i + 2]);
lua_rawseti(L, 1, j++);
}
return 1;
@ -608,8 +614,8 @@ int luaopen_lovr_headset(lua_State* L) {
luax_pushconf(L);
lua_getfield(L, -1, "headset");
vec_t(HeadsetDriver) drivers;
vec_init(&drivers);
arr_t(HeadsetDriver, 8) drivers;
arr_init(&drivers);
float offset = 1.7f;
int msaa = 4;
@ -620,7 +626,7 @@ int luaopen_lovr_headset(lua_State* L) {
int n = luax_len(L, -1);
for (int i = 0; i < n; i++) {
lua_rawgeti(L, -1, i + 1);
vec_push(&drivers, luaL_checkoption(L, -1, NULL, HeadsetDrivers));
arr_push(&drivers, luaL_checkoption(L, -1, NULL, HeadsetDrivers));
lua_pop(L, 1);
}
lua_pop(L, 1);
@ -640,7 +646,7 @@ int luaopen_lovr_headset(lua_State* L) {
luax_atexit(L, lovrHeadsetDestroy);
}
vec_deinit(&drivers);
arr_free(&drivers);
lua_pop(L, 2);
headsetRenderData.ref = LUA_NOREF;

View File

@ -79,16 +79,9 @@ float* luax_newmathtype(lua_State* L, MathType type) {
}
static int l_lovrMathNewCurve(lua_State* L) {
Curve* curve = lovrCurveCreate();
int top = lua_gettop(L);
if (top == 1 && lua_type(L, 1) == LUA_TNUMBER) {
Curve* curve = lovrCurveCreate(luaL_checkinteger(L, 1));
luax_pushtype(L, Curve, curve);
return 1;
}
Curve* curve = lovrCurveCreate(3);
if (lua_istable(L, 1)) {
int pointIndex = 0;
int length = luax_len(L, 1);

View File

@ -5,6 +5,7 @@
#include "thread/channel.h"
#include "core/ref.h"
#include <stdlib.h>
#include <string.h>
static int threadRunner(void* data) {
Thread* thread = (Thread*) data;

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/source.h"
#include "data/audioStream.h"
#include "core/arr.h"
#include "core/maf.h"
#include "core/ref.h"
#include "util.h"
#include "lib/vec/vec.h"
#include <stdlib.h>
#include <AL/al.h>
#include <AL/alc.h>
@ -15,10 +15,10 @@ static struct {
bool spatialized;
ALCdevice* device;
ALCcontext* context;
vec_void_t sources;
float LOVR_ALIGN(16) orientation[4];
float LOVR_ALIGN(16) position[4];
float LOVR_ALIGN(16) velocity[4];
arr_t(Source*, 32) sources;
} state;
ALenum lovrAudioConvertFormat(uint32_t bitDepth, uint32_t channelCount) {
@ -58,7 +58,7 @@ bool lovrAudioInit() {
state.device = device;
state.context = context;
vec_init(&state.sources);
arr_init(&state.sources);
return state.initialized = true;
}
@ -67,16 +67,17 @@ void lovrAudioDestroy() {
alcMakeContextCurrent(NULL);
alcDestroyContext(state.context);
alcCloseDevice(state.device);
for (int i = 0; i < state.sources.length; i++) {
for (size_t i = 0; i < state.sources.length; i++) {
lovrRelease(Source, state.sources.data[i]);
}
vec_deinit(&state.sources);
arr_free(&state.sources);
memset(&state, 0, sizeof(state));
}
void lovrAudioUpdate() {
int i; Source* source;
vec_foreach_rev(&state.sources, source, i) {
for (size_t i = state.sources.length; i-- > 0;) {
Source* source = state.sources.data[i];
if (lovrSourceGetType(source) == SOURCE_STATIC) {
continue;
}
@ -95,7 +96,7 @@ void lovrAudioUpdate() {
}
} else if (isStopped) {
lovrAudioStreamRewind(lovrSourceGetStream(source));
vec_splice(&state.sources, i, 1);
arr_splice(&state.sources, i, 1);
lovrRelease(Source, source);
}
}
@ -104,7 +105,7 @@ void lovrAudioUpdate() {
void lovrAudioAdd(Source* source) {
if (!lovrAudioHas(source)) {
lovrRetain(source);
vec_push(&state.sources, source);
arr_push(&state.sources, source);
}
}
@ -141,9 +142,13 @@ float lovrAudioGetVolume() {
}
bool lovrAudioHas(Source* source) {
int index;
vec_find(&state.sources, source, index);
return index >= 0;
for (size_t i = 0; i < state.sources.length; i++) {
if (state.sources.data[i] == source) {
return true;
}
}
return false;
}
bool lovrAudioIsSpatialized() {
@ -151,23 +156,20 @@ bool lovrAudioIsSpatialized() {
}
void lovrAudioPause() {
int i; Source* source;
vec_foreach(&state.sources, source, i) {
lovrSourcePause(source);
for (size_t i = 0; i < state.sources.length; i++) {
lovrSourcePause(state.sources.data[i]);
}
}
void lovrAudioResume() {
int i; Source* source;
vec_foreach(&state.sources, source, i) {
lovrSourceResume(source);
for (size_t i = 0; i < state.sources.length; i++) {
lovrSourceResume(state.sources.data[i]);
}
}
void lovrAudioRewind() {
int i; Source* source;
vec_foreach(&state.sources, source, i) {
lovrSourceRewind(source);
for (size_t i = 0; i < state.sources.length; i++) {
lovrSourceRewind(state.sources.data[i]);
}
}
@ -205,8 +207,7 @@ void lovrAudioSetVolume(float volume) {
}
void lovrAudioStop() {
int i; Source* source;
vec_foreach(&state.sources, source, i) {
lovrSourceStop(source);
for (size_t i = 0; i < state.sources.length; i++) {
lovrSourceStop(state.sources.data[i]);
}
}

View File

@ -2,27 +2,27 @@
#include "data/blob.h"
#include "data/textureData.h"
#include "filesystem/filesystem.h"
#include "core/arr.h"
#include "core/maf.h"
#include "core/ref.h"
#include "lib/map/map.h"
#include "lib/vec/vec.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef vec_t(ModelMaterial) vec_material_t;
typedef struct {
int material;
int start;
int count;
} objGroup;
typedef vec_t(objGroup) vec_group_t;
typedef arr_t(ModelMaterial, 1) arr_material_t;
typedef arr_t(TextureData*, 1) arr_texturedata_t;
typedef arr_t(objGroup, 1) arr_group_t;
#define STARTS_WITH(a, b) !strncmp(a, b, strlen(b))
static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials, map_int_t* names, char* base) {
static void parseMtl(char* path, arr_texturedata_t* textures, arr_material_t* materials, map_int_t* names, char* base) {
size_t length = 0;
char* data = lovrFilesystemRead(path, -1, &length);
lovrAssert(data && length > 0, "Unable to read mtl from '%s'", path);
@ -36,18 +36,18 @@ static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials
bool hasName = sscanf(s + 7, "%s\n%n", name, &lineLength);
lovrAssert(hasName, "Bad OBJ: Expected a material name");
map_set(names, name, materials->length);
vec_push(materials, ((ModelMaterial) {
arr_push(materials, ((ModelMaterial) {
.scalars[SCALAR_METALNESS] = 1.f,
.scalars[SCALAR_ROUGHNESS] = 1.f,
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
.colors[COLOR_EMISSIVE] = { 0.f, 0.f, 0.f, 0.f }
}));
memset(&vec_last(materials).textures, 0xff, MAX_MATERIAL_TEXTURES * sizeof(int));
memset(&materials->data[materials->length - 1].textures, 0xff, MAX_MATERIAL_TEXTURES * sizeof(int));
} else if (STARTS_WITH(s, "Kd")) {
float r, g, b;
int count = sscanf(s + 2, "%f %f %f\n%n", &r, &g, &b, &lineLength);
lovrAssert(count == 3, "Bad OBJ: Expected 3 components for diffuse color");
ModelMaterial* material = &vec_last(materials);
ModelMaterial* material = &materials->data[materials->length - 1];
material->colors[COLOR_DIFFUSE] = (Color) { r, g, b, 1.f };
} else if (STARTS_WITH(s, "map_Kd")) {
@ -56,7 +56,7 @@ static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials
bool hasFilename = sscanf(s + 7, "%s\n%n", filename, &lineLength);
lovrAssert(hasFilename, "Bad OBJ: Expected a texture filename");
char path[1024];
snprintf(path, 1023, "%s%s", base, filename);
snprintf(path, sizeof(path), "%s%s", base, filename);
size_t size = 0;
void* data = lovrFilesystemRead(path, -1, &size);
lovrAssert(data && size > 0, "Unable to read texture from %s", path);
@ -65,11 +65,11 @@ static void parseMtl(char* path, vec_void_t* textures, vec_material_t* materials
// Load texture, assign to material
TextureData* texture = lovrTextureDataCreateFromBlob(blob, true);
lovrAssert(materials->length > 0, "Tried to set a material property without declaring a material first");
ModelMaterial* material = &vec_last(materials);
ModelMaterial* material = &materials->data[materials->length - 1];
material->textures[TEXTURE_DIFFUSE] = textures->length;
material->filters[TEXTURE_DIFFUSE].mode = FILTER_TRILINEAR;
material->wraps[TEXTURE_DIFFUSE] = (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT };
vec_push(textures, texture);
arr_push(textures, texture);
lovrRelease(Blob, blob);
} else {
char* newline = memchr(s, '\n', length);
@ -92,29 +92,29 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
return NULL;
}
vec_group_t groups;
vec_void_t textures;
vec_material_t materials;
arr_group_t groups;
arr_texturedata_t textures;
arr_material_t materials;
map_int_t materialNames;
vec_float_t vertexBlob;
vec_int_t indexBlob;
arr_t(float, 1) vertexBlob;
arr_t(int, 1) indexBlob;
map_int_t vertexMap;
vec_float_t positions;
vec_float_t normals;
vec_float_t uvs;
arr_t(float, 1) positions;
arr_t(float, 1) normals;
arr_t(float, 1) uvs;
vec_init(&groups);
vec_init(&textures);
vec_init(&materials);
arr_init(&groups);
arr_init(&textures);
arr_init(&materials);
map_init(&materialNames);
vec_init(&vertexBlob);
vec_init(&indexBlob);
arr_init(&vertexBlob);
arr_init(&indexBlob);
map_init(&vertexMap);
vec_init(&positions);
vec_init(&normals);
vec_init(&uvs);
arr_init(&positions);
arr_init(&normals);
arr_init(&uvs);
vec_push(&groups, ((objGroup) { .material = -1 }));
arr_push(&groups, ((objGroup) { .material = -1 }));
char base[1024];
lovrAssert(strlen(source->name) < sizeof(base), "OBJ filename is too long");
@ -130,17 +130,17 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
float x, y, z;
int count = sscanf(data + 2, "%f %f %f\n%n", &x, &y, &z, &lineLength);
lovrAssert(count == 3, "Bad OBJ: Expected 3 coordinates for vertex position");
vec_pusharr(&positions, ((float[3]) { x, y, z }), 3);
arr_append(&positions, ((float[3]) { x, y, z }), 3);
} else if (STARTS_WITH(data, "vn ")) {
float x, y, z;
int count = sscanf(data + 3, "%f %f %f\n%n", &x, &y, &z, &lineLength);
lovrAssert(count == 3, "Bad OBJ: Expected 3 coordinates for vertex normal");
vec_pusharr(&normals, ((float[3]) { x, y, z }), 3);
arr_append(&normals, ((float[3]) { x, y, z }), 3);
} else if (STARTS_WITH(data, "vt ")) {
float u, v;
int count = sscanf(data + 3, "%f %f\n%n", &u, &v, &lineLength);
lovrAssert(count == 2, "Bad OBJ: Expected 2 coordinates for texture coordinate");
vec_pusharr(&uvs, ((float[2]) { u, v }), 2);
arr_append(&uvs, ((float[2]) { u, v }), 2);
} else if (STARTS_WITH(data, "f ")) {
char* s = data + 2;
for (int i = 0; i < 3; i++) {
@ -150,29 +150,29 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
*space = '\0'; // I'll be back
int* index = map_get(&vertexMap, s);
if (index) {
vec_push(&indexBlob, *index);
arr_push(&indexBlob, *index);
} else {
int v, vt, vn;
int newIndex = vertexBlob.length / 8;
vec_push(&indexBlob, newIndex);
arr_push(&indexBlob, newIndex);
map_set(&vertexMap, s, newIndex);
// Can be improved
if (sscanf(s, "%d/%d/%d", &v, &vt, &vn) == 3) {
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
arr_append(&vertexBlob, normals.data + 3 * (vn - 1), 3);
arr_append(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
} else if (sscanf(s, "%d//%d", &v, &vn) == 2) {
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
vec_pusharr(&vertexBlob, normals.data + 3 * (vn - 1), 3);
vec_pusharr(&vertexBlob, ((float[2]) { 0 }), 2);
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
arr_append(&vertexBlob, normals.data + 3 * (vn - 1), 3);
arr_append(&vertexBlob, ((float[2]) { 0 }), 2);
} else if (sscanf(s, "%d/%d", &v, &vt) == 2) {
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
vec_pusharr(&vertexBlob, ((float[3]) { 0 }), 3);
vec_pusharr(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
arr_append(&vertexBlob, ((float[3]) { 0 }), 3);
arr_append(&vertexBlob, uvs.data + 2 * (vt - 1), 2);
} else if (sscanf(s, "%d", &v) == 1) {
vec_pusharr(&vertexBlob, positions.data + 3 * (v - 1), 3);
vec_pusharr(&vertexBlob, ((float[5]) { 0 }), 5);
arr_append(&vertexBlob, positions.data + 3 * (v - 1), 3);
arr_append(&vertexBlob, ((float[5]) { 0 }), 5);
} else {
lovrThrow("Bad OBJ: Unknown face format");
}
@ -181,14 +181,14 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
s = space + 1;
}
}
vec_last(&groups).count += 3;
groups.data[groups.length - 1].count += 3;
lineLength = s - data;
} else if (STARTS_WITH(data, "mtllib ")) {
char filename[1024];
bool hasName = sscanf(data + 7, "%1024s\n%n", filename, &lineLength);
lovrAssert(hasName, "Bad OBJ: Expected filename after mtllib");
char path[1024];
snprintf(path, 1023, "%s%s", base, filename);
snprintf(path, sizeof(path), "%s%s", base, filename);
parseMtl(path, &textures, &materials, &materialNames, base);
} else if (STARTS_WITH(data, "usemtl ")) {
char name[128];
@ -197,10 +197,10 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
lovrAssert(hasName, "Bad OBJ: Expected a material name");
// If the last group didn't have any faces, just reuse it, otherwise make a new group
objGroup* group = &vec_last(&groups);
objGroup* group = &groups.data[groups.length - 1];
if (group->count > 0) {
int start = group->start + group->count; // Don't put this in the compound literal (realloc)
vec_push(&groups, ((objGroup) {
arr_push(&groups, ((objGroup) {
.material = material ? *material : -1,
.start = start,
.count = 0
@ -276,7 +276,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
.components = 2
};
for (int i = 0; i < groups.length; i++) {
for (size_t i = 0; i < groups.length; i++) {
objGroup* group = &groups.data[i];
model->attributes[3 + i] = (ModelAttribute) {
.buffer = 1,
@ -287,7 +287,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
};
}
for (int i = 0; i < groups.length; i++) {
for (size_t i = 0; i < groups.length; i++) {
objGroup* group = &groups.data[i];
model->primitives[i] = (ModelPrimitive) {
.mode = DRAW_TRIANGLES,
@ -307,13 +307,13 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
.primitiveCount = groups.length
};
vec_deinit(&groups);
vec_deinit(&textures);
vec_deinit(&materials);
arr_free(&groups);
arr_free(&textures);
arr_free(&materials);
map_deinit(&materialNames);
map_deinit(&vertexMap);
vec_deinit(&positions);
vec_deinit(&normals);
vec_deinit(&uvs);
arr_free(&positions);
arr_free(&normals);
arr_free(&uvs);
return model;
}

View File

@ -7,6 +7,7 @@
#include "lib/stb/stb_truetype.h"
#include <msdfgen-c.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
Rasterizer* lovrRasterizerInit(Rasterizer* rasterizer, Blob* blob, float size) {

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 height = textureData->height = header->height;
uint32_t mipmapCount = MAX(header->mipMapCount, 1);
uint32_t mipmapCount = textureData->mipmapCount = MAX(header->mipMapCount, 1);
textureData->mipmaps = malloc(mipmapCount * sizeof(Mipmap));
size_t blockBytes = 0;
switch (textureData->format) {
@ -303,12 +304,11 @@ static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) {
// Overflow check
if (mipmapSize == 0 || (offset + mipmapSize) > size) {
vec_deinit(&textureData->mipmaps);
free(textureData->mipmaps);
return false;
}
Mipmap mipmap = { .width = width, .height = height, .data = &data[offset], .size = mipmapSize };
vec_push(&textureData->mipmaps, mipmap);
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = &data[offset], .size = mipmapSize };
offset += mipmapSize;
width = MAX(width >> 1, 1);
height = MAX(height >> 1, 1);
@ -363,18 +363,12 @@ static bool parseKTX(uint8_t* bytes, size_t size, TextureData* textureData) {
uint32_t width = textureData->width = data.ktx->pixelWidth;
uint32_t height = textureData->height = data.ktx->pixelHeight;
uint32_t mipmapCount = data.ktx->numberOfMipmapLevels;
vec_reserve(&textureData->mipmaps, mipmapCount);
uint32_t mipmapCount = textureData->mipmapCount = data.ktx->numberOfMipmapLevels;
textureData->mipmaps = malloc(mipmapCount * sizeof(Mipmap));
data.u8 += sizeof(KTXHeader) + data.ktx->bytesOfKeyValueData;
for (uint32_t i = 0; i < mipmapCount; i++) {
vec_push(&textureData->mipmaps, ((Mipmap) {
.width = width,
.height = height,
.data = data.u8 + sizeof(uint32_t),
.size = *data.u32
}));
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = data.u8 + sizeof(uint32_t), .size = *data.u32 };
width = MAX(width >> 1, 1u);
height = MAX(height >> 1, 1u);
data.u8 = (uint8_t*) ALIGN(data.u8 + sizeof(uint32_t) + *data.u32 + 3, 4);
@ -425,13 +419,13 @@ static bool parseASTC(uint8_t* bytes, size_t size, TextureData* textureData) {
textureData->width = data.astc->width[0] + (data.astc->width[1] << 8) + (data.astc->width[2] << 16);
textureData->height = data.astc->height[0] + (data.astc->height[1] << 8) + (data.astc->height[2] << 16);
vec_push(&textureData->mipmaps, ((Mipmap) {
textureData->mipmaps = malloc(sizeof(Mipmap));
textureData->mipmaps[0] = (Mipmap) {
.width = textureData->width,
.height = textureData->height,
.data = data.astc + 1,
.size = size - sizeof(*data.astc)
}));
};
return true;
}
@ -448,13 +442,10 @@ TextureData* lovrTextureDataInit(TextureData* textureData, uint32_t width, uint3
textureData->blob.data = malloc(size);
lovrAssert(textureData->blob.data, "Out of memory");
memset(textureData->blob.data, value, size);
vec_init(&textureData->mipmaps);
return textureData;
}
TextureData* lovrTextureDataInitFromBlob(TextureData* textureData, Blob* blob, bool flip) {
vec_init(&textureData->mipmaps);
if (parseDDS(blob->data, blob->size, textureData)) {
textureData->source = blob;
lovrRetain(blob);
@ -488,6 +479,7 @@ TextureData* lovrTextureDataInitFromBlob(TextureData* textureData, Blob* blob, b
textureData->width = width;
textureData->height = height;
textureData->mipmapCount = 0;
return textureData;
}
@ -574,6 +566,6 @@ bool lovrTextureDataEncode(TextureData* textureData, const char* filename) {
void lovrTextureDataDestroy(void* ref) {
TextureData* textureData = ref;
lovrRelease(Blob, textureData->source);
vec_deinit(&textureData->mipmaps);
free(textureData->mipmaps);
lovrBlobDestroy(ref);
}

View File

@ -1,6 +1,5 @@
#include "data/blob.h"
#include "util.h"
#include "lib/vec/vec.h"
#include <stdint.h>
#include <stdbool.h>
@ -48,15 +47,14 @@ typedef struct {
void* data;
} Mipmap;
typedef vec_t(Mipmap) vec_mipmap_t;
typedef struct TextureData {
Blob blob;
uint32_t width;
uint32_t height;
Blob* source;
TextureFormat format;
vec_mipmap_t mipmaps;
Mipmap* mipmaps;
uint32_t mipmapCount;
} TextureData;
TextureData* lovrTextureDataInit(TextureData* textureData, uint32_t width, uint32_t height, uint8_t value, TextureFormat format);

View File

@ -1,14 +1,14 @@
#include "event/event.h"
#include "platform.h"
#include "core/arr.h"
#include "core/ref.h"
#include "lib/vec/vec.h"
#include <stdlib.h>
#include <string.h>
static struct {
bool initialized;
vec_t(EventPump) pumps;
vec_t(Event) events;
arr_t(Event, 8) events;
size_t head;
} state;
void lovrVariantDestroy(Variant* variant) {
@ -21,47 +21,35 @@ void lovrVariantDestroy(Variant* variant) {
bool lovrEventInit() {
if (state.initialized) return false;
vec_init(&state.pumps);
vec_init(&state.events);
lovrEventAddPump(lovrPlatformPollEvents);
arr_init(&state.events);
return state.initialized = true;
}
void lovrEventDestroy() {
if (!state.initialized) return;
vec_deinit(&state.pumps);
vec_deinit(&state.events);
arr_free(&state.events);
memset(&state, 0, sizeof(state));
}
void lovrEventAddPump(EventPump pump) {
vec_push(&state.pumps, pump);
}
void lovrEventRemovePump(EventPump pump) {
vec_remove(&state.pumps, pump);
}
void lovrEventPump() {
int i; EventPump pump;
vec_foreach(&state.pumps, pump, i) {
pump();
}
lovrPlatformPollEvents();
}
void lovrEventPush(Event event) {
vec_insert(&state.events, 0, event);
arr_push(&state.events, event);
}
bool lovrEventPoll(Event* event) {
if (state.events.length == 0) {
if (state.head == state.events.length) {
state.head = state.events.length = 0;
return false;
}
*event = vec_pop(&state.events);
*event = state.events.data[state.head++];
return true;
}
void lovrEventClear() {
vec_clear(&state.events);
arr_clear(&state.events);
state.head = 0;
}

View File

@ -70,14 +70,10 @@ typedef struct {
EventData data;
} Event;
typedef void (*EventPump)(void);
void lovrVariantDestroy(Variant* variant);
bool lovrEventInit(void);
void lovrEventDestroy(void);
void lovrEventAddPump(EventPump pump);
void lovrEventRemovePump(EventPump pump);
void lovrEventPump(void);
void lovrEventPush(Event event);
bool lovrEventPoll(Event* event);

View File

@ -4,6 +4,8 @@
File* lovrFileInit(File* file ,const char* path) {
file->path = path;
file->handle = NULL;
file->mode = 0;
return file;
}

View File

@ -31,13 +31,12 @@ const char lovrDirSep = '/';
static struct {
bool initialized;
bool fused;
char* source;
const char* identity;
char* savePathRelative;
char* savePathFull;
bool isFused;
char* requirePath[2];
vec_str_t requirePattern[2];
char requirePath[2][1024];
} state;
bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* argRoot) {
@ -52,16 +51,14 @@ bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* arg
state.source = malloc(LOVR_PATH_MAX * sizeof(char));
lovrAssert(state.source, "Out of memory");
state.identity = NULL;
state.isFused = true;
vec_init(&state.requirePattern[0]);
vec_init(&state.requirePattern[1]);
state.fused = true;
lovrFilesystemSetRequirePath("?.lua;?/init.lua;lua_modules/?.lua;lua_modules/?/init.lua;deps/?.lua;deps/?/init.lua");
lovrFilesystemSetCRequirePath("??;lua_modules/??;deps/??");
// Try to mount either an archive fused to the executable or an archive from the command line
lovrFilesystemGetExecutablePath(state.source, LOVR_PATH_MAX);
if (!lovrFilesystemMount(state.source, NULL, 1, argRoot)) { // Attempt to load fused. If that fails...
state.isFused = false;
state.fused = false;
if (argGame) {
strncpy(state.source, argGame, LOVR_PATH_MAX);
@ -82,10 +79,6 @@ void lovrFilesystemDestroy() {
free(state.source);
free(state.savePathFull);
free(state.savePathRelative);
for (int i = 0; i < 2; i++) {
free(state.requirePath[i]);
vec_deinit(&state.requirePattern[i]);
}
PHYSFS_deinit();
memset(&state, 0, sizeof(state));
}
@ -151,12 +144,12 @@ const char* lovrFilesystemGetRealDirectory(const char* path) {
return PHYSFS_getRealDir(path);
}
vec_str_t* lovrFilesystemGetRequirePath() {
return &state.requirePattern[0];
const char* lovrFilesystemGetRequirePath() {
return state.requirePath[0];
}
vec_str_t* lovrFilesystemGetCRequirePath() {
return &state.requirePattern[1];
const char* lovrFilesystemGetCRequirePath() {
return state.requirePath[1];
}
const char* lovrFilesystemGetSaveDirectory() {
@ -213,7 +206,7 @@ bool lovrFilesystemIsFile(const char* path) {
}
bool lovrFilesystemIsFused() {
return state.isFused;
return state.fused;
}
// Returns zero on success, nonzero on failure
@ -227,7 +220,7 @@ bool lovrFilesystemMount(const char* path, const char* mountpoint, bool append,
void* lovrFilesystemRead(const char* path, size_t bytes, size_t* bytesRead) {
File file;
lovrFileInit(memset(&file, 0, sizeof(File)), path);
lovrFileInit(&file, path);
if (!lovrFileOpen(&file, OPEN_READ)) {
return NULL;
@ -293,30 +286,12 @@ bool lovrFilesystemSetIdentity(const char* identity) {
return PHYSFS_mount(state.savePathFull, NULL, 0);
}
static void setRequirePath(int i, const char* requirePath) {
if (state.requirePath[i]) {
free(state.requirePath[i]);
vec_clear(&state.requirePattern[i]);
}
char* p = state.requirePath[i] = strdup(requirePath);
while (1) {
vec_push(&state.requirePattern[i], p);
if ((p = strchr(p, ';')) != NULL) {
*p++ = '\0';
} else {
break;
}
}
}
void lovrFilesystemSetRequirePath(const char* requirePath) {
setRequirePath(0, requirePath);
strncpy(state.requirePath[0], requirePath, sizeof(state.requirePath[0]) - 1);
}
void lovrFilesystemSetCRequirePath(const char* requirePath) {
setRequirePath(1, requirePath);
strncpy(state.requirePath[1], requirePath, sizeof(state.requirePath[1]) - 1);
}
bool lovrFilesystemUnmount(const char* path) {

View File

@ -1,6 +1,6 @@
#include "lib/vec/vec.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#pragma once
@ -19,8 +19,8 @@ int lovrFilesystemGetExecutablePath(char* path, uint32_t size);
const char* lovrFilesystemGetIdentity(void);
long lovrFilesystemGetLastModified(const char* path);
const char* lovrFilesystemGetRealDirectory(const char* path);
vec_str_t* lovrFilesystemGetRequirePath(void);
vec_str_t* lovrFilesystemGetCRequirePath(void);
const char* lovrFilesystemGetRequirePath();
const char* lovrFilesystemGetCRequirePath();
const char* lovrFilesystemGetSaveDirectory(void);
size_t lovrFilesystemGetSize(const char* path);
const char* lovrFilesystemGetSource(void);

View File

@ -13,12 +13,12 @@ Animator* lovrAnimatorInit(Animator* animator, ModelData* data) {
lovrRetain(data);
animator->data = data;
map_init(&animator->animations);
vec_init(&animator->tracks);
vec_reserve(&animator->tracks, data->animationCount);
arr_init(&animator->tracks);
arr_reserve(&animator->tracks, data->animationCount);
animator->speed = 1.f;
for (uint32_t i = 0; i < data->animationCount; i++) {
vec_push(&animator->tracks, ((Track) {
arr_push(&animator->tracks, ((Track) {
.time = 0.f,
.speed = 1.f,
.alpha = 1.f,
@ -38,12 +38,12 @@ Animator* lovrAnimatorInit(Animator* animator, ModelData* data) {
void lovrAnimatorDestroy(void* ref) {
Animator* animator = ref;
lovrRelease(ModelData, animator->data);
vec_deinit(&animator->tracks);
arr_free(&animator->tracks);
}
void lovrAnimatorReset(Animator* animator) {
Track* track; int i;
vec_foreach_ptr(&animator->tracks, track, i) {
for (size_t i = 0; i < animator->tracks.length; i++) {
Track* track = &animator->tracks.data[i];
track->time = 0.f;
track->speed = 1.f;
track->playing = false;
@ -53,8 +53,8 @@ void lovrAnimatorReset(Animator* animator) {
}
void lovrAnimatorUpdate(Animator* animator, float dt) {
Track* track; int i;
vec_foreach_ptr(&animator->tracks, track, i) {
for (size_t i = 0; i < animator->tracks.length; i++) {
Track* track = &animator->tracks.data[i];
if (track->playing) {
track->time += dt * track->speed * animator->speed;
float duration = animator->data->animations[i].duration;
@ -247,7 +247,7 @@ int32_t lovrAnimatorGetPriority(Animator* animator, uint32_t animation) {
void lovrAnimatorSetPriority(Animator* animator, uint32_t animation, int32_t priority) {
Track* track = &animator->tracks.data[animation];
track->priority = priority;
vec_sort(&animator->tracks, trackSortCallback);
qsort(animator->tracks.data, animator->tracks.length, sizeof(Track), trackSortCallback);
}
float lovrAnimatorGetSpeed(Animator* animator, uint32_t animation) {

View File

@ -1,5 +1,5 @@
#include "core/arr.h"
#include "lib/map/map.h"
#include "lib/vec/vec.h"
#include <stdbool.h>
#include <stdint.h>
@ -16,12 +16,10 @@ typedef struct {
bool looping;
} Track;
typedef vec_t(Track) vec_track_t;
typedef struct Animator {
struct ModelData* data;
map_t(uint32_t) animations;
vec_track_t tracks;
arr_t(Track, 1) tracks;
float speed;
} Animator;

View File

@ -1,5 +1,6 @@
#include "graphics/font.h"
#include "graphics/shader.h"
#include "core/arr.h"
#include "core/maf.h"
#include "util.h"
#include "platform.h"
@ -307,7 +308,7 @@ typedef struct {
typedef struct {
int shaderSwitches;
int drawCalls;
vec_t(GpuTimer) timers;
arr_t(GpuTimer, 4) timers;
} GpuStats;
typedef struct {

View File

@ -10,7 +10,6 @@
#include "data/modelData.h"
#include "core/ref.h"
#include "lib/map/map.h"
#include "lib/vec/vec.h"
#include <math.h>
#include <limits.h>
#include <string.h>
@ -82,7 +81,7 @@ static struct {
Image images[MAX_IMAGES];
float viewports[2][4];
uint32_t viewportCount;
vec_void_t incoherents[MAX_BARRIERS];
arr_t(void*, 2) incoherents[MAX_BARRIERS];
map_t(TimerList) timers;
GpuFeatures features;
GpuLimits limits;
@ -420,18 +419,18 @@ static void lovrGpuSync(uint8_t flags) {
}
if (i == BARRIER_BLOCK) {
for (int j = 0; j < state.incoherents[i].length; j++) {
for (size_t j = 0; j < state.incoherents[i].length; j++) {
Buffer* buffer = state.incoherents[i].data[j];
buffer->incoherent &= ~(1 << i);
}
} else {
for (int j = 0; j < state.incoherents[i].length; j++) {
for (size_t j = 0; j < state.incoherents[i].length; j++) {
Texture* texture = state.incoherents[i].data[j];
texture->incoherent &= ~(1 << i);
}
}
vec_clear(&state.incoherents[i]);
arr_clear(&state.incoherents[i]);
switch (i) {
case BARRIER_BLOCK: bits |= GL_SHADER_STORAGE_BARRIER_BIT; break;
@ -453,11 +452,11 @@ static void lovrGpuDestroySyncResource(void* resource, uint8_t incoherent) {
return;
}
for (int i = 0; i < MAX_BARRIERS; i++) {
for (uint32_t i = 0; i < MAX_BARRIERS; i++) {
if (incoherent & (1 << i)) {
for (int j = 0; j < state.incoherents[i].length; j++) {
for (size_t j = 0; j < state.incoherents[i].length; j++) {
if (state.incoherents[i].data[j] == resource) {
vec_swapsplice(&state.incoherents[i], j, 1);
arr_splice(&state.incoherents[i], j, 1);
break;
}
}
@ -839,23 +838,21 @@ static void lovrGpuBindPipeline(Pipeline* pipeline) {
}
static void lovrGpuBindShader(Shader* shader) {
UniformBlock* block;
Uniform* uniform;
int i;
lovrGpuUseProgram(shader->program);
// Figure out if we need to wait for pending writes on resources to complete
#ifndef LOVR_WEBGL
uint8_t flags = 0;
vec_foreach_ptr(&shader->blocks[BLOCK_COMPUTE], block, i) {
for (size_t i = 0; i < shader->blocks[BLOCK_COMPUTE].length; i++) {
UniformBlock* block = &shader->blocks[BLOCK_COMPUTE].data[i];
if (block->source && (block->source->incoherent >> BARRIER_BLOCK) & 1) {
flags |= 1 << BARRIER_BLOCK;
break;
}
}
vec_foreach_ptr(&shader->uniforms, uniform, i) {
for (size_t i = 0; i < shader->uniforms.length; i++) {
Uniform* uniform = &shader->uniforms.data[i];
if (uniform->type == UNIFORM_SAMPLER) {
for (int i = 0; i < uniform->count; i++) {
Texture* texture = uniform->value.textures[i];
@ -883,7 +880,9 @@ static void lovrGpuBindShader(Shader* shader) {
#endif
// Bind uniforms
vec_foreach_ptr(&shader->uniforms, uniform, i) {
for (size_t i = 0; i < shader->uniforms.length; i++) {
Uniform* uniform = &shader->uniforms.data[i];
if (uniform->type != UNIFORM_SAMPLER && uniform->type != UNIFORM_IMAGE && !uniform->dirty) {
continue;
}
@ -930,7 +929,7 @@ static void lovrGpuBindShader(Shader* shader) {
if (texture && image->access != ACCESS_READ) {
for (Barrier barrier = BARRIER_BLOCK + 1; barrier < MAX_BARRIERS; barrier++) {
texture->incoherent |= 1 << barrier;
vec_push(&state.incoherents[barrier], texture);
arr_push(&state.incoherents[barrier], texture);
}
}
@ -951,11 +950,12 @@ static void lovrGpuBindShader(Shader* shader) {
// Bind uniform blocks
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_COMPUTE; type++) {
vec_foreach_ptr(&shader->blocks[type], block, i) {
for (size_t i = 0; i < shader->blocks[type].length; i++) {
UniformBlock* block = &shader->blocks[type].data[i];
if (block->source) {
if (type == BLOCK_COMPUTE && block->access != ACCESS_READ) {
block->source->incoherent |= (1 << BARRIER_BLOCK);
vec_push(&state.incoherents[BARRIER_BLOCK], block->source);
arr_push(&state.incoherents[BARRIER_BLOCK], block->source);
}
lovrBufferUnmap(block->source);
@ -1059,7 +1059,7 @@ void lovrGpuInit(getProcAddressProc getProcAddress) {
#endif
for (int i = 0; i < MAX_BARRIERS; i++) {
vec_init(&state.incoherents[i]);
arr_init(&state.incoherents[i]);
}
}
@ -1072,7 +1072,7 @@ void lovrGpuDestroy() {
lovrRelease(Texture, state.images[i].texture);
}
for (int i = 0; i < MAX_BARRIERS; i++) {
vec_deinit(&state.incoherents[i]);
arr_free(&state.incoherents[i]);
}
memset(&state, 0, sizeof(state));
}
@ -1183,7 +1183,7 @@ void lovrGpuDraw(DrawCommand* draw) {
void lovrGpuPresent() {
state.stats.drawCalls = state.stats.shaderSwitches = 0;
vec_clear(&state.stats.timers);
arr_clear(&state.stats.timers);
#ifdef __APPLE__
// For some reason instancing doesn't work on macOS unless you reset the shader every frame
lovrGpuUseProgram(0);
@ -1284,7 +1284,7 @@ void lovrGpuTock(const char* label) {
}
glGetQueryObjectui64v(timer->timers[timer->oldest], GL_QUERY_RESULT, &timer->ns);
vec_push(&state.stats.timers, ((GpuTimer) { .label = label, .time = timer->ns / 1e9 }));
arr_push(&state.stats.timers, ((GpuTimer) { .label = label, .time = timer->ns / 1e9 }));
timer->oldest = (timer->oldest + 1) % 4;
}
}
@ -1445,16 +1445,16 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, uint32
if (isTextureFormatCompressed(textureData->format)) {
lovrAssert(width == maxWidth && height == maxHeight, "Compressed texture pixels must be fully replaced");
lovrAssert(mipmap == 0, "Unable to replace a specific mipmap of a compressed texture");
Mipmap m; int i;
vec_foreach(&textureData->mipmaps, m, i) {
for (uint32_t i = 0; i < textureData->mipmapCount; i++) {
Mipmap* m = textureData->mipmaps + i;
switch (texture->type) {
case TEXTURE_2D:
case TEXTURE_CUBE:
glCompressedTexImage2D(binding, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
glCompressedTexImage2D(binding, i, glInternalFormat, m->width, m->height, 0, m->size, m->data);
break;
case TEXTURE_ARRAY:
case TEXTURE_VOLUME:
glCompressedTexSubImage3D(binding, i, x, y, slice, m.width, m.height, 1, glInternalFormat, m.size, m.data);
glCompressedTexSubImage3D(binding, i, x, y, slice, m->width, m->height, 1, glInternalFormat, m->size, m->data);
break;
}
}
@ -1795,42 +1795,42 @@ static void lovrShaderSetupUniforms(Shader* shader) {
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount);
lovrAssert(blockCount <= MAX_BLOCK_BUFFERS, "Shader has too many uniform blocks (%d) the max is %d", blockCount, MAX_BLOCK_BUFFERS);
map_init(&shader->blockMap);
vec_block_t* uniformBlocks = &shader->blocks[BLOCK_UNIFORM];
vec_init(uniformBlocks);
vec_reserve(uniformBlocks, blockCount);
arr_block_t* uniformBlocks = &shader->blocks[BLOCK_UNIFORM];
arr_init(uniformBlocks);
arr_reserve(uniformBlocks, (size_t) blockCount);
for (int i = 0; i < blockCount; i++) {
UniformBlock block = { .slot = i, .source = NULL };
glUniformBlockBinding(program, i, block.slot);
vec_init(&block.uniforms);
arr_init(&block.uniforms);
char name[LOVR_MAX_UNIFORM_LENGTH];
glGetActiveUniformBlockName(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
int blockId = (i << 1) + BLOCK_UNIFORM;
map_set(&shader->blockMap, name, blockId);
vec_push(uniformBlocks, block);
arr_push(uniformBlocks, block);
}
// Shader storage buffers and their buffer variables
vec_block_t* computeBlocks = &shader->blocks[BLOCK_COMPUTE];
vec_init(computeBlocks);
arr_block_t* computeBlocks = &shader->blocks[BLOCK_COMPUTE];
arr_init(computeBlocks);
#ifndef LOVR_WEBGL
if (GLAD_GL_ARB_shader_storage_buffer_object && GLAD_GL_ARB_program_interface_query) {
// Iterate over compute blocks, setting their binding and pushing them onto the block vector
int computeBlockCount;
int32_t computeBlockCount;
glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &computeBlockCount);
lovrAssert(computeBlockCount <= MAX_BLOCK_BUFFERS, "Shader has too many compute blocks (%d) the max is %d", computeBlockCount, MAX_BLOCK_BUFFERS);
vec_reserve(computeBlocks, computeBlockCount);
arr_reserve(computeBlocks, (size_t) computeBlockCount);
for (int i = 0; i < computeBlockCount; i++) {
UniformBlock block = { .slot = i, .source = NULL };
glShaderStorageBlockBinding(program, i, block.slot);
vec_init(&block.uniforms);
arr_init(&block.uniforms);
char name[LOVR_MAX_UNIFORM_LENGTH];
glGetProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name);
int blockId = (i << 1) + BLOCK_COMPUTE;
map_set(&shader->blockMap, name, blockId);
vec_push(computeBlocks, block);
arr_push(computeBlocks, block);
}
// Iterate over buffer variables, pushing them onto the uniform list of the correct block
@ -1854,7 +1854,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
} else {
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
}
vec_push(&computeBlocks->data[values[blockIndex]].uniforms, uniform);
arr_push(&computeBlocks->data[values[blockIndex]].uniforms, uniform);
}
}
#endif
@ -1864,7 +1864,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
int textureSlot = 0;
int imageSlot = 0;
map_init(&shader->uniformMap);
vec_init(&shader->uniforms);
arr_init(&shader->uniforms);
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount);
for (uint32_t i = 0; i < (uint32_t) uniformCount; i++) {
Uniform uniform;
@ -1910,7 +1910,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
}
vec_push(&block->uniforms, uniform);
arr_push(&block->uniforms, uniform);
continue;
} else if (uniform.location == -1) {
continue;
@ -1971,7 +1971,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
}
map_set(&shader->uniformMap, uniform.name, shader->uniforms.length);
vec_push(&shader->uniforms, uniform);
arr_push(&shader->uniforms, uniform);
textureSlot += uniform.type == UNIFORM_SAMPLER ? uniform.count : 0;
imageSlot += uniform.type == UNIFORM_IMAGE ? uniform.count : 0;
}
@ -2115,18 +2115,17 @@ void lovrShaderDestroy(void* ref) {
Shader* shader = ref;
lovrGraphicsFlushShader(shader);
glDeleteProgram(shader->program);
for (int i = 0; i < shader->uniforms.length; i++) {
for (size_t i = 0; i < shader->uniforms.length; i++) {
free(shader->uniforms.data[i].value.data);
}
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_COMPUTE; type++) {
UniformBlock* block; int i;
vec_foreach_ptr(&shader->blocks[type], block, i) {
lovrRelease(Buffer, block->source);
for (size_t i = 0; i < shader->blocks[type].length; i++) {
lovrRelease(Buffer, shader->blocks[type].data[i].source);
}
}
vec_deinit(&shader->uniforms);
vec_deinit(&shader->blocks[BLOCK_UNIFORM]);
vec_deinit(&shader->blocks[BLOCK_COMPUTE]);
arr_free(&shader->uniforms);
arr_free(&shader->blocks[BLOCK_UNIFORM]);
arr_free(&shader->blocks[BLOCK_COMPUTE]);
map_deinit(&shader->attributes);
map_deinit(&shader->uniformMap);
map_deinit(&shader->blockMap);

View File

@ -159,11 +159,11 @@ void lovrShaderSetBlock(Shader* shader, const char* name, Buffer* buffer, size_t
// ShaderBlock
// Calculates uniform size and byte offsets using std140 rules, returning the total buffer size
size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms) {
size_t lovrShaderComputeUniformLayout(arr_uniform_t* uniforms) {
size_t size = 0;
Uniform* uniform; int i;
vec_foreach_ptr(uniforms, uniform, i) {
for (size_t i = 0; i < uniforms->length; i++) {
int align;
Uniform* uniform = &uniforms->data[i];
if (uniform->count > 1 || uniform->type == UNIFORM_MATRIX) {
align = 16 * (uniform->type == UNIFORM_MATRIX ? uniform->components : 1);
uniform->size = align * uniform->count;
@ -177,14 +177,14 @@ size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms) {
return size;
}
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, vec_uniform_t* uniforms) {
vec_init(&block->uniforms);
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, arr_uniform_t* uniforms) {
arr_init(&block->uniforms);
map_init(&block->uniformMap);
Uniform* uniform; int i;
vec_extend(&block->uniforms, uniforms);
vec_foreach_ptr(&block->uniforms, uniform, i) {
map_set(&block->uniformMap, uniform->name, i);
arr_append(&block->uniforms, uniforms->data, uniforms->length);
for (size_t i = 0; i < block->uniforms.length; i++) {
map_set(&block->uniformMap, block->uniforms.data[i].name, i);
}
block->type = type;
@ -196,7 +196,7 @@ ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buf
void lovrShaderBlockDestroy(void* ref) {
ShaderBlock* block = ref;
lovrRelease(Buffer, block->buffer);
vec_deinit(&block->uniforms);
arr_free(&block->uniforms);
map_deinit(&block->uniformMap);
}
@ -215,7 +215,7 @@ char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, si
size += 1; // " "
size += strlen(blockName);
size += 3; // " {\n"
for (int i = 0; i < block->uniforms.length; i++) {
for (size_t i = 0; i < block->uniforms.length; i++) {
size += tab;
size += getUniformTypeLength(&block->uniforms.data[i]);
size += 1; // " "
@ -231,7 +231,7 @@ char* lovrShaderBlockGetShaderCode(ShaderBlock* block, const char* blockName, si
// Concatenate
char* s = code;
s += sprintf(s, "layout(std140) %s %s {\n", block->type == BLOCK_UNIFORM ? "uniform" : "buffer", blockName);
for (int i = 0; i < block->uniforms.length; i++) {
for (size_t i = 0; i < block->uniforms.length; i++) {
const Uniform* uniform = &block->uniforms.data[i];
if (uniform->count > 1) {
s += sprintf(s, " %s %s[%d];\n", getUniformTypeName(uniform), uniform->name, uniform->count);

View File

@ -1,7 +1,7 @@
#include "graphics/texture.h"
#include "graphics/opengl.h"
#include "core/arr.h"
#include "lib/map/map.h"
#include "lib/vec/vec.h"
#include <stdbool.h>
#pragma once
@ -89,17 +89,17 @@ typedef struct Uniform {
bool dirty;
} Uniform;
typedef vec_t(Uniform) vec_uniform_t;
typedef arr_t(Uniform, 8) arr_uniform_t;
typedef struct {
BlockType type;
vec_uniform_t uniforms;
arr_uniform_t uniforms;
map_int_t uniformMap;
struct Buffer* buffer;
} ShaderBlock;
typedef struct {
vec_uniform_t uniforms;
arr_uniform_t uniforms;
UniformAccess access;
struct Buffer* source;
size_t offset;
@ -107,12 +107,12 @@ typedef struct {
int slot;
} UniformBlock;
typedef vec_t(UniformBlock) vec_block_t;
typedef arr_t(UniformBlock, 1) arr_block_t;
typedef struct Shader {
ShaderType type;
vec_uniform_t uniforms;
vec_block_t blocks[2];
arr_uniform_t uniforms;
arr_block_t blocks[2];
map_int_t attributes;
map_int_t uniformMap;
map_int_t blockMap;
@ -142,9 +142,9 @@ void lovrShaderSetBlock(Shader* shader, const char* name, struct Buffer* buffer,
// ShaderBlock
size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms);
size_t lovrShaderComputeUniformLayout(arr_uniform_t* uniforms);
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, struct Buffer* buffer, vec_uniform_t* uniforms);
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, struct Buffer* buffer, arr_uniform_t* uniforms);
#define lovrShaderBlockCreate(...) lovrShaderBlockInit(lovrAlloc(ShaderBlock), __VA_ARGS__)
void lovrShaderBlockDestroy(void* ref);
BlockType lovrShaderBlockGetType(ShaderBlock* block);

View File

@ -86,7 +86,7 @@ static struct {
RenderModel_t* deviceModels[16];
RenderModel_TextureMap_t* deviceTextures[16];
Canvas* canvas;
vec_float_t boundsGeometry;
float boundsGeometry[16];
float clipNear;
float clipFar;
float offset;
@ -205,7 +205,6 @@ static bool openvr_init(float offset, uint32_t msaa) {
state.offset = state.compositor->GetTrackingSpace() == ETrackingUniverseOrigin_TrackingUniverseStanding ? 0. : offset;
state.msaa = msaa;
vec_init(&state.boundsGeometry);
return true;
}
@ -221,7 +220,6 @@ static void openvr_destroy(void) {
state.deviceModels[i] = NULL;
state.deviceTextures[i] = NULL;
}
vec_deinit(&state.boundsGeometry);
VR_ShutdownInternal();
memset(&state, 0, sizeof(state));
}
@ -272,16 +270,13 @@ static void openvr_getBoundsDimensions(float* width, float* depth) {
static const float* openvr_getBoundsGeometry(uint32_t* count) {
struct HmdQuad_t quad;
if (state.chaperone->GetPlayAreaRect(&quad)) {
vec_clear(&state.boundsGeometry);
for (int i = 0; i < 4; i++) {
vec_push(&state.boundsGeometry, quad.vCorners[i].v[0]);
vec_push(&state.boundsGeometry, quad.vCorners[i].v[1]);
vec_push(&state.boundsGeometry, quad.vCorners[i].v[2]);
state.boundsGeometry[4 * i + 0] = quad.vCorners[i].v[0];
state.boundsGeometry[4 * i + 1] = quad.vCorners[i].v[1];
state.boundsGeometry[4 * i + 2] = quad.vCorners[i].v[2];
}
*count = state.boundsGeometry.length;
return state.boundsGeometry.data;
return *count = 16, state.boundsGeometry;
}
return NULL;

View File

@ -4,7 +4,7 @@
#include <math.h>
// Explicit curve evaluation, unroll simple cases to avoid pow overhead
static void evaluate(float* P, int n, float t, vec3 p) {
static void evaluate(float* P, size_t n, float t, vec3 p) {
if (n == 2) {
p[0] = P[0] + (P[4] - P[0]) * t;
p[1] = P[1] + (P[5] - P[1]) * t;
@ -32,7 +32,7 @@ static void evaluate(float* P, int n, float t, vec3 p) {
} else {
float b = 1.f;
p[0] = p[1] = p[2] = p[3] = 0.f;
for (int i = 0; i < n; i++, b *= (float) (n - i) / i) {
for (size_t i = 0; i < n; i++, b *= (float) (n - i) / i) {
float c1 = powf(1 - t, n - (i + 1));
float c2 = powf(t, i);
p[0] += b * c1 * c2 * P[i * 4 + 0];
@ -43,15 +43,14 @@ static void evaluate(float* P, int n, float t, vec3 p) {
}
}
Curve* lovrCurveInit(Curve* curve, int sizeHint) {
vec_init(&curve->points);
lovrAssert(!vec_reserve(&curve->points, sizeHint * 4), "Out of memory");
Curve* lovrCurveInit(Curve* curve) {
arr_init(&curve->points);
return curve;
}
void lovrCurveDestroy(void* ref) {
Curve* curve = ref;
vec_deinit(&curve->points);
arr_free(&curve->points);
}
void lovrCurveEvaluate(Curve* curve, float t, vec3 p) {
@ -62,18 +61,18 @@ void lovrCurveEvaluate(Curve* curve, float t, vec3 p) {
void lovrCurveGetTangent(Curve* curve, float t, vec3 p) {
float q[4];
int n = curve->points.length / 4;
size_t n = curve->points.length / 4;
evaluate(curve->points.data, n - 1, t, q);
evaluate(curve->points.data + 4, n - 1, t, p);
vec3_add(p, vec3_scale(q, -1.f));
vec3_normalize(p);
}
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, int n) {
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, uint32_t n) {
lovrAssert(curve->points.length >= 8, "Need at least 2 points to render a Curve");
lovrAssert(t1 >= 0.f && t2 <= 1.f, "Curve render interval must be within [0, 1]");
float step = 1.f / (n - 1);
for (int i = 0; i < n; i++) {
for (uint32_t i = 0; i < n; i++) {
evaluate(curve->points.data, curve->points.length / 4, t1 + (t2 - t1) * i * step, points + 4 * i);
}
}
@ -82,13 +81,14 @@ Curve* lovrCurveSlice(Curve* curve, float t1, float t2) {
lovrAssert(curve->points.length >= 8, "Need at least 2 points to slice a Curve");
lovrAssert(t1 >= 0.f && t2 <= 1.f, "Curve slice interval must be within [0, 1]");
Curve* new = lovrCurveCreate(curve->points.length / 4);
Curve* new = lovrCurveCreate();
arr_reserve(&new->points, curve->points.length);
new->points.length = curve->points.length;
int n = curve->points.length / 4;
size_t n = curve->points.length / 4;
// Right half of split at t1
for (int i = 0; i < n - 1; i++) {
for (size_t i = 0; i < n - 1; i++) {
evaluate(curve->points.data + 4 * i, n - i, t1, new->points.data + 4 * i);
}
@ -96,29 +96,29 @@ Curve* lovrCurveSlice(Curve* curve, float t1, float t2) {
// Split segment at t2, taking left half
float t = (t2 - t1) / (1.f - t1);
for (int i = n - 1; i >= 1; i--) {
for (size_t i = n - 1; i >= 1; i--) {
evaluate(new->points.data, i + 1, t, new->points.data + 4 * i);
}
return new;
}
int lovrCurveGetPointCount(Curve* curve) {
size_t lovrCurveGetPointCount(Curve* curve) {
return curve->points.length / 4;
}
void lovrCurveGetPoint(Curve* curve, int index, vec3 point) {
void lovrCurveGetPoint(Curve* curve, size_t index, vec3 point) {
vec3_init(point, curve->points.data + 4 * index);
}
void lovrCurveSetPoint(Curve* curve, int index, vec3 point) {
void lovrCurveSetPoint(Curve* curve, size_t index, vec3 point) {
vec3_init(curve->points.data + 4 * index, point);
}
void lovrCurveAddPoint(Curve* curve, vec3 point, int index) {
void lovrCurveAddPoint(Curve* curve, vec3 point, size_t index) {
// Reserve enough memory for 4 more floats, then record destination once memory is allocated
lovrAssert(!vec_reserve(&curve->points, curve->points.length + 4), "Out of memory");
arr_reserve(&curve->points, curve->points.length + 4);
float* dest = curve->points.data + index * 4;
// Shift remaining points over (if any) to create empty space
@ -131,6 +131,6 @@ void lovrCurveAddPoint(Curve* curve, vec3 point, int index) {
memcpy(dest, point, 4 * sizeof(float));
}
void lovrCurveRemovePoint(Curve* curve, int index) {
vec_swapsplice(&curve->points, index * 4, 4);
void lovrCurveRemovePoint(Curve* curve, size_t index) {
arr_splice(&curve->points, index * 4, 4);
}

View File

@ -1,19 +1,19 @@
#include "core/arr.h"
#include "core/maf.h"
#include "lib/vec/vec.h"
typedef struct {
vec_float_t points;
arr_t(float, 16) points;
} Curve;
Curve* lovrCurveInit(Curve* curve, int sizeHint);
#define lovrCurveCreate(...) lovrCurveInit(lovrAlloc(Curve), __VA_ARGS__)
Curve* lovrCurveInit(Curve* curve);
#define lovrCurveCreate(...) lovrCurveInit(lovrAlloc(Curve))
void lovrCurveDestroy(void* ref);
void lovrCurveEvaluate(Curve* curve, float t, vec3 point);
void lovrCurveGetTangent(Curve* curve, float t, vec3 point);
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, int n);
void lovrCurveRender(Curve* curve, float t1, float t2, vec3 points, uint32_t n);
Curve* lovrCurveSlice(Curve* curve, float t1, float t2);
int lovrCurveGetPointCount(Curve* curve);
void lovrCurveGetPoint(Curve* curve, int index, vec3 point);
void lovrCurveSetPoint(Curve* curve, int index, vec3 point);
void lovrCurveAddPoint(Curve* curve, vec3 point, int index);
void lovrCurveRemovePoint(Curve* curve, int index);
size_t lovrCurveGetPointCount(Curve* curve);
void lovrCurveGetPoint(Curve* curve, size_t index, vec3 point);
void lovrCurveSetPoint(Curve* curve, size_t index, vec3 point);
void lovrCurveAddPoint(Curve* curve, vec3 point, size_t index);
void lovrCurveRemovePoint(Curve* curve, size_t index);

View File

@ -11,8 +11,8 @@ static void defaultNearCallback(void* data, dGeomID a, dGeomID b) {
static void customNearCallback(void* data, dGeomID shapeA, dGeomID shapeB) {
World* world = data;
vec_push(&world->overlaps, dGeomGetData(shapeA));
vec_push(&world->overlaps, dGeomGetData(shapeB));
arr_push(&world->overlaps, dGeomGetData(shapeA));
arr_push(&world->overlaps, dGeomGetData(shapeB));
}
static void raycastCallback(void* data, dGeomID a, dGeomID b) {
@ -50,7 +50,7 @@ World* lovrWorldInit(World* world, float xg, float yg, float zg, bool allowSleep
world->space = dHashSpaceCreate(0);
dHashSpaceSetLevels(world->space, -4, 8);
world->contactGroup = dJointGroupCreate(0);
vec_init(&world->overlaps);
arr_init(&world->overlaps);
lovrWorldSetGravity(world, xg, yg, zg);
lovrWorldSetSleepingAllowed(world, allowSleep);
map_init(&world->tags);
@ -68,7 +68,7 @@ World* lovrWorldInit(World* world, float xg, float yg, float zg, bool allowSleep
void lovrWorldDestroy(void* ref) {
World* world = ref;
lovrWorldDestroyData(world);
vec_deinit(&world->overlaps);
arr_free(&world->overlaps);
map_deinit(&world->tags);
}
@ -110,7 +110,7 @@ void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* u
}
void lovrWorldComputeOverlaps(World* world) {
vec_clear(&world->overlaps);
arr_clear(&world->overlaps);
dSpaceCollide(world->space, world, customNearCallback);
}
@ -120,8 +120,8 @@ int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b) {
return 0;
}
*a = vec_pop(&world->overlaps);
*b = vec_pop(&world->overlaps);
*a = arr_pop(&world->overlaps);
*b = arr_pop(&world->overlaps);
return 1;
}
@ -278,8 +278,8 @@ Collider* lovrColliderInit(Collider* collider, World* world, float x, float y, f
collider->restitution = 0;
collider->tag = NO_TAG;
dBodySetData(collider->body, collider);
vec_init(&collider->shapes);
vec_init(&collider->joints);
arr_init(&collider->shapes);
arr_init(&collider->joints);
lovrColliderSetPosition(collider, x, y, z);
@ -300,8 +300,8 @@ Collider* lovrColliderInit(Collider* collider, World* world, float x, float y, f
void lovrColliderDestroy(void* ref) {
Collider* collider = ref;
lovrColliderDestroyData(collider);
vec_deinit(&collider->shapes);
vec_deinit(&collider->joints);
arr_free(&collider->shapes);
arr_free(&collider->joints);
}
void lovrColliderDestroyData(Collider* collider) {
@ -309,16 +309,16 @@ void lovrColliderDestroyData(Collider* collider) {
return;
}
vec_void_t* shapes = lovrColliderGetShapes(collider);
Shape* shape; int i;
vec_foreach(shapes, shape, i) {
lovrColliderRemoveShape(collider, shape);
size_t count;
Shape** shapes = lovrColliderGetShapes(collider, &count);
for (size_t i = 0; i < count; i++) {
lovrColliderRemoveShape(collider, shapes[i]);
}
vec_void_t* joints = lovrColliderGetJoints(collider);
Joint* joint; int j;
vec_foreach(joints, joint, j) {
lovrRelease(Joint, joint);
Joint** joints = lovrColliderGetJoints(collider, &count);
for (size_t i = 0; i < count; i++) {
lovrRelease(Joint, joints[i]);
}
dBodyDestroy(collider->body);
@ -359,27 +359,27 @@ void lovrColliderRemoveShape(Collider* collider, Shape* shape) {
}
}
vec_void_t* lovrColliderGetShapes(Collider* collider) {
vec_clear(&collider->shapes);
Shape** lovrColliderGetShapes(Collider* collider, size_t* count) {
arr_clear(&collider->shapes);
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) {
Shape* shape = dGeomGetData(geom);
if (shape) {
vec_push(&collider->shapes, shape);
arr_push(&collider->shapes, shape);
}
}
return &collider->shapes;
return *count = collider->shapes.length, collider->shapes.data;
}
vec_void_t* lovrColliderGetJoints(Collider* collider) {
vec_clear(&collider->joints);
Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
arr_clear(&collider->joints);
int jointCount = dBodyGetNumJoints(collider->body);
for (int i = 0; i < jointCount; i++) {
Joint* joint = dJointGetData(dBodyGetJoint(collider->body, i));
if (joint) {
vec_push(&collider->joints, joint);
arr_push(&collider->joints, joint);
}
}
return &collider->joints;
return *count = collider->joints.length, collider->joints.data;
}
void* lovrColliderGetUserData(Collider* collider) {

View File

@ -1,4 +1,4 @@
#include "lib/vec/vec.h"
#include "core/arr.h"
#include "lib/map/map.h"
#include <stdint.h>
#include <stdbool.h>
@ -25,12 +25,14 @@ typedef enum {
} JointType;
typedef struct Collider Collider;
typedef struct Shape Shape;
typedef struct Joint Joint;
typedef struct {
dWorldID id;
dSpaceID space;
dJointGroupID contactGroup;
vec_void_t overlaps;
arr_t(Shape*, 8) overlaps;
map_int_t tags;
uint16_t masks[MAX_TAGS];
Collider* head;
@ -43,29 +45,29 @@ struct Collider {
Collider* next;
void* userdata;
int tag;
vec_void_t shapes;
vec_void_t joints;
arr_t(Shape*, 2) shapes;
arr_t(Joint*, 2) joints;
float friction;
float restitution;
};
typedef struct Shape {
struct Shape {
ShapeType type;
dGeomID id;
Collider* collider;
void* userdata;
} Shape;
};
typedef Shape SphereShape;
typedef Shape BoxShape;
typedef Shape CapsuleShape;
typedef Shape CylinderShape;
typedef struct Joint {
struct Joint {
JointType type;
dJointID id;
void* userdata;
} Joint;
};
typedef Joint BallJoint;
typedef Joint DistanceJoint;
@ -112,8 +114,8 @@ void lovrColliderDestroyData(Collider* collider);
World* lovrColliderGetWorld(Collider* collider);
void lovrColliderAddShape(Collider* collider, Shape* shape);
void lovrColliderRemoveShape(Collider* collider, Shape* shape);
vec_void_t* lovrColliderGetShapes(Collider* collider);
vec_void_t* lovrColliderGetJoints(Collider* collider);
Shape** lovrColliderGetShapes(Collider* collider, size_t* count);
Joint** lovrColliderGetJoints(Collider* collider, size_t* count);
void* lovrColliderGetUserData(Collider* collider);
void lovrColliderSetUserData(Collider* collider, void* data);
const char* lovrColliderGetTag(Collider* collider);

View File

@ -5,7 +5,7 @@
#include <math.h>
Channel* lovrChannelInit(Channel* channel) {
vec_init(&channel->messages);
arr_init(&channel->messages);
mtx_init(&channel->lock, mtx_plain | mtx_timed);
cnd_init(&channel->cond);
return channel;
@ -14,7 +14,7 @@ Channel* lovrChannelInit(Channel* channel) {
void lovrChannelDestroy(void* ref) {
Channel* channel = ref;
lovrChannelClear(channel);
vec_deinit(&channel->messages);
arr_free(&channel->messages);
mtx_destroy(&channel->lock);
cnd_destroy(&channel->cond);
}
@ -24,7 +24,7 @@ bool lovrChannelPush(Channel* channel, Variant variant, double timeout, uint64_t
if (channel->messages.length == 0) {
lovrRetain(channel);
}
vec_insert(&channel->messages, 0, variant);
arr_push(&channel->messages, variant);
*id = ++channel->sent;
cnd_broadcast(&channel->cond);
@ -47,7 +47,7 @@ bool lovrChannelPush(Channel* channel, Variant variant, double timeout, uint64_t
until.tv_nsec = start.tv_nsec + fraction * 1e9;
cnd_timedwait(&channel->cond, &channel->lock, &until);
timespec_get(&stop, TIME_UTC);
timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / (double) 1e9;
timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9;
}
}
@ -60,9 +60,10 @@ bool lovrChannelPop(Channel* channel, Variant* variant, double timeout) {
mtx_lock(&channel->lock);
do {
if (channel->messages.length > 0) {
*variant = vec_pop(&channel->messages);
if (channel->messages.length == 0) {
if (channel->head < channel->messages.length) {
*variant = channel->messages.data[channel->head++];
if (channel->head == channel->messages.length) {
channel->head = channel->messages.length = 0;
lovrRelease(Channel, channel);
}
channel->received++;
@ -89,14 +90,14 @@ bool lovrChannelPop(Channel* channel, Variant* variant, double timeout) {
timespec_get(&stop, TIME_UTC);
timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / (double) 1e9;
}
} while (true);
} while (1);
}
bool lovrChannelPeek(Channel* channel, Variant* variant) {
mtx_lock(&channel->lock);
if (channel->messages.length > 0) {
*variant = vec_last(&channel->messages);
if (channel->head < channel->messages.length) {
*variant = channel->messages.data[channel->head];
mtx_unlock(&channel->lock);
return true;
}
@ -107,18 +108,19 @@ bool lovrChannelPeek(Channel* channel, Variant* variant) {
void lovrChannelClear(Channel* channel) {
mtx_lock(&channel->lock);
for (int i = 0; i < channel->messages.length; i++) {
for (size_t i = channel->head; i < channel->messages.length; i++) {
lovrVariantDestroy(&channel->messages.data[i]);
}
channel->received = channel->sent;
vec_clear(&channel->messages);
arr_clear(&channel->messages);
channel->head = 0;
cnd_broadcast(&channel->cond);
mtx_unlock(&channel->lock);
}
uint64_t lovrChannelGetCount(Channel* channel) {
mtx_lock(&channel->lock);
uint64_t length = channel->messages.length;
uint64_t length = channel->messages.length - channel->head;
mtx_unlock(&channel->lock);
return length;
}

View File

@ -1,15 +1,17 @@
#include "event/event.h"
#include "core/arr.h"
#include "lib/tinycthread/tinycthread.h"
#include "lib/vec/vec.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#pragma once
typedef struct Channel {
mtx_t lock;
cnd_t cond;
vec_t(Variant) messages;
arr_t(Variant, 1) messages;
size_t head;
uint64_t sent;
uint64_t received;
} Channel;