VR mode
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 14 Nov 2016 17:50:56 +0000 (19:50 +0200)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 14 Nov 2016 17:50:56 +0000 (19:50 +0200)
Makefile
src/app.cc
src/app.h
src/main.cc
src/opt.cc [new file with mode: 0644]
src/opt.h [new file with mode: 0644]

index e43c5ac..85c4046 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ warn = -pedantic -Wall
 CFLAGS = $(warn) $(opt) $(dbg) $(incpath)
 CXXFLAGS = -std=c++11 $(warn) $(opt) $(dbg) $(incpath)
 LDFLAGS = $(libpath) $(libgl_$(sys)) -lm -lgmath -lvmath -limago -lresman \
-                 -lpthread -lassimp -ltreestore -ldrawtext `pkg-config --libs sdl2`
+                 -lpthread -lassimp -ltreestore -ldrawtext -loptcfg -lgoatvr `pkg-config --libs sdl2`
 
 sys = $(shell uname -s)
 libgl_Linux = -lGL -lGLU -lGLEW
index 065e581..d3b5657 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <assert.h>
+#include <goatvr.h>
 #include "app.h"
 #include "opengl.h"
 #include "sdr.h"
 #include "metascene.h"
 #include "datamap.h"
 #include "ui.h"
+#include "opt.h"
+
+#define NEAR_CLIP      5.0
+#define FAR_CLIP       10000.0
 
 static void draw_scene();
 
@@ -27,11 +32,13 @@ static float user_eye_height = 165;
 static float walk_speed = 300.0f;
 static bool show_walk_mesh, noclip = false;
 
+static bool have_headtracking, should_swap;
+
 static int prev_mx, prev_my;
 static bool bnstate[8];
 static bool keystate[256];
 
-static Mat4 view_matrix;
+static Mat4 view_matrix, mouse_view_matrix, proj_matrix;
 static TextureSet texman;
 static Scene *scn;
 static unsigned int sdr;
@@ -39,8 +46,29 @@ static unsigned int sdr;
 static long prev_msec;
 
 
-bool app_init()
+bool app_init(int argc, char **argv)
 {
+       if(!init_options(argc, argv, "demo.conf")) {
+               return false;
+       }
+       app_resize(opt.width, opt.height);
+       app_fullscreen(opt.fullscreen);
+
+       if(opt.vr) {
+               if(goatvr_init() == -1) {
+                       return false;
+               }
+               goatvr_set_origin_mode(GOATVR_HEAD);
+               goatvr_set_units_scale(100.0f);
+
+               goatvr_startvr();
+               should_swap = goatvr_should_swap() != 0;
+               user_eye_height = goatvr_get_eye_height();
+               have_headtracking = goatvr_have_headtracking();
+
+               goatvr_recenter();
+       }
+
        glEnable(GL_FRAMEBUFFER_SRGB);
        glEnable(GL_MULTISAMPLE);
        glEnable(GL_DEPTH_TEST);
@@ -53,6 +81,8 @@ bool app_init()
        float ambient[] = {0.0, 0.0, 0.0, 0.0};
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
 
+       glClearColor(0.2, 0.2, 0.2, 1.0);
+
        scn = new Scene(&texman);
        if(!load_scene(scn, "data/museum.scene")) {
                return false;
@@ -76,11 +106,19 @@ bool app_init()
        set_uniform_int(sdr, "lightmap", 1);
 
        glUseProgram(0);
+
+       if(opt.vr || opt.fullscreen) {
+               app_grab_mouse(true);
+       }
        return true;
 }
 
 void app_cleanup()
 {
+       app_grab_mouse(false);
+       if(opt.vr) {
+               goatvr_shutdown();
+       }
        texman.clear();
 }
 
@@ -160,6 +198,15 @@ static void update(float dt)
                }
                floor_y = cam_pos.y - user_eye_height;
        }
+
+       // calculate mouselook view matrix
+       mouse_view_matrix = Mat4::identity;
+       mouse_view_matrix.pre_translate(0, 0, -cam_dist);
+       if(!have_headtracking) {
+               mouse_view_matrix.pre_rotate_x(deg_to_rad(cam_phi));
+       }
+       mouse_view_matrix.pre_rotate_y(deg_to_rad(cam_theta));
+       mouse_view_matrix.pre_translate(-cam_pos.x, -cam_pos.y, -cam_pos.z);
 }
 
 static void set_light(int idx, const Vec3 &pos, const Vec3 &color)
