2018-09-26 17:39:17 +00:00
|
|
|
#include <stdarg.h>
|
2019-06-02 07:20:10 +00:00
|
|
|
#include <stddef.h>
|
2020-05-19 19:49:40 +00:00
|
|
|
#include <stdint.h>
|
2021-02-09 00:23:18 +00:00
|
|
|
#include <stdatomic.h>
|
2016-09-30 06:18:51 +00:00
|
|
|
|
2017-01-26 10:20:30 +00:00
|
|
|
#pragma once
|
2016-10-04 22:05:34 +00:00
|
|
|
|
2019-05-20 09:47:33 +00:00
|
|
|
#define LOVR_VERSION_MAJOR 0
|
2020-10-05 22:40:27 +00:00
|
|
|
#define LOVR_VERSION_MINOR 14
|
2019-05-20 09:47:33 +00:00
|
|
|
#define LOVR_VERSION_PATCH 0
|
2020-10-05 22:40:27 +00:00
|
|
|
#define LOVR_VERSION_ALIAS "Maximum Moss"
|
2019-05-20 09:47:33 +00:00
|
|
|
|
2019-01-04 10:18:21 +00:00
|
|
|
#ifdef _WIN32
|
2020-10-26 08:24:44 +00:00
|
|
|
#define LOVR_NORETURN __declspec(noreturn)
|
|
|
|
#define LOVR_THREAD_LOCAL __declspec(thread)
|
2019-06-03 03:35:52 +00:00
|
|
|
#define LOVR_ALIGN(n) __declspec(align(n))
|
2019-12-05 21:39:04 +00:00
|
|
|
#define LOVR_RESTRICT __restrict
|
2019-01-04 10:18:21 +00:00
|
|
|
#else
|
2019-05-20 11:05:39 +00:00
|
|
|
#define LOVR_NORETURN __attribute__((noreturn))
|
|
|
|
#define LOVR_THREAD_LOCAL __thread
|
2019-06-03 03:35:52 +00:00
|
|
|
#define LOVR_ALIGN(n) __attribute__((aligned(n)))
|
2019-12-05 21:39:04 +00:00
|
|
|
#define LOVR_RESTRICT restrict
|
2019-01-18 16:44:03 +00:00
|
|
|
#endif
|
2018-12-13 03:35:18 +00:00
|
|
|
|
2019-06-21 04:43:40 +00:00
|
|
|
#ifndef M_PI
|
|
|
|
#define M_PI 3.14159265358979
|
|
|
|
#endif
|
|
|
|
|
2018-09-27 18:45:43 +00:00
|
|
|
#define MAX(a, b) (a > b ? a : b)
|
|
|
|
#define MIN(a, b) (a < b ? a : b)
|
|
|
|
#define CLAMP(x, min, max) MAX(min, MIN(max, x))
|
2020-10-26 08:03:19 +00:00
|
|
|
#define ALIGN(p, n) (((uintptr_t) (p) + (n - 1)) & ~(n - 1))
|
2019-05-20 11:15:24 +00:00
|
|
|
#define CHECK_SIZEOF(T) int(*_o)[sizeof(T)]=1
|
2018-11-25 02:04:27 +00:00
|
|
|
|
2019-04-05 12:08:03 +00:00
|
|
|
typedef struct Color { float r, g, b, a; } Color;
|
2017-08-02 08:25:56 +00:00
|
|
|
|
lovr.log;
lovr.log is a new callback that is invoked whenever LÖVR wants to
send the project a message. For example, this could be a performance
warning from the graphics module, an error message from one of the
headset backends, or an API deprecation notice.
The callback's signature is (message, level, tag). The message is a
string containing the message to log, level is a string that is currently
one of "debug", "info", "warn", "error", and tag is an optional string
that is used to indicate the source of the message for grouping purposes.
The default implementation of the callback just prints the message,
but the callback can be overridden to do things like filter messages,
write them to a file, or even render them in VR. Projects can also
invoke the callback directly to log their own messages.
2020-07-06 22:20:55 +00:00
|
|
|
// Error handling
|
2019-06-02 07:20:10 +00:00
|
|
|
typedef void errorFn(void*, const char*, va_list);
|
|
|
|
extern LOVR_THREAD_LOCAL errorFn* lovrErrorCallback;
|
2019-05-20 11:05:39 +00:00
|
|
|
extern LOVR_THREAD_LOCAL void* lovrErrorUserdata;
|
lovr.log;
lovr.log is a new callback that is invoked whenever LÖVR wants to
send the project a message. For example, this could be a performance
warning from the graphics module, an error message from one of the
headset backends, or an API deprecation notice.
The callback's signature is (message, level, tag). The message is a
string containing the message to log, level is a string that is currently
one of "debug", "info", "warn", "error", and tag is an optional string
that is used to indicate the source of the message for grouping purposes.
The default implementation of the callback just prints the message,
but the callback can be overridden to do things like filter messages,
write them to a file, or even render them in VR. Projects can also
invoke the callback directly to log their own messages.
2020-07-06 22:20:55 +00:00
|
|
|
void lovrSetErrorCallback(errorFn* callback, void* userdata);
|
2019-05-20 11:05:39 +00:00
|
|
|
void LOVR_NORETURN lovrThrow(const char* format, ...);
|
2019-04-05 09:50:11 +00:00
|
|
|
#define lovrAssert(c, ...) if (!(c)) { lovrThrow(__VA_ARGS__); }
|
2020-05-19 19:49:40 +00:00
|
|
|
|
lovr.log;
lovr.log is a new callback that is invoked whenever LÖVR wants to
send the project a message. For example, this could be a performance
warning from the graphics module, an error message from one of the
headset backends, or an API deprecation notice.
The callback's signature is (message, level, tag). The message is a
string containing the message to log, level is a string that is currently
one of "debug", "info", "warn", "error", and tag is an optional string
that is used to indicate the source of the message for grouping purposes.
The default implementation of the callback just prints the message,
but the callback can be overridden to do things like filter messages,
write them to a file, or even render them in VR. Projects can also
invoke the callback directly to log their own messages.
2020-07-06 22:20:55 +00:00
|
|
|
// Logging
|
|
|
|
typedef void logFn(void*, int, const char*, const char*, va_list);
|
|
|
|
enum { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR };
|
|
|
|
void lovrSetLogCallback(logFn* callback, void* userdata);
|
|
|
|
void lovrLog(int level, const char* tag, const char* format, ...);
|
|
|
|
|
|
|
|
// Hash function (FNV1a)
|
2020-12-25 19:29:22 +00:00
|
|
|
static inline uint64_t hash64(const void* data, size_t length) {
|
2020-05-19 19:49:40 +00:00
|
|
|
const uint8_t* bytes = (const uint8_t*) data;
|
|
|
|
uint64_t hash = 0xcbf29ce484222325;
|
|
|
|
for (size_t i = 0; i < length; i++) {
|
|
|
|
hash = (hash ^ bytes[i]) * 0x100000001b3;
|
|
|
|
}
|
|
|
|
return hash;
|
|
|
|
}
|
2021-02-09 00:23:18 +00:00
|
|
|
|
|
|
|
// Refcounting
|
|
|
|
typedef atomic_uint ref_t;
|
|
|
|
#define lovrRetain(o) if (o) { atomic_fetch_add((ref_t*) (o), 1); }
|
2021-02-09 00:52:26 +00:00
|
|
|
#define lovrRelease(o, f) if (o && atomic_fetch_sub((ref_t*) (o), 1) == 1) f(o)
|
2021-02-09 01:25:05 +00:00
|
|
|
|
|
|
|
// Dynamic Array
|
|
|
|
typedef void* arr_allocator(void* data, size_t size);
|
|
|
|
#define arr_t(T) struct { T* data; arr_allocator* alloc; size_t length, capacity; }
|
|
|
|
#define arr_init(a, allocator) (a)->data = NULL, (a)->length = 0, (a)->capacity = 0, (a)->alloc = allocator
|
|
|
|
#define arr_free(a) (a)->alloc((a)->data, 0)
|
|
|
|
#define arr_reserve(a, n) _arr_reserve((void**) &((a)->data), n, &(a)->capacity, sizeof(*(a)->data), (a)->alloc)
|
|
|
|
#define arr_expand(a, n) arr_reserve(a, (a)->length + n)
|
|
|
|
#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), ((a)->length - (n)) * sizeof(*(a)->data)), (a)->length -= n
|
|
|
|
#define arr_clear(a) (a)->length = 0
|
|
|
|
|
|
|
|
static inline void _arr_reserve(void** data, size_t n, size_t* capacity, size_t stride, arr_allocator* allocator) {
|
|
|
|
if (*capacity >= n) return;
|
|
|
|
if (*capacity == 0) *capacity = 1;
|
|
|
|
while (*capacity < n) *capacity *= 2;
|
|
|
|
*data = allocator(*data, *capacity * stride);
|
|
|
|
lovrAssert(*data, "Out of memory");
|
|
|
|
}
|