6 #include "gmath/gmath.h"
17 #define LASER_TIMEOUT 2000
18 #define PTIME_INVAL -LASER_TIMEOUT
20 static void draw_scene();
21 static void draw_laser();
23 int win_width, win_height;
27 Mat4 view_matrix, mouse_view_matrix, proj_matrix;
29 float cam_height = 1.65;
32 static float mtheta, mphi;
33 static long last_pointer_time = PTIME_INVAL;
34 static float laser_alpha;
36 static float cam_theta, cam_phi = 15;
37 static bool should_swap;
39 static bool bnstate[16];
40 static int mouse_x, mouse_y;
42 static float fov = 60.0;
44 static bool have_headtracking;
46 static RenderTarget *rtarg;
47 static bool rtarg_valid;
48 static unsigned int post_sdr;
51 bool app_init(int argc, char **argv)
53 if(!init_options(argc, argv, "vrfileman.conf")) {
56 app_resize(opt.width, opt.height);
57 app_fullscreen(opt.fullscreen);
59 if(init_opengl() == -1) {
63 glEnable(GL_MULTISAMPLE);
66 glGetIntegerv(GL_SAMPLES, &aasamples);
67 printf("got %d samples per pixel\n", aasamples);
69 printf("Max anisotropy: %d\n", glcaps.max_aniso);
71 glEnable(GL_CULL_FACE);
72 glEnable(GL_DEPTH_TEST);
74 if(opt.srgb && GLEW_ARB_framebuffer_sRGB) {
75 printf("enabling sRGB framebuffer\n");
76 glEnable(GL_FRAMEBUFFER_SRGB);
79 rtarg = new RenderTarget;
80 rtarg->create(GL_RGB16F);
83 if(goatvr_init() == -1) {
86 goatvr_set_origin_mode(GOATVR_HEAD);
89 should_swap = goatvr_should_swap() != 0;
90 cam_height = goatvr_get_eye_height();
91 have_headtracking = goatvr_have_headtracking();
94 RenderTarget::default_fbo = goatvr_get_fbo();
98 add_shader_header(GL_FRAGMENT_SHADER, "#define set_pixel set_pixel_linear");
100 add_shader_header(GL_FRAGMENT_SHADER, "#define set_pixel set_pixel_srgb");
102 if(!(post_sdr = create_program_load("sdr/post.v.glsl", "sdr/post.p.glsl"))) {
105 clear_shader_header(0);
107 Mesh::use_custom_sdr_attr = false;
109 if(!init_backdrop()) {
113 if(!init_fs(opt.path)) {
117 if(opt.vr || opt.fullscreen) {
118 app_grab_mouse(true);
125 app_grab_mouse(false);
130 free_program(post_sdr);
137 rtarg->resize(win_width, win_height);
140 /* calculate the mouselook view matrix */
141 mouse_view_matrix = Mat4::identity;
142 if(!have_headtracking) {
143 mouse_view_matrix.pre_rotate_x(deg_to_rad(cam_phi));
145 mouse_view_matrix.pre_rotate_y(deg_to_rad(cam_theta));
146 mouse_view_matrix.pre_translate(0, -cam_height, 0);
148 long interval = time_msec - last_pointer_time;
149 if(interval < LASER_TIMEOUT) {
152 if(have_headtracking) {
153 target.x = sin(deg_to_rad(mtheta)) * cos(deg_to_rad(mphi)) * 200.0;
154 target.y = sin(deg_to_rad(mphi)) * 200.0;
155 target.z = -cos(deg_to_rad(mtheta)) * cos(deg_to_rad(mphi)) * 200.0;
157 mray.origin = inverse(view_matrix) * Vec3(0.2, -0.4, 0.0);
159 /* pick on a distant sphere to find where the mouse is pointing to
160 * and use that as the other end of the mouse ray
162 float px = 2.0 * (float)mouse_x / win_width - 1.0;
163 float py = 1.0 - (2.0 * (float)mouse_y / win_height);
165 Mat4 mvp_inv = inverse(mouse_view_matrix * proj_matrix);
166 Vec4 vfar = mvp_inv * Vec4(px, py, 1, 1);
168 target = vfar.xyz() / vfar.w;
170 mray.origin = Vec3(0, cam_height, 0);
173 mray.dir = target - mray.origin;
175 laser_alpha = 1.0 - std::max(4.0f * interval / LASER_TIMEOUT - 3.0f, 0.0f);
188 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
190 for(int i=0; i<2; i++) {
193 proj_matrix = goatvr_projection_matrix(i, 0.1, 200.0);
194 glMatrixMode(GL_PROJECTION);
195 glLoadMatrixf(proj_matrix[0]);
197 view_matrix = mouse_view_matrix * Mat4(goatvr_view_matrix(i));
199 glMatrixMode(GL_MODELVIEW);
200 glLoadMatrixf(view_matrix[0]);
209 app_redraw(); // in VR mode, force continuous redraw
212 // regular monoscopic mode
213 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
215 proj_matrix.perspective(deg_to_rad(fov), win_aspect, 0.1, 200.0);
216 glMatrixMode(GL_PROJECTION);
217 glLoadMatrixf(proj_matrix[0]);
219 view_matrix = mouse_view_matrix;
221 glMatrixMode(GL_MODELVIEW);
222 glLoadMatrixf(view_matrix[0]);
227 app_redraw(); // since we added animation we need to redisplay even in non-VR mode
229 assert(glGetError() == GL_NO_ERROR);
232 static void draw_scene()
235 set_render_target(rtarg);
236 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
241 if(laser_alpha > 0.0) {
246 set_render_target(0);
248 glPushAttrib(GL_ENABLE_BIT);
249 glDisable(GL_DEPTH_TEST);
251 glUseProgram(post_sdr);
252 set_uniform_matrix4(post_sdr, "texmat", rtarg->get_texture_matrix()[0]);
254 bind_texture(rtarg->get_texture());
274 static void draw_laser()
276 glPushAttrib(GL_ENABLE_BIT);
278 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
285 glColor4f(1.0, 0.3, 0.2, laser_alpha);
286 glVertex3f(mray.origin.x, mray.origin.y, mray.origin.z);
287 Vec3 end = mray.origin + mray.dir;
288 glVertex3f(end.x, end.y, end.z);
296 void app_reshape(int x, int y)
298 glViewport(0, 0, x, y);
302 goatvr_set_fb_size(x, y, 1.0);
306 void app_keyboard(int key, bool pressed)
315 if(!opt.vr || should_swap) {
316 /* we take the need to swap as a signal that our window is not managed
317 * by some VR compositor, and therefore it's safe to fullscreen without
318 * upsetting the VR rendering output
320 opt.fullscreen = !opt.fullscreen;
321 app_fullscreen(opt.fullscreen);
333 if(fov > 160.0) fov = 160.0;
338 if(fov < 0.0) fov = 0.0;
342 app_toggle_grab_mouse();
349 void app_mouse_button(int bn, bool pressed, int x, int y)
351 bnstate[bn] = pressed;
356 void app_mouse_motion(int x, int y)
358 int dx = x - mouse_x;
359 int dy = y - mouse_y;
361 app_mouse_delta(dx, dy);
367 template <typename T>
368 static T clamp(T x, T a, T b)
370 return x < a ? a : (b < x ? b : x);
373 void app_mouse_delta(int dx, int dy)
375 if(!dx && !dy) return;
377 mouse_x = clamp(mouse_x + dx, 0, win_width);
378 mouse_y = clamp(mouse_y + dy, 0, win_height);
381 cam_theta += dx * 0.5;
382 cam_phi = clamp(cam_phi + dy * 0.5f, -90.0f, 90.0f);
385 last_pointer_time = PTIME_INVAL;
389 mphi = clamp(mphi - dy * 0.05f, -90.0f, 90.0f);
391 last_pointer_time = time_msec;