@@ -179,34 +226,59 @@ void app_display()
        float dt = (float)(time_msec - prev_msec) / 1000.0f;
        prev_msec = time_msec;
 
-       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+       update(dt);
 
-       view_matrix = Mat4::identity;
-       view_matrix.pre_translate(0, 0, -cam_dist);
-       view_matrix.pre_rotate(deg_to_rad(cam_phi), 1, 0, 0);
-       view_matrix.pre_rotate(deg_to_rad(cam_theta), 0, 1, 0);
-       view_matrix.pre_translate(-cam_pos.x, -cam_pos.y, -cam_pos.z);
+       if(opt.vr) {
+               // VR mode
+               goatvr_draw_start();
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-       glMatrixMode(GL_MODELVIEW);
-       glLoadMatrixf(view_matrix[0]);
+               for(int i=0; i<2; i++) {
+                       // for each eye
+                       goatvr_draw_eye(i);
 
-       static const Vec3 lpos[] = { Vec3(-50, 75, 100), Vec3(100, 0, 30), Vec3(-10, -10, 60) };
-       set_light(0, lpos[0], Vec3(1.0, 0.8, 0.7) * 0.8);
-       set_light(1, lpos[1], Vec3(0.6, 0.7, 1.0) * 0.6);
-       set_light(2, lpos[2], Vec3(0.8, 1.0, 0.8) * 0.3);
+                       proj_matrix = goatvr_projection_matrix(i, NEAR_CLIP, FAR_CLIP);
+                       glMatrixMode(GL_PROJECTION);
+                       glLoadMatrixf(proj_matrix[0]);
 
-       update(dt);
+                       view_matrix = mouse_view_matrix * Mat4(goatvr_view_matrix(i));
+                       glMatrixMode(GL_MODELVIEW);
+                       glLoadMatrixf(view_matrix[0]);
 
-       draw_scene();
-       draw_ui();
+                       draw_scene();
+               }
+               goatvr_draw_done();
+
+               if(should_swap) {
+                       app_swap_buffers();
+               }
+
+       } else {
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+               proj_matrix.perspective(deg_to_rad(50.0), win_aspect, NEAR_CLIP, FAR_CLIP);
+               glMatrixMode(GL_PROJECTION);
+               glLoadMatrixf(proj_matrix[0]);
+
+               view_matrix = mouse_view_matrix;
+               glMatrixMode(GL_MODELVIEW);
+               glLoadMatrixf(view_matrix[0]);
 
-       app_swap_buffers();
+               draw_scene();
+
+               app_swap_buffers();
+       }
        assert(glGetError() == GL_NO_ERROR);
 }
 
 
 static void draw_scene()
 {
+       static const Vec3 lpos[] = { Vec3(-50, 75, 100), Vec3(100, 0, 30), Vec3(-10, -10, 60) };
+       set_light(0, lpos[0], Vec3(1.0, 0.8, 0.7) * 0.8);
+       set_light(1, lpos[1], Vec3(0.6, 0.7, 1.0) * 0.6);
+       set_light(2, lpos[2], Vec3(0.8, 1.0, 0.8) * 0.3);
+
        glUseProgram(sdr);
        scn->draw();
        glUseProgram(0);
@@ -228,16 +300,15 @@ static void draw_scene()
 
                glPopAttrib();
        }
+
+       draw_ui();
 }
 
 
 void app_reshape(int x, int y)
 {
        glViewport(0, 0, x, y);
-
-       glMatrixMode(GL_PROJECTION);
-       glLoadIdentity();
-       gluPerspective(50.0, (float)x / (float)y, 1.0, 10000.0);
+       goatvr_set_fb_size(x, y, 1.0f);
 }
 
 void app_keyboard(int key, bool pressed)
index 2867309..02db8db 100644 (file)
--- a/src/app.h
+++ b/src/app.h
@@ -12,7 +12,7 @@ enum {
        MOD_CTRL        = 4
 };
 
-bool app_init();
+bool app_init(int argc, char **argv);
 void app_cleanup();
 
 void app_display();
index f21c406..01c9d12 100644 (file)
@@ -5,7 +5,7 @@
 #include <SDL2/SDL.h>
 #include "app.h"
 
-static bool init();
+static bool init(int argc, char **argv);
 static void process_event(SDL_Event *ev);
 static void proc_modkeys();
 
@@ -51,7 +51,7 @@ int main(int argc, char **argv)
        SDL_GL_GetDrawableSize(win, &win_width, &win_height);
        win_aspect = (float)win_width / (float)win_height;
 
