# HG changeset patch # User John Tsiombikas # Date 1409273125 -10800 # Node ID ded3d0a74e193fd01cef6359edf179acbf46ae4e initial commit diff -r 000000000000 -r ded3d0a74e19 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,14 @@ +\.o$ +\.d$ +\.swp$ +\.so$ +\.so\. +\.a$ +\.dll$ +\.lib$ +\.obj$ +\.suo$ +\.sdf$ +\.opensdf$ +^Debug +^Release diff -r 000000000000 -r ded3d0a74e19 libgoatvr.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgoatvr.def Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,30 @@ +LIBRARY libgoatvr +EXPORTS + vr_init + vr_shutdown + + vr_module_count + vr_module_name + + vr_use_module + vr_use_module_named + + vr_set_opti + vr_set_optf + vr_get_opti + vr_get_optf + + vr_view_translation + vr_view_rotation + + vr_view_matrix + vr_proj_matrix + + vr_begin + vr_end + vr_swap_buffers + + vr_output_texture + vr_output_texture_eye + + vr_recenter \ No newline at end of file diff -r 000000000000 -r ded3d0a74e19 libgoatvr.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgoatvr.sln Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgoatvr", "libgoatvr.vcxproj", "{6AD69AF8-6F44-4D45-A59C-A7A07F6E1CE0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgoatvr_static", "libgoatvr_static.vcxproj", "{DF0FC238-A249-432C-9163-3778DDE78A62}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6AD69AF8-6F44-4D45-A59C-A7A07F6E1CE0}.Debug|Win32.ActiveCfg = Debug|Win32 + {6AD69AF8-6F44-4D45-A59C-A7A07F6E1CE0}.Debug|Win32.Build.0 = Debug|Win32 + {6AD69AF8-6F44-4D45-A59C-A7A07F6E1CE0}.Release|Win32.ActiveCfg = Release|Win32 + {6AD69AF8-6F44-4D45-A59C-A7A07F6E1CE0}.Release|Win32.Build.0 = Release|Win32 + {DF0FC238-A249-432C-9163-3778DDE78A62}.Debug|Win32.ActiveCfg = Debug|Win32 + {DF0FC238-A249-432C-9163-3778DDE78A62}.Debug|Win32.Build.0 = Debug|Win32 + {DF0FC238-A249-432C-9163-3778DDE78A62}.Release|Win32.ActiveCfg = Release|Win32 + {DF0FC238-A249-432C-9163-3778DDE78A62}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r 000000000000 -r ded3d0a74e19 libgoatvr.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgoatvr.vcxproj Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,107 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6AD69AF8-6F44-4D45-A59C-A7A07F6E1CE0} + Win32Proj + libgoatvr + + + + DynamicLibrary + true + v120 + MultiByte + + + DynamicLibrary + false + v120 + false + MultiByte + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGOATVR_EXPORTS;%(PreprocessorDefinitions) + 4244;4996 + + + Windows + true + libgoatvr.def + opengl32.lib;libovrd.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGOATVR_EXPORTS;%(PreprocessorDefinitions) + 4244;4996 + + + Windows + true + true + true + libgoatvr.def + opengl32.lib;libovr.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 000000000000 -r ded3d0a74e19 libgoatvr.vcxproj.filters --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgoatvr.vcxproj.filters Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,55 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;h;inl + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + src + + + src + + + src + + + src + + + src + + + + + + \ No newline at end of file diff -r 000000000000 -r ded3d0a74e19 libgoatvr_static.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgoatvr_static.vcxproj Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,102 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + {DF0FC238-A249-432C-9163-3778DDE78A62} + Win32Proj + libgoatvr_static + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + false + MultiByte + + + + + + + + + + + + + $(Configuration)_static\ + $(SolutionDir)$(Configuration)_static\ + + + $(Configuration)_static\ + $(SolutionDir)$(Configuration)_static\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + 4244;4996 + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + 4244;4996 + + + Windows + true + true + true + + + + + + \ No newline at end of file diff -r 000000000000 -r ded3d0a74e19 libgoatvr_static.vcxproj.filters --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libgoatvr_static.vcxproj.filters Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,52 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;h;inl + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + src + + + src + + + src + + + src + + + src + + + \ No newline at end of file diff -r 000000000000 -r ded3d0a74e19 src/mathutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mathutil.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,78 @@ +#include +#include +#include "mathutil.h" + +#define M(i, j) ((i) * 4 + (j)) + +static const float idmat[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + +void rotation_matrix(const float *quat, float *matrix) +{ + matrix[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2]; + matrix[1] = 2.0 * quat[0] * quat[1] + 2.0 * quat[3] * quat[2]; + matrix[2] = 2.0 * quat[2] * quat[0] - 2.0 * quat[3] * quat[1]; + matrix[3] = 0.0f; + + matrix[4] = 2.0 * quat[0] * quat[1] - 2.0 * quat[3] * quat[2]; + matrix[5] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[2]*quat[2]; + matrix[6] = 2.0 * quat[1] * quat[2] + 2.0 * quat[3] * quat[0]; + matrix[7] = 0.0f; + + matrix[8] = 2.0 * quat[2] * quat[0] + 2.0 * quat[3] * quat[1]; + matrix[9] = 2.0 * quat[1] * quat[2] - 2.0 * quat[3] * quat[0]; + matrix[10] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[1]*quat[1]; + matrix[11] = 0.0f; + + matrix[12] = matrix[13] = matrix[14] = 0.0f; + matrix[15] = 1.0f; + + transpose_matrix(matrix); +} + +void translation_matrix(const float *vec, float *matrix) +{ + memcpy(matrix, idmat, sizeof idmat); + matrix[12] = vec[0]; + matrix[13] = vec[1]; + matrix[14] = vec[2]; +} + +void mult_matrix(float *dest, const float *m1, const float *m2) +{ + int i, j; + float tmp[16]; + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + tmp[M(i, j)] = m1[M(i, 0)] * m2[M(0, j)] + m1[M(i, 1)] * m2[M(1, j)] + + m1[M(i, 2)] * m2[M(2, j)] + m1[M(i, 3)] * m2[M(3, j)]; + } + } + memcpy(dest, tmp, sizeof tmp); +} + +void transpose_matrix(float *matrix) +{ + int i, j; + float tmp[16]; + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + tmp[M(i, j)] = matrix[M(j, i)]; + } + } + memcpy(matrix, tmp, sizeof tmp); +} + +void print_matrix(const float *matrix) +{ + int i, j; + + for(i=0; i<4; i++) { + putchar('['); + for(j=0; j<4; j++) { + printf("%6.3f ", matrix[M(i, j)]); + } + printf("]\n"); + } +} diff -r 000000000000 -r ded3d0a74e19 src/mathutil.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mathutil.h Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,13 @@ +#ifndef MATHUTIL_H_ +#define MATHUTIL_H_ + +void rotation_matrix(const float *quat, float *matrix); +void translation_matrix(const float *vec, float *matrix); + +void mult_matrix(float *dest, const float *m1, const float *m2); + +void transpose_matrix(float *matrix); + +void print_matrix(const float *matrix); + +#endif /* MATHUTIL_H_ */ diff -r 000000000000 -r ded3d0a74e19 src/opt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opt.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include "opt.h" +#include "rbtree.h" + +static void opt_del_func(struct rbnode *opt, void *cls) +{ + free(opt); +} + +void *create_options(void) +{ + struct rbtree *db = rb_create(RB_KEY_STRING); + rb_set_delete_func(db, opt_del_func, 0); + return db; +} + +void destroy_options(void *optdb) +{ + rb_destroy(optdb); +} + +void set_option_int(void *optdb, const char *key, int val) +{ + struct option *opt = malloc(sizeof *opt); + if(!opt) { + fprintf(stderr, "failed to set option: %s: %s\n", key, strerror(errno)); + return; + } + opt->type = OTYPE_INT; + opt->ival = val; + opt->fval = (float)val; + + if(rb_insert(optdb, (void*)key, opt) == -1) { + fprintf(stderr, "failed to set option: %s\n", key); + } +} + +void set_option_float(void *optdb, const char *key, float val) +{ + struct option *opt = malloc(sizeof *opt); + if(!opt) { + fprintf(stderr, "failed to set option: %s: %s\n", key, strerror(errno)); + return; + } + opt->type = OTYPE_FLOAT; + opt->fval = val; + opt->ival = (int)val; + + if(rb_insert(optdb, (void*)key, opt) == -1) { + fprintf(stderr, "failed to set option: %s\n", key); + } +} + +int get_option_int(void *optdb, const char *key, int *val) +{ + struct option *opt = rb_find(optdb, (void*)key); + if(!opt) { + *val = 0; + return -1; + } + *val = opt->ival; + return 0; +} + +int get_option_float(void *optdb, const char *key, float *val) +{ + struct option *opt = rb_find(optdb, (void*)key); + if(!opt) { + *val = 0.0f; + return -1; + } + *val = opt->fval; + return 0; +} diff -r 000000000000 -r ded3d0a74e19 src/opt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/opt.h Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,21 @@ +#ifndef OPT_H_ +#define OPT_H_ + +enum opt_type { OTYPE_INT, OTYPE_FLOAT }; + +struct option { + enum opt_type type; + int ival; + float fval; +}; + +void *create_options(void); +void destroy_options(void *optdb); + +void set_option_int(void *optdb, const char *key, int val); +void set_option_float(void *optdb, const char *key, float val); + +int get_option_int(void *optdb, const char *key, int *val); +int get_option_float(void *optdb, const char *key, float *val); + +#endif /* OPT_H_ */ diff -r 000000000000 -r ded3d0a74e19 src/rbtree.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rbtree.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,501 @@ +/* +rbtree - simple balanced binary search tree (red-black tree) library. +Copyright (C) 2011-2014 John Tsiombikas + +rbtree is free software, feel free to use, modify, and redistribute it, under +the terms of the 3-clause BSD license. See COPYING for details. + */ +#include +#include +#include +#include +#include "rbtree.h" + +#define INT2PTR(x) ((void*)(intptr_t)(x)) +#define PTR2INT(x) ((int)(intptr_t)(x)) + +struct rbtree { + struct rbnode *root; + + rb_alloc_func_t alloc; + rb_free_func_t free; + + rb_cmp_func_t cmp; + rb_del_func_t del; + void *del_cls; + + struct rbnode *rstack, *iter; +}; + +static int cmpaddr(const void *ap, const void *bp); +static int cmpint(const void *ap, const void *bp); + +static int count_nodes(struct rbnode *node); +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls); +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data); +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key); +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/ +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls); + +struct rbtree *rb_create(rb_cmp_func_t cmp_func) +{ + struct rbtree *rb; + + if(!(rb = malloc(sizeof *rb))) { + return 0; + } + if(rb_init(rb, cmp_func) == -1) { + free(rb); + return 0; + } + return rb; +} + +void rb_free(struct rbtree *rb) +{ + rb_destroy(rb); + free(rb); +} + + +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func) +{ + memset(rb, 0, sizeof *rb); + + if(cmp_func == RB_KEY_INT) { + rb->cmp = cmpint; + } else if(cmp_func == RB_KEY_STRING) { + rb->cmp = (rb_cmp_func_t)strcmp; + } else { + rb->cmp = cmpaddr; + } + + rb->alloc = malloc; + rb->free = free; + return 0; +} + +void rb_destroy(struct rbtree *rb) +{ + del_tree(rb->root, rb->del, rb->del_cls); +} + +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free) +{ + rb->alloc = alloc; + rb->free = free; +} + + +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func) +{ + rb->cmp = func; +} + +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls) +{ + rb->del = func; + rb->del_cls = cls; +} + + +void rb_clear(struct rbtree *rb) +{ + del_tree(rb->root, rb->del, rb->del_cls); + rb->root = 0; +} + +int rb_copy(struct rbtree *dest, struct rbtree *src) +{ + struct rbnode *node; + + rb_clear(dest); + rb_begin(src); + while((node = rb_next(src))) { + if(rb_insert(dest, node->key, node->data) == -1) { + return -1; + } + } + return 0; +} + +int rb_size(struct rbtree *rb) +{ + return count_nodes(rb->root); +} + +int rb_insert(struct rbtree *rb, void *key, void *data) +{ + rb->root = insert(rb, rb->root, key, data); + rb->root->red = 0; + return 0; +} + +int rb_inserti(struct rbtree *rb, int key, void *data) +{ + rb->root = insert(rb, rb->root, INT2PTR(key), data); + rb->root->red = 0; + return 0; +} + + +int rb_delete(struct rbtree *rb, void *key) +{ + rb->root = delete(rb, rb->root, key); + rb->root->red = 0; + return 0; +} + +int rb_deletei(struct rbtree *rb, int key) +{ + rb->root = delete(rb, rb->root, INT2PTR(key)); + rb->root->red = 0; + return 0; +} + + +void *rb_find(struct rbtree *rb, void *key) +{ + struct rbnode *node = rb->root; + + while(node) { + int cmp = rb->cmp(key, node->key); + if(cmp == 0) { + return node->data; + } + node = cmp < 0 ? node->left : node->right; + } + return 0; +} + +void *rb_findi(struct rbtree *rb, int key) +{ + return rb_find(rb, INT2PTR(key)); +} + + +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls) +{ + traverse(rb->root, func, cls); +} + + +struct rbnode *rb_root(struct rbtree *rb) +{ + return rb->root; +} + +void rb_begin(struct rbtree *rb) +{ + rb->rstack = 0; + rb->iter = rb->root; +} + +#define push(sp, x) ((x)->next = (sp), (sp) = (x)) +#define pop(sp) ((sp) = (sp)->next) +#define top(sp) (sp) + +struct rbnode *rb_next(struct rbtree *rb) +{ + struct rbnode *res = 0; + + while(rb->rstack || rb->iter) { + if(rb->iter) { + push(rb->rstack, rb->iter); + rb->iter = rb->iter->left; + } else { + rb->iter = top(rb->rstack); + pop(rb->rstack); + res = rb->iter; + rb->iter = rb->iter->right; + break; + } + } + return res; +} + +void *rb_node_key(struct rbnode *node) +{ + return node ? node->key : 0; +} + +int rb_node_keyi(struct rbnode *node) +{ + return node ? PTR2INT(node->key) : 0; +} + +void *rb_node_data(struct rbnode *node) +{ + return node ? node->data : 0; +} + +static int cmpaddr(const void *ap, const void *bp) +{ + return ap < bp ? -1 : (ap > bp ? 1 : 0); +} + +static int cmpint(const void *ap, const void *bp) +{ + return PTR2INT(ap) - PTR2INT(bp); +} + + +/* ---- left-leaning 2-3 red-black implementation ---- */ + +/* helper prototypes */ +static int is_red(struct rbnode *tree); +static void color_flip(struct rbnode *tree); +static struct rbnode *rot_left(struct rbnode *a); +static struct rbnode *rot_right(struct rbnode *a); +static struct rbnode *find_min(struct rbnode *tree); +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree); +/*static struct rbnode *move_red_right(struct rbnode *tree);*/ +static struct rbnode *move_red_left(struct rbnode *tree); +static struct rbnode *fix_up(struct rbnode *tree); + +static int count_nodes(struct rbnode *node) +{ + if(!node) + return 0; + + return 1 + count_nodes(node->left) + count_nodes(node->right); +} + +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls) +{ + if(!node) + return; + + del_tree(node->left, delfunc, cls); + del_tree(node->right, delfunc, cls); + + if(delfunc) { + delfunc(node, cls); + } + free(node); +} + +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data) +{ + int cmp; + + if(!tree) { + struct rbnode *node = rb->alloc(sizeof *node); + node->red = 1; + node->key = key; + node->data = data; + node->left = node->right = 0; + return node; + } + + cmp = rb->cmp(key, tree->key); + + if(cmp < 0) { + tree->left = insert(rb, tree->left, key, data); + } else if(cmp > 0) { + tree->right = insert(rb, tree->right, key, data); + } else { + tree->data = data; + } + + /* fix right-leaning reds */ + if(is_red(tree->right)) { + tree = rot_left(tree); + } + /* fix two reds in a row */ + if(is_red(tree->left) && is_red(tree->left->left)) { + tree = rot_right(tree); + } + + /* if 4-node, split it by color inversion */ + if(is_red(tree->left) && is_red(tree->right)) { + color_flip(tree); + } + + return tree; +} + +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key) +{ + int cmp; + + if(!tree) { + return 0; + } + + cmp = rb->cmp(key, tree->key); + + if(cmp < 0) { + if(!is_red(tree->left) && !is_red(tree->left->left)) { + tree = move_red_left(tree); + } + tree->left = delete(rb, tree->left, key); + } else { + /* need reds on the right */ + if(is_red(tree->left)) { + tree = rot_right(tree); + } + + /* found it at the bottom (XXX what certifies left is null?) */ + if(cmp == 0 && !tree->right) { + if(rb->del) { + rb->del(tree, rb->del_cls); + } + rb->free(tree); + return 0; + } + + if(!is_red(tree->right) && !is_red(tree->right->left)) { + tree = move_red_left(tree); + } + + if(key == tree->key) { + struct rbnode *rmin = find_min(tree->right); + tree->key = rmin->key; + tree->data = rmin->data; + tree->right = del_min(rb, tree->right); + } else { + tree->right = delete(rb, tree->right, key); + } + } + + return fix_up(tree); +} + +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key) +{ + int cmp; + + if(!node) + return 0; + + if((cmp = rb->cmp(key, node->key)) == 0) { + return node; + } + return find(rb, cmp < 0 ? node->left : node->right, key); +}*/ + +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls) +{ + if(!node) + return; + + traverse(node->left, func, cls); + func(node, cls); + traverse(node->right, func, cls); +} + +/* helpers */ + +static int is_red(struct rbnode *tree) +{ + return tree && tree->red; +} + +static void color_flip(struct rbnode *tree) +{ + tree->red = !tree->red; + tree->left->red = !tree->left->red; + tree->right->red = !tree->right->red; +} + +static struct rbnode *rot_left(struct rbnode *a) +{ + struct rbnode *b = a->right; + a->right = b->left; + b->left = a; + b->red = a->red; + a->red = 1; + return b; +} + +static struct rbnode *rot_right(struct rbnode *a) +{ + struct rbnode *b = a->left; + a->left = b->right; + b->right = a; + b->red = a->red; + a->red = 1; + return b; +} + +static struct rbnode *find_min(struct rbnode *tree) +{ + struct rbnode *node = tree; + + if(!tree) + return 0; + + while(node->left) { + node = node->left; + } + return node; +} + +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree) +{ + if(!tree->left) { + if(rb->del) { + rb->del(tree->left, rb->del_cls); + } + rb->free(tree->left); + return 0; + } + + /* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */ + if(!is_red(tree->left) && !is_red(tree->left->left)) { + tree = move_red_left(tree); + } + tree->left = del_min(rb, tree->left); + + /* fix right-reds, red-reds, and split 4-nodes on the way up */ + return fix_up(tree); +} + +#if 0 +/* push a red link on this node to the right */ +static struct rbnode *move_red_right(struct rbnode *tree) +{ + /* flipping it makes both children go red, so we have a red to the right */ + color_flip(tree); + + /* if after the flip we've got a red-red situation to the left, fix it */ + if(is_red(tree->left->left)) { + tree = rot_right(tree); + color_flip(tree); + } + return tree; +} +#endif + +/* push a red link on this node to the left */ +static struct rbnode *move_red_left(struct rbnode *tree) +{ + /* flipping it makes both children go red, so we have a red to the left */ + color_flip(tree); + + /* if after the flip we've got a red-red on the right-left, fix it */ + if(is_red(tree->right->left)) { + tree->right = rot_right(tree->right); + tree = rot_left(tree); + color_flip(tree); + } + return tree; +} + +static struct rbnode *fix_up(struct rbnode *tree) +{ + /* fix right-leaning */ + if(is_red(tree->right)) { + tree = rot_left(tree); + } + /* change invalid red-red pairs into a proper 4-node */ + if(is_red(tree->left) && is_red(tree->left->left)) { + tree = rot_right(tree); + } + /* split 4-nodes */ + if(is_red(tree->left) && is_red(tree->right)) { + color_flip(tree); + } + return tree; +} diff -r 000000000000 -r ded3d0a74e19 src/rbtree.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rbtree.h Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,78 @@ +/* +rbtree - simple balanced binary search tree (red-black tree) library. +Copyright (C) 2011-2014 John Tsiombikas + +rbtree is free software, feel free to use, modify, and redistribute it, under +the terms of the 3-clause BSD license. See COPYING for details. + */ +#ifndef RBTREE_H_ +#define RBTREE_H_ + +struct rbtree; + + +struct rbnode { + void *key, *data; + int red; + struct rbnode *left, *right; + struct rbnode *next; /* for iterator stack */ +}; + + +typedef void *(*rb_alloc_func_t)(size_t); +typedef void (*rb_free_func_t)(void*); + +typedef int (*rb_cmp_func_t)(const void*, const void*); +typedef void (*rb_del_func_t)(struct rbnode*, void*); + +#define RB_KEY_ADDR (rb_cmp_func_t)(0) +#define RB_KEY_INT (rb_cmp_func_t)(1) +#define RB_KEY_STRING (rb_cmp_func_t)(3) + + +#ifdef __cplusplus +extern "C" { +#endif + +struct rbtree *rb_create(rb_cmp_func_t cmp_func); +void rb_free(struct rbtree *rb); + +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func); +void rb_destroy(struct rbtree *rb); + +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free); +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func); +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls); +/* TODO add user deep copy function */ + +void rb_clear(struct rbtree *rb); +int rb_copy(struct rbtree *dest, struct rbtree *src); + +int rb_size(struct rbtree *rb); + +int rb_insert(struct rbtree *rb, void *key, void *data); +int rb_inserti(struct rbtree *rb, int key, void *data); + +int rb_delete(struct rbtree *rb, void *key); +int rb_deletei(struct rbtree *rb, int key); + +void *rb_find(struct rbtree *rb, void *key); +void *rb_findi(struct rbtree *rb, int key); + +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls); + +struct rbnode *rb_root(struct rbtree *rb); + +void rb_begin(struct rbtree *rb); +struct rbnode *rb_next(struct rbtree *rb); + +void *rb_node_key(struct rbnode *node); +int rb_node_keyi(struct rbnode *node); +void *rb_node_data(struct rbnode *node); + +#ifdef __cplusplus +} +#endif + + +#endif /* RBTREE_H_ */ diff -r 000000000000 -r ded3d0a74e19 src/vr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,260 @@ +#include +#include +#include "vr.h" +#include "vr_impl.h" +#include "mathutil.h" + + +static void swap_buffers(void); + + +static struct vr_module *vrm; +static float idmat[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 +}; +static float fbtex_rect[] = { + 0, 0, 1, 1 +}; + +int vr_init(void) +{ + int i, nmodules; + + if(vrm) { + vr_shutdown(); + } + + vr_init_modules(); + + nmodules = vr_get_num_modules(); + for(i=0; iinit() != -1) { + /* add to the active modules array */ + vr_activate_module(i); + if(!vrm) { + vr_use_module(0); + } + } + } + + if(!vrm) { + return -1; + } + return 0; +} + +void vr_shutdown(void) +{ + vr_clear_modules(); + vrm = 0; + fbtex_rect[0] = fbtex_rect[1] = 0; + fbtex_rect[2] = fbtex_rect[3] = 1; +} + +int vr_module_count(void) +{ + return vr_get_num_active_modules(); +} + +const char *vr_module_name(int idx) +{ + struct vr_module *m = vr_get_active_module(idx); + if(!m) { + return 0; + } + return m->name; +} + +int vr_use_module(int idx) +{ + if(idx >= 0 && idx < vr_get_num_active_modules()) { + struct vr_module *m = vr_get_active_module(idx); + if(m != vrm) { + vrm = m; + printf("using vr module: %s\n", vrm->name); + } + return 0; + } + return -1; +} + +int vr_use_module_named(const char *name) +{ + int i, count = vr_get_num_active_modules(); + + for(i=0; iname, name) == 0) { + return vr_use_module(i); + } + } + return -1; +} + +void vr_set_opti(const char *optname, int val) +{ + if(vrm && vrm->set_option) { + vrm->set_option(optname, OTYPE_INT, &val); + } +} + +void vr_set_optf(const char *optname, float val) +{ + if(vrm && vrm->set_option) { + vrm->set_option(optname, OTYPE_FLOAT, &val); + } +} + +int vr_get_opti(const char *optname) +{ + int res = 0; + + if(vrm && vrm->get_option) { + vrm->get_option(optname, OTYPE_INT, &res); + } + return res; +} + +float vr_get_optf(const char *optname) +{ + float res = 0.0f; + + if(vrm && vrm->get_option) { + vrm->get_option(optname, OTYPE_FLOAT, &res); + } + return res; +} + + +int vr_view_translation(int eye, float *vec) +{ + if(vrm && vrm->translation) { + vrm->translation(eye, vec); + return 1; + } + vec[0] = vec[1] = vec[2] = 0.0f; + return 0; +} + +int vr_view_rotation(int eye, float *quat) +{ + if(vrm && vrm->rotation) { + vrm->rotation(eye, quat); + return 1; + } + quat[0] = quat[1] = quat[2] = 0.0f; + quat[3] = 1.0f; + return 0; +} + +int vr_view_matrix(int eye, float *mat) +{ + int have_trans, have_rot; + float offs[3], quat[4]; + float rmat[16], tmat[16]; + + if(vrm && vrm->view_matrix) { + vrm->view_matrix(eye, mat); + return 1; + } + + have_trans = vr_view_translation(eye, offs); + have_rot = vr_view_rotation(eye, quat); + + if(!have_trans && !have_rot) { + return 0; + } + + offs[0] = -offs[0]; + offs[1] = -offs[1]; + offs[2] = -offs[2]; + + translation_matrix(offs, tmat); + rotation_matrix(quat, rmat); + mult_matrix(mat, tmat, rmat); + return 1; +} + +int vr_proj_matrix(int eye, float znear, float zfar, float *mat) +{ + if(vrm && vrm->proj_matrix) { + vrm->proj_matrix(eye, znear, zfar, mat); + return 1; + } + memcpy(mat, idmat, sizeof idmat); + return 0; +} + +void vr_begin(int eye) +{ + if(vrm && vrm->begin) { + vrm->begin(eye); + } +} + +void vr_end(void) +{ + if(vrm && vrm->end) { + vrm->end(); + } +} + +int vr_swap_buffers(void) +{ + int res = 0; + + if(vrm && vrm->present) { + res = vrm->present(); + } + + if(!res) { + swap_buffers(); + } + return 0; +} + +void vr_output_texture(unsigned int tex, float umin, float vmin, float umax, float vmax) +{ + float halfu = (umax + umin) * 0.5f; + + vr_output_texture_eye(VR_EYE_LEFT, tex, umin, vmin, halfu, vmax); + vr_output_texture_eye(VR_EYE_RIGHT, tex, halfu, vmin, umax, vmax); +} + +void vr_output_texture_eye(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax) +{ + if(vrm && vrm->set_eye_texture) { + vrm->set_eye_texture(eye, tex, umin, vmin, umax, vmax); + } +} + +void vr_recenter(void) +{ + if(vrm && vrm->recenter) { + vrm->recenter(); + } +} + + +#ifdef __unix__ +#include + +static void swap_buffers(void) +{ + glXSwapBuffers(glXGetCurrentDisplay(), glXGetCurrentDrawable()); +} + +#endif + +#ifdef WIN32 +#include + +static void swap_buffers(void) +{ + SwapBuffers(wglGetCurrentDC()); +} +#endif diff -r 000000000000 -r ded3d0a74e19 src/vr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr.h Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,61 @@ +#ifndef VR_H_ +#define VR_H_ + +#define VR_OPT_DISPLAY_WIDTH "display-xres" +#define VR_OPT_DISPLAY_HEIGHT "display-yres" +#define VR_OPT_LEYE_XRES "left-eye-xres" +#define VR_OPT_LEYE_YRES "left-eye-yres" +#define VR_OPT_REYE_XRES "right-eye-xres" +#define VR_OPT_REYE_YRES "right-eye-yres" +#define VR_OPT_EYE_HEIGHT "eye-height" +#define VR_OPT_IPD "ipd" +#define VR_OPT_WIN_XOFFS "win-xoffset" +#define VR_OPT_WIN_YOFFS "win-yoffset" + +enum { + VR_EYE_LEFT, + VR_EYE_RIGHT +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int vr_init(void); +void vr_shutdown(void); + +int vr_module_count(void); +const char *vr_module_name(int idx); + +int vr_use_module(int idx); +int vr_use_module_named(const char *name); + +void vr_set_opti(const char *optname, int val); +void vr_set_optf(const char *optname, float val); +int vr_get_opti(const char *optname); +float vr_get_optf(const char *optname); + +int vr_view_translation(int eye, float *vec); +int vr_view_rotation(int eye, float *quat); + +/* returns non-zero if the active vr module provides this kind of matrix + * information, otherwise it returns zero, and sets mat to identity + */ +int vr_view_matrix(int eye, float *mat); +int vr_proj_matrix(int eye, float znear, float zfar, float *mat); + +void vr_begin(int eye); +void vr_end(void); +int vr_swap_buffers(void); + +/* set the output texture or separate textures for each eye */ +void vr_output_texture(unsigned int tex, float umin, float vmin, float umax, float vmax); +void vr_output_texture_eye(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax); + +void vr_recenter(void); + +#ifdef __cplusplus +} +#endif + +#endif /* VR_H_ */ diff -r 000000000000 -r ded3d0a74e19 src/vr_impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr_impl.h Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,44 @@ +#ifndef VR_IMPL_H_ +#define VR_IMPL_H_ + +#include "vr.h" +#include "opt.h" + +struct vr_module { + char *name; + + int (*init)(void); + void (*cleanup)(void); + + int (*set_option)(const char *opt, enum opt_type type, void *valp); + int (*get_option)(const char *opt, enum opt_type type, void *valp); + + void (*translation)(int eye, float *vec); + void (*rotation)(int eye, float *quat); + + void (*view_matrix)(int eye, float *mat); + void (*proj_matrix)(int eye, float znear, float zfar, float *mat); + + void (*begin)(int eye); + void (*end)(void); + int (*present)(void); + + void (*set_eye_texture)(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax); + + void (*recenter)(void); +}; + +void vr_init_modules(void); + +void vr_clear_modules(void); +void vr_register_module(struct vr_module *mod); + +int vr_get_num_modules(void); +struct vr_module *vr_get_module(int idx); + +void vr_activate_module(int idx); + +int vr_get_num_active_modules(void); +struct vr_module *vr_get_active_module(int idx); + +#endif /* VR_IMPL_H_ */ diff -r 000000000000 -r ded3d0a74e19 src/vr_libovr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr_libovr.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,308 @@ +#ifdef WIN32 +#define OVR_OS_WIN32 +#endif + +#include "vr_impl.h" + +#ifdef USE_LIBOVR +#include +#include +#include +#include "opt.h" + +#include +#include + +#define DISABLE_RETARDED_HEALTH_WARNING + +/* just dropping the prototype here to avoid including CAPI_HSWDisplay.h */ +OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enabled); + +static ovrHmd hmd; +static void *optdb; +static ovrEyeRenderDesc eye_render_desc[2]; +static ovrSizei eye_res[2]; +static ovrGLTexture eye_tex[2]; +static ovrFovPort eye_fov[2]; +static ovrPosef pose[2]; +static int deferred_init_done; + +static int init(void) +{ + int i, num_hmds; + + if(!ovr_Initialize()) { + return -1; + } + printf("initialized LibOVR %s\n", ovr_GetVersionString()); + + if(!(num_hmds = ovrHmd_Detect())) { + ovr_Shutdown(); + return -1; + } + printf("%d Oculus HMD(s) found\n", num_hmds); + + hmd = 0; + for(i=0; iManufacturer, h->ProductName); + + if(!hmd) { + hmd = h; + } else { + ovrHmd_Destroy(h); + } + } + + if(!hmd) { + fprintf(stderr, "failed to initialize any Oculus HMDs\n"); + return -1; + } + + ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0); + + eye_fov[0] = hmd->DefaultEyeFov[0]; + eye_fov[1] = hmd->DefaultEyeFov[1]; + + eye_res[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, eye_fov[0], 1.0); + eye_res[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, eye_fov[1], 1.0); + + /* create the options database */ + if((optdb = create_options())) { + set_option_int(optdb, VR_OPT_DISPLAY_WIDTH, hmd->Resolution.w); + set_option_int(optdb, VR_OPT_DISPLAY_HEIGHT, hmd->Resolution.h); + set_option_int(optdb, VR_OPT_LEYE_XRES, eye_res[0].w); + set_option_int(optdb, VR_OPT_LEYE_YRES, eye_res[0].h); + set_option_int(optdb, VR_OPT_REYE_XRES, eye_res[1].w); + set_option_int(optdb, VR_OPT_REYE_YRES, eye_res[1].h); + set_option_float(optdb, VR_OPT_EYE_HEIGHT, ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT)); + set_option_float(optdb, VR_OPT_IPD, ovrHmd_GetFloat(hmd, OVR_KEY_IPD, OVR_DEFAULT_IPD)); + set_option_int(optdb, VR_OPT_WIN_XOFFS, hmd->WindowsPos.x); + set_option_int(optdb, VR_OPT_WIN_YOFFS, hmd->WindowsPos.y); + } + + deferred_init_done = 0; + return 0; +} + +static void deferred_init(void) +{ + union ovrGLConfig glcfg; + unsigned int dcaps; + void *win = 0; + + deferred_init_done = 1; + + memset(&glcfg, 0, sizeof glcfg); + glcfg.OGL.Header.API = ovrRenderAPI_OpenGL; + glcfg.OGL.Header.RTSize = hmd->Resolution; + glcfg.OGL.Header.Multisample = 1; +#ifdef WIN32 + win = GetActiveWindow(); + /*glcfg.OGL.Window = win; + glcfg.OGL.DC = wglGetCurrentDC(); + assert(glcfg.OGL.Window); + assert(glcfg.OGL.DC);*/ +#endif + + if(!(hmd->HmdCaps & ovrHmdCap_ExtendDesktop)) { + ovrHmd_AttachToWindow(hmd, win, 0, 0); + printf("running in \"direct-to-rift\" mode\n"); + } else { + printf("running in \"extended desktop\" mode\n"); + } + ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); + + dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp | + ovrDistortionCap_Overdrive | ovrDistortionCap_NoRestore; + + if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, eye_fov, eye_render_desc)) { + fprintf(stderr, "failed to configure LibOVR distortion renderer\n"); + } + +#ifdef DISABLE_RETARDED_HEALTH_WARNING + ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); +#endif +} + +static void cleanup(void) +{ + if(hmd) { + ovrHmd_Destroy(hmd); + ovr_Shutdown(); + } +} + +static int set_option(const char *opt, enum opt_type type, void *valp) +{ + switch(type) { + case OTYPE_INT: + set_option_int(optdb, opt, *(int*)valp); + break; + + case OTYPE_FLOAT: + set_option_float(optdb, opt, *(float*)valp); + break; + } + return 0; +} + +static int get_option(const char *opt, enum opt_type type, void *valp) +{ + switch(type) { + case OTYPE_INT: + return get_option_int(optdb, opt, valp); + case OTYPE_FLOAT: + return get_option_float(optdb, opt, valp); + } + return -1; +} + +static int translation(int eye, float *vec) +{ + if(!hmd) { + vec[0] = vec[1] = vec[2] = 0; + return 0; + } + + pose[eye] = ovrHmd_GetEyePose(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right); + vec[0] = pose[eye].Position.x + eye_render_desc[eye].ViewAdjust.x; + vec[1] = pose[eye].Position.y + eye_render_desc[eye].ViewAdjust.y; + vec[2] = pose[eye].Position.z + eye_render_desc[eye].ViewAdjust.z; + + return 1; +} + +static int rotation(int eye, float *quat) +{ + if(!hmd) { + quat[0] = quat[1] = quat[2] = 0.0f; + quat[3] = 1.0f; + return 0; + } + + pose[eye] = ovrHmd_GetEyePose(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right); + quat[0] = pose[eye].Orientation.x; + quat[1] = pose[eye].Orientation.y; + quat[2] = pose[eye].Orientation.z; + quat[3] = pose[eye].Orientation.w; + return 1; +} + +static const float idmat[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + +static void proj_matrix(int eye, float znear, float zfar, float *mat) +{ + int i, j; + ovrMatrix4f vmat; + + if(!hmd) { + memcpy(mat, idmat, sizeof idmat); + return; + } + + vmat = ovrMatrix4f_Projection(eye_render_desc[eye].Fov, znear, zfar, 1); + + for(i=0; i<4; i++) { + for(j=0; j<4; j++) { + *mat++ = vmat.M[j][i]; + } + } +} + +static int new_frame = 1; + +static void begin(int eye) +{ + if(!hmd) return; + + if(!deferred_init_done) { + deferred_init(); + } + + if(new_frame) { + ovrHmd_BeginFrame(hmd, 0); + new_frame = 0; + } +} + +static int present(void) +{ + if(!hmd) return 0; + + ovrHmd_EndFrame(hmd, pose, &eye_tex[0].Texture); + new_frame = 1; + + return 1; +} + +static void set_eye_texture(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax) +{ + ovrSizei texsz; + ovrRecti rect; + + glBindTexture(GL_TEXTURE_2D, tex); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texsz.w); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texsz.h); + + rect.Pos.x = (int)(umin * texsz.w); + rect.Pos.y = (int)((vmin + 1.0 - vmax) * texsz.h); + rect.Size.w = (int)((umax - umin) * texsz.w); + rect.Size.h = (int)((vmax - vmin) * texsz.h); + + eye_tex[eye].OGL.Header.API = ovrRenderAPI_OpenGL; + eye_tex[eye].OGL.Header.TextureSize = texsz; + eye_tex[eye].OGL.Header.RenderViewport = rect; + eye_tex[eye].OGL.TexId = tex; +} + +static void recenter(void) +{ + if(hmd) { + ovrHmd_RecenterPose(hmd); + } +} + +struct vr_module *vr_module_libovr(void) +{ + static struct vr_module m; + + if(!m.init) { + m.name = "libovr"; + m.init = init; + m.cleanup = cleanup; + m.set_option = set_option; + m.get_option = get_option; + m.translation = translation; + m.rotation = rotation; + m.proj_matrix = proj_matrix; + m.begin = begin; + m.present = present; + m.set_eye_texture = set_eye_texture; + m.recenter = recenter; + } + return &m; +} + +#else /* no libovr */ + +static int init(void) +{ + return -1; +} + +struct vr_module *vr_module_libovr(void) +{ + static struct vr_module m; + + if(!m.init) { + m.name = "libovr"; + m.init = init; + } + return &m; +} + +#endif /* USE_LIBOVR */ diff -r 000000000000 -r ded3d0a74e19 src/vr_modules.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr_modules.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,94 @@ +/* XXX this might become partly auto-generated in the future */ +#include +#include +#include "vr_impl.h" + +struct vr_module *vr_module_libovr(void); +struct vr_module *vr_module_openhmd(void); +struct vr_module *vr_module_null(void); + +static struct vr_module *modules; +static int num_modules, modules_max_size; + +static int *active_modules; +static int num_act_modules, act_modules_max_size; + + +void vr_init_modules(void) +{ + struct vr_module *m; + + vr_clear_modules(); + + if((m = vr_module_libovr())) { + vr_register_module(m); + } + + if((m = vr_module_openhmd())) { + vr_register_module(m); + } + + if((m = vr_module_null())) { + vr_register_module(m); + } +} + +void vr_clear_modules(void) +{ + free(modules); + free(active_modules); + modules = 0; + num_modules = modules_max_size = 0; + active_modules = 0; + num_act_modules = act_modules_max_size = 0; +} + +void vr_register_module(struct vr_module *mod) +{ + if(num_modules >= modules_max_size) { + int newsz = modules_max_size ? modules_max_size * 2 : 2; + struct vr_module *newmods = realloc(modules, newsz * sizeof *newmods); + if(!newmods) { + fprintf(stderr, "failed to resize modules array up to %d\n", newsz); + return; + } + modules = newmods; + modules_max_size = newsz; + } + modules[num_modules++] = *mod; +} + +int vr_get_num_modules(void) +{ + return num_modules; +} + +struct vr_module *vr_get_module(int idx) +{ + return modules + idx; +} + +void vr_activate_module(int idx) +{ + if(num_act_modules >= act_modules_max_size) { + int newsz = act_modules_max_size ? act_modules_max_size * 2 : 2; + int *newact = realloc(active_modules, newsz * sizeof *newact); + if(!newact) { + fprintf(stderr, "failed to resize active modules array up to %d\n", newsz); + return; + } + active_modules = newact; + act_modules_max_size = newsz; + } + active_modules[num_act_modules++] = idx; +} + +int vr_get_num_active_modules(void) +{ + return num_act_modules; +} + +struct vr_module *vr_get_active_module(int idx) +{ + return modules + active_modules[idx]; +} diff -r 000000000000 -r ded3d0a74e19 src/vr_null.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr_null.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,85 @@ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#ifdef __APPLE__ +#include +#else +#include +#endif +#include "vr_impl.h" + +static unsigned int eye_tex[2]; +static float tex_umin[2], tex_umax[2]; +static float tex_vmin[2], tex_vmax[2]; + +static int init(void) +{ + return 0; +} + +static int present(void) +{ + int i; + + glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT); + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glDisable(GL_FOG); + glDisable(GL_CULL_FACE); + + glEnable(GL_TEXTURE_2D); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + for(i=0; i<2; i++) { + float x0 = i == 0 ? -1 : 0; + float x1 = i == 0 ? 0 : 1; + + glBindTexture(GL_TEXTURE_2D, eye_tex[i]); + + glBegin(GL_QUADS); + glTexCoord2f(tex_umin[i], tex_vmin[i]); + glVertex2f(x0, -1); + glTexCoord2f(tex_umax[i], tex_vmin[i]); + glVertex2f(x1, -1); + glTexCoord2f(tex_umax[i], tex_vmax[i]); + glVertex2f(x1, 1); + glTexCoord2f(tex_umin[i], tex_vmax[i]); + glVertex2f(x0, 1); + glEnd(); + } + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glPopAttrib(); + return 0; +} + +static void set_eye_texture(int eye, unsigned int tex, float umin, float vmin, float umax, float vmax) +{ + eye_tex[eye] = tex; + tex_umin[eye] = umin; + tex_umax[eye] = umax; + tex_vmin[eye] = vmin; + tex_vmax[eye] = vmax; +} + +struct vr_module *vr_module_null(void) +{ + static struct vr_module m; + + if(!m.init) { + m.name = "null"; + m.init = init; + m.set_eye_texture = set_eye_texture; + m.present = present; + } + return &m; +} diff -r 000000000000 -r ded3d0a74e19 src/vr_openhmd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr_openhmd.c Fri Aug 29 03:45:25 2014 +0300 @@ -0,0 +1,210 @@ +#include "vr_impl.h" + +#ifdef USE_OPENHMD +#include +#include +#include +#include "opt.h" + +/* a noble spirit embiggens the framebuffer to avoid aliasing in the middle */ +#define EMBIGGEN 1.5 + +static ohmd_context *ctx; +static ohmd_device *dev; +static void *optdb; +static int new_frame = 1; + +static int disp_width, disp_height; +static float ipd; + +static struct { + unsigned int id; + float umin, umax; + float vmin, vmax; +} eye_tex[2]; + + +static int init(void) +{ + int i, num_hmds; + + if(!(ctx = ohmd_ctx_create())) { + fprintf(stderr, "failed to create OpenHMD context\n"); + ohmd_ctx_destroy(ctx); + return -1; + } + if(!(num_hmds = ohmd_ctx_probe(ctx))) { + fprintf(stderr, "no HMDs detected\n"); + return -1; + } + + for(i=0; i