# HG changeset patch # User John Tsiombikas # Date 1408715716 -10800 # Node ID bd8202d6d28d828d52c2e388da328615d1fe614b # Parent 3c36bc28c6c283b2841957485daf7185e43ff10f some progress... diff -r 3c36bc28c6c2 -r bd8202d6d28d src/game.cc --- a/src/game.cc Thu Aug 21 01:08:03 2014 +0300 +++ b/src/game.cc Fri Aug 22 16:55:16 2014 +0300 @@ -4,11 +4,13 @@ #include "texture.h" #include "vr/vr.h" +static void game_render_eye(int eye); static void draw_scene(); static bool setup_rtarg(int x, int y); -static Texture *rtarg[2]; +static Texture *rtarg; static unsigned int fbo, rtarg_depth; +static int rtwidth, rtheight; static const float move_speed = 10.0f; @@ -20,6 +22,7 @@ bool game_init() { vr_init(); + vr_use_module_named("null"); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); @@ -45,8 +48,7 @@ if(fbo) { glDeleteFramebuffers(1, &fbo); glDeleteRenderbuffers(1, &rtarg_depth); - delete rtarg[0]; - delete rtarg[1]; + delete rtarg; } } @@ -83,22 +85,39 @@ cam.input_rotate(0, 0, roll); } -void game_render(int eye) +void game_render() { - vr_begin(eye <= 0 ? VR_EYE_LEFT : VR_EYE_RIGHT); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glClearColor(1, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, rtwidth / 2.0, rtheight); + vr_begin(VR_EYE_LEFT); + game_render_eye(-1); + vr_end(); + + glViewport(rtwidth / 2, 0, rtwidth / 2.0, rtheight); + vr_begin(VR_EYE_RIGHT); + game_render_eye(1); + vr_end(); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + vr_output_texture(rtarg->get_texture_id(), 0, 0, (float)rtwidth / (float)rtarg->get_width(), + (float)rtheight / (float)rtarg->get_height()); +} + +static void game_render_eye(int eye) +{ float mat[16]; Matrix4x4 view_matrix = cam.get_matrix().inverse(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); glLoadIdentity(); - if(eye == 0 || !vr_proj_matrix(eye < 0 ? 0 : 1, mat)) { + //if(eye == 0 || !vr_proj_matrix(eye < 0 ? 0 : 1, 0.5, 500.0, mat)) { gluPerspective(60.0, (float)fb_width / (float)fb_height, 0.5, 500.0); - } else { - glLoadTransposeMatrixf(mat); - } + /*} else { + glLoadMatrixf(mat); + }*/ glMatrixMode(GL_MODELVIEW); if(eye == 0 || !vr_view_matrix(eye < 0 ? 0 : 1, mat)) { @@ -109,8 +128,6 @@ glMultTransposeMatrixf(view_matrix[0]); draw_scene(); - - vr_end(); } void game_reshape(int x, int y) @@ -119,7 +136,20 @@ fb_width = x; fb_height = y; - setup_rtarg(x, y); + int lxres = vr_get_opti(VR_OPT_LEYE_XRES); + if(lxres) { + int lyres = vr_get_opti(VR_OPT_LEYE_YRES); + int rxres = vr_get_opti(VR_OPT_REYE_XRES); + int ryres = vr_get_opti(VR_OPT_REYE_YRES); + + rtwidth = lxres + rxres; + rtheight = lyres > ryres ? lyres : ryres; + } else { + rtwidth = x; + rtheight = y; + } + + setup_rtarg(rtwidth, rtheight); } void game_keyboard(int key, bool pressed, int x, int y) @@ -222,10 +252,7 @@ if(!fbo) { glGenFramebuffers(1, &fbo); glGenRenderbuffers(1, &rtarg_depth); - - for(int i=0; i<2; i++) { - rtarg[i] = new Texture; - } + rtarg = new Texture; } glBindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -234,17 +261,16 @@ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_width, tex_height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtarg_depth); - for(int i=0; i<2; i++) { - rtarg[i] = new Texture; - rtarg[i]->create2d(tex_width, tex_height); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, rtarg[i]->get_texture_id(), 0); - } + rtarg->create2d(tex_width, tex_height); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + rtarg->get_texture_id(), 0); if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { fprintf(stderr, "incomplete framebuffer!\n"); return false; } glBindFramebuffer(GL_FRAMEBUFFER, 0); + + printf("created render target %dx%d (texture: %dx%d)\n", x, y, tex_width, tex_height); return true; } diff -r 3c36bc28c6c2 -r bd8202d6d28d src/game.h --- a/src/game.h Thu Aug 21 01:08:03 2014 +0300 +++ b/src/game.h Fri Aug 22 16:55:16 2014 +0300 @@ -5,7 +5,7 @@ void game_cleanup(); void game_update(unsigned int msec); -void game_render(int eye); +void game_render(); void game_reshape(int x, int y); void game_keyboard(int key, bool pressed, int x, int y); diff -r 3c36bc28c6c2 -r bd8202d6d28d src/main.cc --- a/src/main.cc Thu Aug 21 01:08:03 2014 +0300 +++ b/src/main.cc Fri Aug 22 16:55:16 2014 +0300 @@ -50,6 +50,12 @@ if(!game_init()) { return false; } + + int win_xsz = vr_get_opti(VR_OPT_DISPLAY_WIDTH); + int win_ysz = vr_get_opti(VR_OPT_DISPLAY_HEIGHT); + if(win_xsz && win_ysz) { + glutReshapeWindow(win_xsz, win_ysz); + } return true; } @@ -63,7 +69,7 @@ unsigned int msec = glutGet(GLUT_ELAPSED_TIME); game_update(msec); - game_render(0); + game_render(); if(!vr_swap_buffers()) { glutSwapBuffers(); diff -r 3c36bc28c6c2 -r bd8202d6d28d src/texture.cc --- a/src/texture.cc Thu Aug 21 01:08:03 2014 +0300 +++ b/src/texture.cc Fri Aug 22 16:55:16 2014 +0300 @@ -12,6 +12,16 @@ destroy(); } +int Texture::get_width() const +{ + return img.get_width(); +} + +int Texture::get_height() const +{ + return img.get_height(); +} + void Texture::create2d(int xsz, int ysz) { destroy(); diff -r 3c36bc28c6c2 -r bd8202d6d28d src/texture.h --- a/src/texture.h Thu Aug 21 01:08:03 2014 +0300 +++ b/src/texture.h Fri Aug 22 16:55:16 2014 +0300 @@ -13,6 +13,9 @@ Texture(); ~Texture(); + int get_width() const; + int get_height() const; + void create2d(int xsz, int ysz); void destroy(); diff -r 3c36bc28c6c2 -r bd8202d6d28d src/vr/opt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr/opt.c Fri Aug 22 16:55:16 2014 +0300 @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include "opt.h" +#include "rbtree.h" + +static void opt_del_func(void *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); + } + printf("stored %s -> %p\n", key, opt); +} + +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); + } + printf("stored %s -> %p\n", key, opt); +} + +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; + } + printf("got %s -> %p\n", key, opt); + *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; + } + printf("got %s -> %p\n", key, opt); + *val = opt->fval; + return 0; +} diff -r 3c36bc28c6c2 -r bd8202d6d28d src/vr/opt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr/opt.h Fri Aug 22 16:55:16 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_ */ \ No newline at end of file diff -r 3c36bc28c6c2 -r bd8202d6d28d src/vr/rbtree.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr/rbtree.c Fri Aug 22 16:55:16 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 3c36bc28c6c2 -r bd8202d6d28d src/vr/rbtree.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vr/rbtree.h Fri Aug 22 16:55:16 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 3c36bc28c6c2 -r bd8202d6d28d src/vr/vr.c --- a/src/vr/vr.c Thu Aug 21 01:08:03 2014 +0300 +++ b/src/vr/vr.c Fri Aug 22 16:55:16 2014 +0300 @@ -88,20 +88,72 @@ 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 0; + } + vec[0] = vec[1] = vec[2] = 0.0f; + return -1; +} + +int vr_view_rotation(int eye, float *quat) +{ + if(vrm && vrm->rotation) { + vrm->rotation(eye, quat); + return 0; + } + quat[0] = quat[1] = quat[2] = 0.0f; + quat[3] = 1.0f; + return -1; +} + int vr_view_matrix(int eye, float *mat) { - if(vrm && vrm->view_matrix) { - vrm->view_matrix(eye, mat); - return 1; - } - memcpy(mat, idmat, sizeof idmat); + /* TODO combine vr_view_translation and vr_view_rotation */ return 0; } -int vr_proj_matrix(int eye, float *mat) +int vr_proj_matrix(int eye, float znear, float zfar, float *mat) { if(vrm && vrm->proj_matrix) { - vrm->proj_matrix(eye, mat); + vrm->proj_matrix(eye, znear, zfar, mat); return 1; } memcpy(mat, idmat, sizeof idmat); @@ -130,3 +182,25 @@ } 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(); + } +} \ No newline at end of file diff -r 3c36bc28c6c2 -r bd8202d6d28d src/vr/vr.h --- a/src/vr/vr.h Thu Aug 21 01:08:03 2014 +0300 +++ b/src/vr/vr.h Fri Aug 22 16:55:16 2014 +0300 @@ -1,6 +1,15 @@ #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" + enum { VR_EYE_LEFT, VR_EYE_RIGHT @@ -19,22 +28,30 @@ int vr_use_module(int idx); int vr_use_module_named(const char *name); -/* if we're using a vr module which requires a specific output resolution, vr_display_size - * returns non-zero, and writes the size through the xsz/ysz pointers. Otherwise returns 0 - */ -int vr_display_size(int *xsz, int *ysz); -int vr_eye_texture_size(int eye, int *xsz, int *ysz); +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 *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 diff -r 3c36bc28c6c2 -r bd8202d6d28d src/vr/vr_impl.h --- a/src/vr/vr_impl.h Thu Aug 21 01:08:03 2014 +0300 +++ b/src/vr/vr_impl.h Fri Aug 22 16:55:16 2014 +0300 @@ -1,18 +1,30 @@ #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); - void (*view_matrix)(int eye, float *mat); - void (*proj_matrix)(int eye, float *mat); + 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 (*proj_matrix)(int eye, float znear, float zfar, float *mat); void (*begin)(int eye); void (*end)(void); void (*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); diff -r 3c36bc28c6c2 -r bd8202d6d28d src/vr/vr_libovr.c --- a/src/vr/vr_libovr.c Thu Aug 21 01:08:03 2014 +0300 +++ b/src/vr/vr_libovr.c Fri Aug 22 16:55:16 2014 +0300 @@ -2,20 +2,32 @@ #define OVR_OS_WIN32 #endif -#include -#include #include "vr_impl.h" #ifdef USE_LIBOVR +#include +#include +#include +#include "opt.h" + #include #include +/* 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; - union ovrGLConfig glcfg; if(!ovr_Initialize()) { return -1; @@ -48,48 +60,185 @@ return -1; } + 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)); + } + + deferred_init_done = 0; + return 0; +} + +static void deferred_init(void) +{ + union ovrGLConfig glcfg; + unsigned int dcaps; + + deferred_init_done = 1; + ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0); glcfg.OGL.Header.API = ovrRenderAPI_OpenGL; glcfg.OGL.Header.RTSize = hmd->Resolution; glcfg.OGL.Header.Multisample = 0; - glcfg.OGL.Window = 0; - glcfg.OGL.DC = 0; +#ifdef WIN32 + glcfg.OGL.Window = GetActiveWindow(); + glcfg.OGL.DC = wglGetCurrentDC(); + ovrHmd_AttachToWindow(hmd, glcfg.OGL.Window, 0, 0); + assert(glcfg.OGL.Window); +#endif - if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, eyes_fov, eye_rend_desc))) { + dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp | + ovrDistortionCap_Overdrive | ovrDistortionCap_FlipInput; + + if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, eye_fov, eye_render_desc)) { fprintf(stderr, "failed to configure LibOVR distortion renderer\n"); - return -1; } + + ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); } static void cleanup(void) { if(hmd) { ovrHmd_Destroy(hmd); - ovr_Destroy(); + ovr_Shutdown(); } } -static void view_matrix(int eye, float *mat) +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 void proj_matrix(int eye, float *mat) +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 -1; + } + + pose[eye] = ovrHmd_GetEyePose(hmd, eye == VR_EYE_LEFT ? ovrEye_Left : ovrEye_Right); + vec[0] = pose[eye].Position.x; + vec[1] = pose[eye].Position.y; + vec[2] = pose[eye].Position.z; + return 0; +} + +static int rotation(int eye, float *quat) +{ + if(!hmd) { + quat[0] = quat[1] = quat[2] = 0.0f; + quat[3] = 1.0f; + return -1; + } + + 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 0; +} + +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) +{ + ovrMatrix4f vmat; + + if(!hmd) { + memcpy(mat, idmat, sizeof idmat); + return; + } + + vmat = ovrMatrix4f_Projection(eye_render_desc[eye].Fov, znear, zfar, 1); + memcpy(mat, vmat.M[0], 16 * sizeof(float)); +} + +static int new_frame = 1; + static void begin(int eye) { -} + if(!hmd) return; -static void end(void) -{ + if(!deferred_init_done) { + deferred_init(); + } + + if(new_frame) { + ovrHmd_BeginFrame(hmd, 0); + new_frame = 0; + } } static void present(void) { + if(!hmd) return; + + ovrHmd_EndFrame(hmd, pose, &eye_tex[0].Texture); + new_frame = 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 * 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) { @@ -99,11 +248,15 @@ m.name = "libovr"; m.init = init; m.cleanup = cleanup; - m.view_matrix = view_matrix; + 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.end = end; m.present = present; + m.set_eye_texture = set_eye_texture; + m.recenter = recenter; } return &m; } diff -r 3c36bc28c6c2 -r bd8202d6d28d src/vr/vr_null.c --- a/src/vr/vr_null.c Thu Aug 21 01:08:03 2014 +0300 +++ b/src/vr/vr_null.c Fri Aug 22 16:55:16 2014 +0300 @@ -11,11 +11,71 @@ #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 void 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(); + +#ifdef WIN32 + SwapBuffers(wglGetCurrentDC()); +#endif +} + +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; @@ -23,6 +83,8 @@ if(!m.init) { m.name = "null"; m.init = init; + m.set_eye_texture = set_eye_texture; + m.present = present; } return &m; } diff -r 3c36bc28c6c2 -r bd8202d6d28d vrchess.vcxproj --- a/vrchess.vcxproj Thu Aug 21 01:08:03 2014 +0300 +++ b/vrchess.vcxproj Fri Aug 22 16:55:16 2014 +0300 @@ -51,13 +51,14 @@ Level3 Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);USE_LIBOVR 4996;4244;4305 + $(SolutionDir)\src Console true - opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovrd.lib;%(AdditionalDependencies) + opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovrd.lib;ws2_32.lib;%(AdditionalDependencies) @@ -68,15 +69,16 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);USE_LIBOVR 4996;4244;4305 + $(SolutionDir)\src Console true true true - opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovr.lib;%(AdditionalDependencies) + opengl32.lib;glut32.lib;glew32.lib;libvmath.lib;libimago2.lib;jpeglib.lib;libpng.lib;zlib.lib;libovr.lib;ws2_32.lib;%(AdditionalDependencies) @@ -87,6 +89,8 @@ + + @@ -99,6 +103,8 @@ + + diff -r 3c36bc28c6c2 -r bd8202d6d28d vrchess.vcxproj.filters --- a/vrchess.vcxproj.filters Thu Aug 21 01:08:03 2014 +0300 +++ b/vrchess.vcxproj.filters Fri Aug 22 16:55:16 2014 +0300 @@ -43,6 +43,12 @@ src\vr + + src\vr + + + src\vr + @@ -69,5 +75,11 @@ src\vr + + src\vr + + + src\vr + \ No newline at end of file