-       if(!init()) {
+       if(!init(argc, argv)) {
                SDL_Quit();
                return 1;
        }
@@ -113,9 +113,8 @@ bool app_is_fullscreen()
 
 void app_grab_mouse(bool grab)
 {
-       /*SDL_SetWindowGrab(win, grab ? SDL_TRUE : SDL_FALSE);
+       SDL_SetWindowGrab(win, grab ? SDL_TRUE : SDL_FALSE);
        SDL_ShowCursor(grab ? 1 : 0);
-       */
        SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE);
        mouse_grabbed = grab;
 }
@@ -131,11 +130,11 @@ bool app_is_mouse_grabbed()
 }
 
 
-static bool init()
+static bool init(int argc, char **argv)
 {
        glewInit();
 
-       if(!app_init()) {
+       if(!app_init(argc, argv)) {
                return false;
        }
 
diff --git a/src/opt.cc b/src/opt.cc
new file mode 100644 (file)
index 0000000..9226785
--- /dev/null
@@ -0,0 +1,104 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <optcfg.h>
+#include "opt.h"
+
+Options opt;
+
+Options def_opt = {
+       1280, 800,
+       false,  // vr
+       false   // fullscreen
+};
+
+enum {
+       OPT_SIZE,
+       OPT_VR,
+       OPT_SRGB,
+       OPT_FULLSCREEN,
+       OPT_WINDOWED,
+       OPT_HELP
+};
+
+static optcfg_option options[] = {
+       // short, long, id, desc
+       {'s', "size", OPT_SIZE, "window size (WxH)"},
+       {0, "vr", OPT_VR, "enable VR mode"},
+       {'f', "fullscreen", OPT_FULLSCREEN, "run in fullscreen mode"},
+       {'w', "windowed", OPT_WINDOWED, "run in windowed mode"},
+       {'h', "help", OPT_HELP, "print usage and exit"},
+       OPTCFG_OPTIONS_END
+};
+
+static int opt_handler(optcfg *oc, int opt, void *cls);
+static int arg_handler(optcfg *oc, const char *arg, void *cls);
+
+bool init_options(int argc, char **argv, const char *cfgfile)
+{
+       // default options
+       opt = def_opt;
+
+       optcfg *oc = optcfg_init(options);
+       optcfg_set_opt_callback(oc, opt_handler, 0);
+       optcfg_set_arg_callback(oc, arg_handler, 0);
+
+       if(cfgfile) {
+               optcfg_parse_config_file(oc, cfgfile);
+       }
+
+       if(argv && optcfg_parse_args(oc, argc, argv) == -1) {
+               fprintf(stderr, "invalid option\n");
+               optcfg_destroy(oc);
+               return false;
+       }
+
+       optcfg_destroy(oc);
+       return true;
+}
+
+static bool is_enabled(optcfg *oc)
+{
+       int res;
+       optcfg_enabled_value(oc, &res);
+       return res != 0;
+}
+
+static int opt_handler(optcfg *oc, int optid, void *cls)
+{
+       switch(optid) {
+       case OPT_SIZE:
+               {
+                       char *valstr = optcfg_next_value(oc);
+                       if(!valstr || sscanf(valstr, "%dx%d", &opt.width, &opt.height) != 2) {
+                               fprintf(stderr, "size must be in the form: WIDTHxHEIGHT\n");
+                               return -1;
+                       }
+               }
+               break;
+
+       case OPT_VR:
+               opt.vr = is_enabled(oc);
+               break;
+
+       case OPT_FULLSCREEN:
+               opt.fullscreen = is_enabled(oc);
+               break;
+
+       case OPT_WINDOWED:
+               opt.fullscreen = !is_enabled(oc);
+               break;
+
+       case OPT_HELP:
+               printf("Usage: vrfileman [options]\nOptions:\n");
+               optcfg_print_options(oc);
+               exit(0);
+       }
+       return 0;
+}
+
+static int arg_handler(optcfg *oc, const char *arg, void *cls)
+{
+       fprintf(stderr, "unexpected argument: %s\n", arg);
+       return -1;
+}
diff --git a/src/opt.h b/src/opt.h
new file mode 100644 (file)
index 0000000..176dd61
--- /dev/null
+++ b/src/opt.h
@@ -0,0 +1,14 @@
+#ifndef OPT_H_
+#define OPT_H_
+
+struct Options {
+       int width, height;
+       bool vr;
+       bool fullscreen;
+};
+
+extern Options opt, def_opt;
+
+bool init_options(int argc, char **argv, const char *cfgfile);
+
+#endif // OPT_H_