f0757618ebcbacef0660cd8ec54acdc344778489
[vrfileman] / src / app.cc
1 #include <stdio.h>
2 #include <assert.h>
3 #include "opengl.h"
4 #include "app.h"
5 #include "gmath/gmath.h"
6 #include "mesh.h"
7 #include "meshgen.h"
8 #include "backdrop.h"
9 #include "goatvr.h"
10 #include "opt.h"
11 #include "fs.h"
12 #include "rtarg.h"
13 #include "texture.h"
14 #include "sdr.h"
15
16 static void draw_scene();
17
18 int win_width, win_height;
19 float win_aspect;
20 long time_msec;
21 double time_sec;
22 Mat4 view_matrix;
23
24 float cam_height = 1.65;
25
26 static float cam_theta, cam_phi;
27 static bool should_swap;
28
29 static bool bnstate[16];
30 static int prev_x, prev_y;
31
32 static float fov = 60.0;
33
34 static RenderTarget *rtarg;
35 static bool rtarg_valid;
36 static unsigned int post_sdr;
37
38
39 bool app_init(int argc, char **argv)
40 {
41         if(!init_options(argc, argv, "vrfileman.conf")) {
42                 return false;
43         }
44         app_resize(opt.width, opt.height);
45         app_fullscreen(opt.fullscreen);
46
47         if(init_opengl() == -1) {
48                 return false;
49         }
50
51         glEnable(GL_MULTISAMPLE);
52
53         int aasamples = 0;
54         glGetIntegerv(GL_SAMPLES, &aasamples);
55         printf("got %d samples per pixel\n", aasamples);
56
57         printf("Max anisotropy: %d\n", glcaps.max_aniso);
58
59         glEnable(GL_CULL_FACE);
60         glEnable(GL_DEPTH_TEST);
61
62         if(opt.srgb && GLEW_ARB_framebuffer_sRGB) {
63                 printf("enabling sRGB framebuffer\n");
64                 glEnable(GL_FRAMEBUFFER_SRGB);
65         }
66
67         rtarg = new RenderTarget;
68         rtarg->create(GL_RGB16F);
69
70         if(opt.vr) {
71                 if(goatvr_init() == -1) {
72                         return false;
73                 }
74                 goatvr_set_origin_mode(GOATVR_HEAD);
75
76                 goatvr_startvr();
77                 should_swap = goatvr_should_swap() != 0;
78                 cam_height = goatvr_get_eye_height();
79
80                 RenderTarget::default_fbo = goatvr_get_fbo();
81         }
82
83         if(opt.srgb) {
84                 add_shader_header(GL_FRAGMENT_SHADER, "#define set_pixel set_pixel_linear");
85         } else {
86                 add_shader_header(GL_FRAGMENT_SHADER, "#define set_pixel set_pixel_srgb");
87         }
88         if(!(post_sdr = create_program_load("sdr/post.v.glsl", "sdr/post.p.glsl"))) {
89                 return false;
90         }
91         clear_shader_header(0);
92
93         Mesh::use_custom_sdr_attr = false;
94
95         if(!init_backdrop()) {
96                 return false;
97         }
98
99         if(!init_fs(opt.path)) {
100                 return false;
101         }
102
103         return true;
104 }
105
106 void app_cleanup()
107 {
108         if(opt.vr) {
109                 goatvr_shutdown();
110         }
111         delete rtarg;
112         free_program(post_sdr);
113         cleanup_backdrop();
114 }
115
116 static void update()
117 {
118         if(!rtarg_valid) {
119                 rtarg->resize(win_width, win_height);
120         }
121 }
122
123 void app_draw()
124 {
125         update();
126
127         if(opt.vr) {
128                 // VR mode
129                 goatvr_draw_start();
130                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
131
132                 for(int i=0; i<2; i++) {
133                         goatvr_draw_eye(i);
134
135                         glMatrixMode(GL_PROJECTION);
136                         glLoadMatrixf(goatvr_projection_matrix(i, 0.1, 200.0));
137
138                         view_matrix = goatvr_view_matrix(i);
139                         view_matrix.pre_rotate_x(deg_to_rad(cam_phi));
140                         view_matrix.pre_rotate_y(deg_to_rad(cam_theta));
141                         view_matrix.pre_translate(0, -cam_height, 0);
142
143                         glMatrixMode(GL_MODELVIEW);
144                         glLoadMatrixf(view_matrix[0]);
145
146                         draw_scene();
147                 }
148                 goatvr_draw_done();
149
150                 if(should_swap) {
151                         app_swap_buffers();
152                 }
153                 app_redraw();   // in VR mode, force continuous redraw
154
155         } else {
156                 // regular monoscopic mode
157                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
158
159                 Mat4 mat;
160                 mat.perspective(deg_to_rad(fov), win_aspect, 0.1, 200.0);
161                 glMatrixMode(GL_PROJECTION);
162                 glLoadMatrixf(mat[0]);
163
164                 view_matrix = Mat4::identity;
165                 view_matrix.pre_rotate_x(deg_to_rad(cam_phi));
166                 view_matrix.pre_rotate_y(deg_to_rad(cam_theta));
167                 view_matrix.pre_translate(0, -cam_height, 0);
168
169                 glMatrixMode(GL_MODELVIEW);
170                 glLoadMatrixf(view_matrix[0]);
171
172                 draw_scene();
173
174                 app_swap_buffers();
175                 app_redraw();   // since we added animation we need to redisplay even in non-VR mode
176         }
177         assert(glGetError() == GL_NO_ERROR);
178 }
179
180 static void draw_scene()
181 {
182         if(!opt.vr) {
183                 set_render_target(rtarg);
184                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
185         }
186
187         draw_backdrop();
188         draw_fs();
189
190         if(!opt.vr) {
191                 set_render_target(0);
192
193                 glPushAttrib(GL_ENABLE_BIT);
194                 glDisable(GL_DEPTH_TEST);
195
196                 glUseProgram(post_sdr);
197                 set_uniform_matrix4(post_sdr, "texmat", rtarg->get_texture_matrix()[0]);
198
199                 bind_texture(rtarg->get_texture());
200
201                 glBegin(GL_QUADS);
202                 glTexCoord2f(0, 0);
203                 glVertex2f(-1, -1);
204                 glTexCoord2f(1, 0);
205                 glVertex2f(1, -1);
206                 glTexCoord2f(1, 1);
207                 glVertex2f(1, 1);
208                 glTexCoord2f(0, 1);
209                 glVertex2f(-1, 1);
210                 glEnd();
211
212                 bind_texture(0);
213                 glUseProgram(0);
214
215                 glPopAttrib();
216         }
217 }
218
219 void app_reshape(int x, int y)
220 {
221         glViewport(0, 0, x, y);
222         rtarg_valid = false;
223
224         if(opt.vr) {
225                 goatvr_set_fb_size(x, y, 1.0);
226         }
227 }
228
229 void app_keyboard(int key, bool pressed)
230 {
231         if(pressed) {
232                 switch(key) {
233                 case 27:
234                         app_quit();
235                         break;
236
237                 case 'f':
238                         if(!opt.vr || should_swap) {
239                                 /* we take the need to swap as a signal that our window is not managed
240                                  * by some VR compositor, and therefore it's safe to fullscreen without
241                                  * upsetting the VR rendering output
242                                  */
243                                 opt.fullscreen = !opt.fullscreen;
244                                 app_fullscreen(opt.fullscreen);
245                         }
246                         break;
247
248                 case ' ':
249                         if(opt.vr) {
250                                 goatvr_recenter();
251                         }
252                         break;
253
254                 case '-':
255                         fov += 1.0;
256                         if(fov > 160.0) fov = 160.0;
257                         break;
258
259                 case '=':
260                         fov -= 1.0;
261                         if(fov < 0.0) fov = 0.0;
262                         break;
263                 }
264         }
265 }
266
267 void app_mouse_button(int bn, bool pressed, int x, int y)
268 {
269         bnstate[bn] = pressed;
270         prev_x = x;
271         prev_y = y;
272 }
273
274 void app_mouse_motion(int x, int y)
275 {
276         int dx = x - prev_x;
277         int dy = y - prev_y;
278         prev_x = x;
279         prev_y = y;
280
281         if(!dx && !dy) return;
282
283         if(bnstate[0]) {
284                 cam_theta += dx * 0.5;
285
286                 if(!opt.vr || !goatvr_have_headtracking()) {
287                         cam_phi += dy * 0.5;
288
289                         if(cam_phi < -90) cam_phi = -90;
290                         if(cam_phi > 90) cam_phi = 90;
291                 }
292         }
293         app_redraw();
294 }