rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@1
|
3 #include <string.h>
|
nuclear@0
|
4 #include <assert.h>
|
nuclear@8
|
5 #include "opengl.h"
|
nuclear@1
|
6 #include "vr.h"
|
nuclear@0
|
7 #include "camera.h"
|
nuclear@16
|
8 #include "sdr.h"
|
nuclear@0
|
9
|
nuclear@18
|
10 #ifdef __APPLE__
|
nuclear@18
|
11 #include <OpenGL/OpenGL.h>
|
nuclear@18
|
12 #include <OpenGL/CGLCurrent.h>
|
nuclear@18
|
13 #include <ApplicationServices/ApplicationServices.h>
|
nuclear@18
|
14 #endif
|
nuclear@18
|
15
|
nuclear@0
|
16 static bool init();
|
nuclear@0
|
17 static void cleanup();
|
nuclear@0
|
18 static void disp();
|
nuclear@16
|
19 static void disp_vr();
|
nuclear@9
|
20 static void draw_scene();
|
nuclear@16
|
21 static void draw_teapot(float size);
|
nuclear@13
|
22 static void draw_squares();
|
nuclear@12
|
23 static void draw_grid(float size, float spacing);
|
nuclear@16
|
24 static void toggle_mouselook();
|
nuclear@16
|
25 static void toggle_fullscreen();
|
nuclear@0
|
26 static void idle();
|
nuclear@0
|
27 static void reshape(int x, int y);
|
nuclear@0
|
28 static void keyb(unsigned char key, int x, int y);
|
nuclear@8
|
29 static void keyup(unsigned char key, int x, int y);
|
nuclear@8
|
30 static void mouse(int bn, int st, int x, int y);
|
nuclear@8
|
31 static void motion(int x, int y);
|
nuclear@8
|
32 static void passive(int x, int y);
|
nuclear@0
|
33 static void sball_rotate(int rx, int ry, int rz);
|
nuclear@1
|
34 static bool parse_args(int argc, char **argv);
|
nuclear@18
|
35 static void printfps();
|
nuclear@18
|
36 static int next_pow2(int x);
|
nuclear@0
|
37
|
nuclear@10
|
38 static VRFpsCamera cam;
|
nuclear@0
|
39 static int width, height;
|
nuclear@1
|
40 static bool use_vr = false;
|
nuclear@8
|
41
|
nuclear@8
|
42 static bool keystate[256];
|
nuclear@8
|
43
|
nuclear@18
|
44 static int rtarg_width, rtarg_height, rtarg_tex_width, rtarg_tex_height;
|
nuclear@18
|
45 static float tex_scale_x, tex_scale_y;
|
nuclear@12
|
46 static unsigned int fbo, tex[2], zbuf;
|
nuclear@12
|
47
|
nuclear@16
|
48 static unsigned int teapot_sdr;
|
nuclear@16
|
49
|
nuclear@16
|
50 static bool fullscreen_pending;
|
nuclear@16
|
51
|
nuclear@18
|
52
|
nuclear@0
|
53 int main(int argc, char **argv)
|
nuclear@0
|
54 {
|
nuclear@3
|
55 glutInitWindowSize(1280, 800);
|
nuclear@0
|
56 glutInit(&argc, argv);
|
nuclear@1
|
57
|
nuclear@1
|
58 if(!parse_args(argc, argv)) {
|
nuclear@1
|
59 return 1;
|
nuclear@1
|
60 }
|
nuclear@1
|
61
|
nuclear@12
|
62 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
|
nuclear@12
|
63 glutCreateWindow("oculus vr test 01");
|
nuclear@12
|
64
|
nuclear@12
|
65 width = glutGet(GLUT_WINDOW_WIDTH);
|
nuclear@12
|
66 height = glutGet(GLUT_WINDOW_HEIGHT);
|
nuclear@0
|
67
|
nuclear@16
|
68 glutDisplayFunc(use_vr ? disp_vr : disp);
|
nuclear@0
|
69 glutIdleFunc(idle);
|
nuclear@0
|
70 glutReshapeFunc(reshape);
|
nuclear@0
|
71 glutKeyboardFunc(keyb);
|
nuclear@8
|
72 glutKeyboardUpFunc(keyup);
|
nuclear@8
|
73 glutMouseFunc(mouse);
|
nuclear@8
|
74 glutMotionFunc(motion);
|
nuclear@0
|
75 glutSpaceballRotateFunc(sball_rotate);
|
nuclear@0
|
76
|
nuclear@0
|
77 if(!init()) {
|
nuclear@0
|
78 return 1;
|
nuclear@0
|
79 }
|
nuclear@0
|
80 atexit(cleanup);
|
nuclear@0
|
81
|
nuclear@0
|
82 glutMainLoop();
|
nuclear@0
|
83 return 0;
|
nuclear@0
|
84 }
|
nuclear@0
|
85
|
nuclear@0
|
86 static bool init()
|
nuclear@0
|
87 {
|
nuclear@9
|
88 glewInit(); // this must be first
|
nuclear@9
|
89
|
nuclear@0
|
90 glEnable(GL_DEPTH_TEST);
|
nuclear@0
|
91 glEnable(GL_LIGHTING);
|
nuclear@0
|
92 glEnable(GL_CULL_FACE);
|
nuclear@0
|
93
|
nuclear@0
|
94 glEnable(GL_LIGHT0);
|
nuclear@0
|
95 glEnable(GL_LIGHTING);
|
nuclear@16
|
96 glEnable(GL_NORMALIZE);
|
nuclear@0
|
97
|
nuclear@11
|
98 // y = height of neck
|
nuclear@11
|
99 cam.input_move(0, 1.65, 0);
|
nuclear@9
|
100
|
nuclear@12
|
101 if(use_vr) {
|
nuclear@12
|
102 if(vr_init(VR_INIT_OCULUS) == -1) {
|
nuclear@12
|
103 return false;
|
nuclear@12
|
104 }
|
nuclear@12
|
105
|
nuclear@12
|
106 // reshape to the size of the VR display
|
nuclear@12
|
107 int xsz = vr_get_width();
|
nuclear@12
|
108 int ysz = vr_get_height();
|
nuclear@12
|
109
|
nuclear@12
|
110 glutReshapeWindow(xsz, ysz);
|
nuclear@12
|
111
|
nuclear@12
|
112 rtarg_width = (xsz + xsz / 2) / 2;
|
nuclear@12
|
113 rtarg_height = ysz + ysz / 2;
|
nuclear@16
|
114
|
nuclear@18
|
115 rtarg_tex_width = next_pow2(rtarg_width);
|
nuclear@18
|
116 rtarg_tex_height = next_pow2(rtarg_height);
|
nuclear@18
|
117 tex_scale_x = (float)rtarg_width / (float)rtarg_tex_width;
|
nuclear@18
|
118 tex_scale_y = (float)rtarg_height / (float)rtarg_tex_height;
|
nuclear@18
|
119
|
nuclear@18
|
120 printf("render target: %dx%d (%dx%d)\n", rtarg_width, rtarg_height, rtarg_tex_width, rtarg_tex_height);
|
nuclear@16
|
121
|
nuclear@16
|
122 // create render targets for each eye
|
nuclear@16
|
123 GLenum wrap_mode = GL_CLAMP_TO_EDGE;
|
nuclear@16
|
124 if(!GLEW_SGIS_texture_edge_clamp) {
|
nuclear@16
|
125 wrap_mode = GL_CLAMP;
|
nuclear@16
|
126 }
|
nuclear@16
|
127
|
nuclear@16
|
128 glGenTextures(2, tex);
|
nuclear@16
|
129 for(int i=0; i<2; i++) {
|
nuclear@16
|
130 glBindTexture(GL_TEXTURE_2D, tex[i]);
|
nuclear@16
|
131 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@16
|
132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@16
|
133 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode);
|
nuclear@16
|
134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode);
|
nuclear@18
|
135 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rtarg_tex_width, rtarg_tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
nuclear@16
|
136 }
|
nuclear@16
|
137
|
nuclear@16
|
138 // create the depth render buffer
|
nuclear@18
|
139 glGenRenderbuffersEXT(1, &zbuf);
|
nuclear@18
|
140 glBindRenderbufferEXT(GL_RENDERBUFFER, zbuf);
|
nuclear@18
|
141 glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rtarg_tex_width, rtarg_tex_height);
|
nuclear@16
|
142
|
nuclear@16
|
143 // create the FBO
|
nuclear@18
|
144 glGenFramebuffersEXT(1, &fbo);
|
nuclear@18
|
145 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
|
nuclear@18
|
146 glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[0], 0);
|
nuclear@18
|
147 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, zbuf);
|
nuclear@0
|
148 }
|
nuclear@12
|
149
|
nuclear@16
|
150 teapot_sdr = create_program_load("sdr/phong.v.glsl", "sdr/phong.p.glsl");
|
nuclear@12
|
151
|
nuclear@18
|
152 // enable vsync
|
nuclear@18
|
153 #ifdef __APPLE__
|
nuclear@18
|
154 int swapint = 1;
|
nuclear@18
|
155 CGLContextObj ctx = CGLGetCurrentContext();
|
nuclear@18
|
156 CGLSetParameter(ctx, kCGLCPSwapInterval, &swapint);
|
nuclear@18
|
157 #endif
|
nuclear@18
|
158
|
nuclear@18
|
159 #ifdef __APPLE__
|
nuclear@18
|
160 // this is required for glutWarpPointer to work correctly, otherwise after every
|
nuclear@18
|
161 // warp, mac os x freezes event processing for 1/4 second.
|
nuclear@18
|
162 CGSetLocalEventsSuppressionInterval(0.0);
|
nuclear@18
|
163 #endif
|
nuclear@0
|
164 return true;
|
nuclear@0
|
165 }
|
nuclear@0
|
166
|
nuclear@0
|
167 static void cleanup()
|
nuclear@0
|
168 {
|
nuclear@12
|
169 glDeleteTextures(2, tex);
|
nuclear@18
|
170 glDeleteRenderbuffersEXT(1, &zbuf);
|
nuclear@18
|
171 glDeleteFramebuffersEXT(1, &fbo);
|
nuclear@1
|
172 vr_shutdown();
|
nuclear@0
|
173 }
|
nuclear@0
|
174
|
nuclear@14
|
175 static void handle_input(float dt)
|
nuclear@14
|
176 {
|
nuclear@14
|
177 Vector3 inpv;
|
nuclear@14
|
178 float offs = dt * 2.0;
|
nuclear@14
|
179
|
nuclear@14
|
180 if(keystate['w'] || keystate['W']) {
|
nuclear@14
|
181 inpv.z -= offs;
|
nuclear@14
|
182 }
|
nuclear@14
|
183 if(keystate['s'] || keystate['S']) {
|
nuclear@14
|
184 inpv.z += offs;
|
nuclear@14
|
185 }
|
nuclear@14
|
186 if(keystate['d'] || keystate['D']) {
|
nuclear@14
|
187 inpv.x += offs;
|
nuclear@14
|
188 }
|
nuclear@14
|
189 if(keystate['a'] || keystate['A']) {
|
nuclear@14
|
190 inpv.x -= offs;
|
nuclear@14
|
191 }
|
nuclear@14
|
192
|
nuclear@14
|
193 cam.input_move(inpv.x, inpv.y, inpv.z);
|
nuclear@14
|
194 }
|
nuclear@14
|
195
|
nuclear@16
|
196 // display function used in regular mode
|
nuclear@0
|
197 static void disp()
|
nuclear@0
|
198 {
|
nuclear@14
|
199 static long prev_msec;
|
nuclear@14
|
200 long msec = glutGet(GLUT_ELAPSED_TIME);
|
nuclear@14
|
201 float dt = (msec - prev_msec) / 1000.0;
|
nuclear@14
|
202 prev_msec = msec;
|
nuclear@4
|
203
|
nuclear@14
|
204 handle_input(dt);
|
nuclear@16
|
205
|
nuclear@16
|
206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@16
|
207
|
nuclear@16
|
208 glMatrixMode(GL_PROJECTION);
|
nuclear@16
|
209 glLoadIdentity();
|
nuclear@16
|
210 gluPerspective(45, (float)width / (float)height, 0.25, 500.0);
|
nuclear@16
|
211
|
nuclear@16
|
212 glMatrixMode(GL_MODELVIEW);
|
nuclear@16
|
213 glLoadIdentity();
|
nuclear@16
|
214 cam.use_inverse();
|
nuclear@16
|
215 draw_scene();
|
nuclear@16
|
216
|
nuclear@16
|
217 glutSwapBuffers();
|
nuclear@16
|
218 assert(glGetError() == GL_NO_ERROR);
|
nuclear@18
|
219
|
nuclear@18
|
220 printfps();
|
nuclear@16
|
221 }
|
nuclear@16
|
222
|
nuclear@16
|
223 // display function used in VR mode
|
nuclear@16
|
224 static void disp_vr()
|
nuclear@16
|
225 {
|
nuclear@16
|
226 static long prev_msec;
|
nuclear@16
|
227 long msec = glutGet(GLUT_ELAPSED_TIME);
|
nuclear@16
|
228 float dt = (msec - prev_msec) / 1000.0;
|
nuclear@16
|
229 prev_msec = msec;
|
nuclear@16
|
230
|
nuclear@16
|
231 handle_input(dt);
|
nuclear@12
|
232 cam.track_vr();
|
nuclear@0
|
233
|
nuclear@13
|
234 float proj_matrix[16];
|
nuclear@13
|
235
|
nuclear@13
|
236 float eye_dist = vr_get_eyedist();
|
nuclear@12
|
237
|
nuclear@12
|
238 glViewport(0, 0, rtarg_width, rtarg_height);
|
nuclear@12
|
239
|
nuclear@12
|
240 glClearColor(0.1, 0.1, 0.1, 1.0);
|
nuclear@12
|
241
|
nuclear@12
|
242 // draw left view
|
nuclear@18
|
243 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
|
nuclear@18
|
244 glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[0], 0);
|
nuclear@12
|
245
|
nuclear@12
|
246 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@0
|
247
|
nuclear@13
|
248 glMatrixMode(GL_PROJECTION);
|
nuclear@13
|
249 vr_get_proj_matrix(proj_matrix, VR_EYE_LEFT);
|
nuclear@13
|
250 glLoadTransposeMatrixf(proj_matrix);
|
nuclear@13
|
251
|
nuclear@0
|
252 glMatrixMode(GL_MODELVIEW);
|
nuclear@9
|
253 glLoadIdentity();
|
nuclear@13
|
254 glTranslatef(eye_dist / 2.0, 0, 0);
|
nuclear@12
|
255 cam.use_inverse();
|
nuclear@12
|
256 draw_scene();
|
nuclear@0
|
257
|
nuclear@12
|
258
|
nuclear@12
|
259 // draw right view
|
nuclear@18
|
260 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
|
nuclear@18
|
261 glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[1], 0);
|
nuclear@12
|
262
|
nuclear@12
|
263 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@12
|
264
|
nuclear@13
|
265 glMatrixMode(GL_PROJECTION);
|
nuclear@13
|
266 vr_get_proj_matrix(proj_matrix, VR_EYE_RIGHT);
|
nuclear@13
|
267 glLoadTransposeMatrixf(proj_matrix);
|
nuclear@13
|
268
|
nuclear@12
|
269 glMatrixMode(GL_MODELVIEW);
|
nuclear@12
|
270 glLoadIdentity();
|
nuclear@13
|
271 glTranslatef(-eye_dist / 2.0, 0, 0);
|
nuclear@9
|
272 cam.use_inverse();
|
nuclear@12
|
273 draw_scene();
|
nuclear@9
|
274
|
nuclear@12
|
275 // return to the regular window framebuffer
|
nuclear@12
|
276 glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
nuclear@12
|
277 glViewport(0, 0, width, height);
|
nuclear@12
|
278
|
nuclear@12
|
279 glClearColor(0, 0, 0, 0);
|
nuclear@12
|
280 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@12
|
281
|
nuclear@18
|
282 vr_draw_eye(VR_EYE_LEFT, tex[0], tex_scale_x, tex_scale_y);
|
nuclear@18
|
283 vr_draw_eye(VR_EYE_RIGHT, tex[1], tex_scale_x, tex_scale_y);
|
nuclear@9
|
284
|
nuclear@9
|
285 glutSwapBuffers();
|
nuclear@9
|
286 assert(glGetError() == GL_NO_ERROR);
|
nuclear@13
|
287
|
nuclear@13
|
288 glFinish();
|
nuclear@18
|
289
|
nuclear@18
|
290 printfps();
|
nuclear@9
|
291 }
|
nuclear@9
|
292
|
nuclear@12
|
293 static void draw_scene()
|
nuclear@12
|
294 {
|
nuclear@12
|
295 float lpos[] = {0, 60, 0, 1};
|
nuclear@12
|
296 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
|
nuclear@12
|
297
|
nuclear@14
|
298 draw_grid(50.0, 2.5);
|
nuclear@13
|
299
|
nuclear@16
|
300 static const Vector2 teapos[] = {
|
nuclear@16
|
301 Vector2(-8, -8), Vector2(8, -8), Vector2(8, 8), Vector2(-8, 8)
|
nuclear@12
|
302 };
|
nuclear@16
|
303 static const float teasize[] = { 1.0, 2.0, 1.7, 1.4 };
|
nuclear@16
|
304 static const float teacolor[][4] = {
|
nuclear@16
|
305 {1.0, 0.4, 0.2, 1.0}, {0.2, 0.35, 1.0, 1.0}, {1.0, 0.9, 0.3, 1.0}, {0.3, 1.0, 0.4, 1.0}
|
nuclear@16
|
306 };
|
nuclear@16
|
307 static const float spec[] = {0.8, 0.8, 0.8, 1.0};
|
nuclear@16
|
308
|
nuclear@16
|
309 glUseProgram(teapot_sdr);
|
nuclear@12
|
310
|
nuclear@12
|
311 for(int i=0; i<4; i++) {
|
nuclear@16
|
312 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, teacolor[i]);
|
nuclear@16
|
313 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
|
nuclear@16
|
314 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.0);
|
nuclear@16
|
315
|
nuclear@12
|
316 glPushMatrix();
|
nuclear@12
|
317 glTranslatef(teapos[i].x, 0, teapos[i].y);
|
nuclear@16
|
318 draw_teapot(teasize[i]);
|
nuclear@12
|
319 glPopMatrix();
|
nuclear@12
|
320 }
|
nuclear@16
|
321 glUseProgram(0);
|
nuclear@12
|
322
|
nuclear@13
|
323 draw_squares();
|
nuclear@12
|
324 }
|
nuclear@12
|
325
|
nuclear@16
|
326 static void draw_teapot(float size)
|
nuclear@9
|
327 {
|
nuclear@9
|
328 static int tealist;
|
nuclear@9
|
329
|
nuclear@9
|
330 if(!tealist) {
|
nuclear@9
|
331 tealist = glGenLists(1);
|
nuclear@9
|
332 glNewList(tealist, GL_COMPILE);
|
nuclear@9
|
333 glutSolidTeapot(1.0);
|
nuclear@9
|
334 glEndList();
|
nuclear@9
|
335 }
|
nuclear@9
|
336
|
nuclear@16
|
337 glMatrixMode(GL_MODELVIEW);
|
nuclear@16
|
338 glPushMatrix();
|
nuclear@16
|
339 glScalef(size, size, size);
|
nuclear@16
|
340 glTranslatef(0, 0.73, 0);
|
nuclear@16
|
341
|
nuclear@9
|
342 glFrontFace(GL_CW);
|
nuclear@9
|
343 glCallList(tealist);
|
nuclear@9
|
344 glFrontFace(GL_CCW);
|
nuclear@16
|
345
|
nuclear@16
|
346 glPopMatrix();
|
nuclear@9
|
347 }
|
nuclear@9
|
348
|
nuclear@13
|
349 static void draw_squares()
|
nuclear@13
|
350 {
|
nuclear@14
|
351 static const int num_sq = 8;
|
nuclear@13
|
352
|
nuclear@13
|
353 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
|
nuclear@13
|
354 glDisable(GL_LIGHTING);
|
nuclear@13
|
355
|
nuclear@13
|
356 glMatrixMode(GL_MODELVIEW);
|
nuclear@13
|
357 glPushMatrix();
|
nuclear@13
|
358 glTranslatef(0, 1, 0);
|
nuclear@13
|
359
|
nuclear@13
|
360
|
nuclear@14
|
361 glLineWidth(2.0);
|
nuclear@13
|
362 glColor3f(1.0, 0.7, 0.2);
|
nuclear@13
|
363
|
nuclear@13
|
364 float zdist = 2.0;
|
nuclear@13
|
365 for(int i=0; i<num_sq; i++) {
|
nuclear@13
|
366 glBegin(GL_LINE_LOOP);
|
nuclear@13
|
367 glVertex3f(-1, -1, -zdist);
|
nuclear@13
|
368 glVertex3f(1, -1, -zdist);
|
nuclear@13
|
369 glVertex3f(1, 1, -zdist);
|
nuclear@13
|
370 glVertex3f(-1, 1, -zdist);
|
nuclear@13
|
371 glEnd();
|
nuclear@13
|
372
|
nuclear@14
|
373 zdist += 2.0;
|
nuclear@13
|
374 }
|
nuclear@13
|
375
|
nuclear@13
|
376 glPopMatrix();
|
nuclear@13
|
377 glPopAttrib();
|
nuclear@13
|
378 }
|
nuclear@13
|
379
|
nuclear@12
|
380 static void draw_grid(float size, float spacing)
|
nuclear@9
|
381 {
|
nuclear@9
|
382 int num_lines = size / spacing;
|
nuclear@9
|
383 float dist = size / 2.0;
|
nuclear@9
|
384
|
nuclear@9
|
385 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
|
nuclear@9
|
386 glDisable(GL_LIGHTING);
|
nuclear@9
|
387
|
nuclear@9
|
388 glLineWidth(1.0);
|
nuclear@9
|
389
|
nuclear@9
|
390 glBegin(GL_LINES);
|
nuclear@9
|
391 glColor3f(0.4, 0.4, 0.4);
|
nuclear@9
|
392
|
nuclear@9
|
393 float x = -dist;
|
nuclear@9
|
394 for(int i=0; i<=num_lines; i++) {
|
nuclear@9
|
395 if(i != num_lines / 2) {
|
nuclear@9
|
396 glVertex3f(-dist, 0, x);
|
nuclear@9
|
397 glVertex3f(dist, 0, x);
|
nuclear@9
|
398 glVertex3f(x, 0, -dist);
|
nuclear@9
|
399 glVertex3f(x, 0, dist);
|
nuclear@9
|
400 }
|
nuclear@9
|
401 x += spacing;
|
nuclear@9
|
402 }
|
nuclear@9
|
403 glEnd();
|
nuclear@9
|
404
|
nuclear@9
|
405 glLineWidth(2.0);
|
nuclear@9
|
406
|
nuclear@9
|
407 glBegin(GL_LINES);
|
nuclear@9
|
408 glColor3f(1.0, 0, 0);
|
nuclear@9
|
409 glVertex3f(-dist, 0, 0);
|
nuclear@9
|
410 glVertex3f(dist, 0, 0);
|
nuclear@9
|
411 glColor3f(0, 1.0, 0);
|
nuclear@9
|
412 glVertex3f(0, 0, -dist);
|
nuclear@9
|
413 glVertex3f(0, 0, dist);
|
nuclear@9
|
414 glEnd();
|
nuclear@9
|
415
|
nuclear@9
|
416 glPopAttrib();
|
nuclear@9
|
417 }
|
nuclear@9
|
418
|
nuclear@16
|
419 static bool mouselook;
|
nuclear@16
|
420
|
nuclear@16
|
421 static void toggle_mouselook()
|
nuclear@16
|
422 {
|
nuclear@16
|
423 mouselook = !mouselook;
|
nuclear@16
|
424 if(mouselook) {
|
nuclear@16
|
425 glutPassiveMotionFunc(passive);
|
nuclear@16
|
426 glutSetCursor(GLUT_CURSOR_NONE);
|
nuclear@16
|
427 glutWarpPointer(width / 2, height / 2);
|
nuclear@16
|
428 } else {
|
nuclear@16
|
429 glutPassiveMotionFunc(0);
|
nuclear@16
|
430 glutSetCursor(GLUT_CURSOR_INHERIT);
|
nuclear@16
|
431 }
|
nuclear@16
|
432 }
|
nuclear@16
|
433
|
nuclear@22
|
434 static bool fullscreen;
|
nuclear@16
|
435 static void toggle_fullscreen()
|
nuclear@16
|
436 {
|
nuclear@16
|
437 static int prev_x, prev_y;
|
nuclear@16
|
438 static int prev_xsz, prev_ysz;
|
nuclear@16
|
439
|
nuclear@16
|
440 fullscreen = !fullscreen;
|
nuclear@16
|
441
|
nuclear@16
|
442 if(fullscreen) {
|
nuclear@16
|
443 prev_x = glutGet(GLUT_WINDOW_X);
|
nuclear@16
|
444 prev_y = glutGet(GLUT_WINDOW_Y);
|
nuclear@16
|
445 prev_xsz = width;
|
nuclear@16
|
446 prev_ysz = height;
|
nuclear@16
|
447
|
nuclear@16
|
448 if(use_vr) {
|
nuclear@16
|
449 // go fullscreen to the correct monitor
|
nuclear@16
|
450 int x, y;
|
nuclear@16
|
451 vr_get_display_pos(&x, &y);
|
nuclear@16
|
452 glutPositionWindow(x, y);
|
nuclear@16
|
453
|
nuclear@16
|
454 // also warp the mouse and enable mouselook
|
nuclear@16
|
455 glutWarpPointer(x + width / 2, y + height / 2);
|
nuclear@16
|
456
|
nuclear@16
|
457 /* Ok this next line needs some explanation:
|
nuclear@16
|
458 * glutPositionWindow, doesn't necessarilly get executed directly.
|
nuclear@16
|
459 * GLUT might defer it for the next round of event processing, just
|
nuclear@16
|
460 * so that it may coalesce multiple positioning requests.
|
nuclear@16
|
461 * However that means that if we just called glutFullScreen right
|
nuclear@16
|
462 * here, the window manager would have no idea that the window will
|
nuclear@16
|
463 * move to another monitor, thus making it the size of the monitor
|
nuclear@16
|
464 * it occupied before the move.
|
nuclear@16
|
465 * So I'm setting a flag here, and execute the glutFullScreen call
|
nuclear@16
|
466 * at the next idle invocation. (would display be a safer place?).
|
nuclear@16
|
467 */
|
nuclear@16
|
468 fullscreen_pending = true;
|
nuclear@16
|
469 } else {
|
nuclear@16
|
470 glutFullScreen();
|
nuclear@16
|
471 toggle_mouselook();
|
nuclear@16
|
472 }
|
nuclear@16
|
473 } else {
|
nuclear@16
|
474 glutReshapeWindow(prev_xsz, prev_ysz);
|
nuclear@16
|
475 glutPositionWindow(prev_x, prev_y);
|
nuclear@16
|
476
|
nuclear@16
|
477 if(mouselook) {
|
nuclear@16
|
478 toggle_mouselook();
|
nuclear@16
|
479 }
|
nuclear@16
|
480 }
|
nuclear@16
|
481 glutPostRedisplay();
|
nuclear@16
|
482 }
|
nuclear@16
|
483
|
nuclear@16
|
484
|
nuclear@0
|
485 static void idle()
|
nuclear@0
|
486 {
|
nuclear@16
|
487 if(fullscreen_pending) {
|
nuclear@16
|
488 glutFullScreen();
|
nuclear@16
|
489
|
nuclear@16
|
490 if(!mouselook) {
|
nuclear@16
|
491 toggle_mouselook();
|
nuclear@16
|
492 }
|
nuclear@16
|
493 fullscreen_pending = false;
|
nuclear@16
|
494 }
|
nuclear@0
|
495 glutPostRedisplay();
|
nuclear@0
|
496 }
|
nuclear@0
|
497
|
nuclear@0
|
498
|
nuclear@0
|
499 static void reshape(int x, int y)
|
nuclear@0
|
500 {
|
nuclear@0
|
501 width = x;
|
nuclear@0
|
502 height = y;
|
nuclear@12
|
503
|
nuclear@12
|
504 if(!use_vr) {
|
nuclear@12
|
505 rtarg_width = width;
|
nuclear@12
|
506 rtarg_height = height;
|
nuclear@18
|
507
|
nuclear@18
|
508 int new_tex_width = next_pow2(width);
|
nuclear@18
|
509 int new_tex_height = next_pow2(height);
|
nuclear@18
|
510
|
nuclear@18
|
511 if(new_tex_width != rtarg_tex_width || new_tex_height != rtarg_tex_width) {
|
nuclear@18
|
512 // TODO
|
nuclear@18
|
513 exit(1);
|
nuclear@18
|
514 }
|
nuclear@18
|
515
|
nuclear@18
|
516 rtarg_tex_width = new_tex_width;
|
nuclear@18
|
517 rtarg_tex_height = new_tex_height;
|
nuclear@18
|
518
|
nuclear@18
|
519 tex_scale_x = (float)rtarg_width / (float)rtarg_tex_width;
|
nuclear@18
|
520 tex_scale_y = (float)rtarg_height / (float)rtarg_tex_height;
|
nuclear@18
|
521
|
nuclear@12
|
522 }
|
nuclear@0
|
523 }
|
nuclear@0
|
524
|
nuclear@0
|
525 static void keyb(unsigned char key, int x, int y)
|
nuclear@0
|
526 {
|
nuclear@0
|
527 switch(key) {
|
nuclear@0
|
528 case 27:
|
nuclear@0
|
529 exit(0);
|
nuclear@8
|
530
|
nuclear@8
|
531 case 'm':
|
nuclear@16
|
532 toggle_mouselook();
|
nuclear@8
|
533 break;
|
nuclear@12
|
534
|
nuclear@12
|
535 case 'f':
|
nuclear@16
|
536 toggle_fullscreen();
|
nuclear@12
|
537 break;
|
nuclear@0
|
538 }
|
nuclear@8
|
539
|
nuclear@8
|
540 keystate[key] = true;
|
nuclear@8
|
541 glutPostRedisplay();
|
nuclear@8
|
542 }
|
nuclear@8
|
543
|
nuclear@8
|
544 static void keyup(unsigned char key, int x, int y)
|
nuclear@8
|
545 {
|
nuclear@8
|
546 keystate[key] = false;
|
nuclear@8
|
547 glutPostRedisplay();
|
nuclear@8
|
548 }
|
nuclear@8
|
549
|
nuclear@8
|
550 static bool bnstate[32];
|
nuclear@8
|
551 static int prev_x, prev_y;
|
nuclear@8
|
552
|
nuclear@8
|
553 static void mouse(int bn, int st, int x, int y)
|
nuclear@8
|
554 {
|
nuclear@8
|
555 prev_x = x;
|
nuclear@8
|
556 prev_y = y;
|
nuclear@8
|
557 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN;
|
nuclear@8
|
558 }
|
nuclear@8
|
559
|
nuclear@8
|
560 static void motion(int x, int y)
|
nuclear@8
|
561 {
|
nuclear@8
|
562 if(mouselook) {
|
nuclear@8
|
563 // just call passive, it does what we need
|
nuclear@8
|
564 passive(x, y);
|
nuclear@8
|
565 }
|
nuclear@8
|
566 }
|
nuclear@8
|
567
|
nuclear@8
|
568 static void passive(int x, int y)
|
nuclear@8
|
569 {
|
nuclear@8
|
570 // no need to test mouselook; this callback is only set when mouselook is enabled
|
nuclear@8
|
571 int center_x = width / 2;
|
nuclear@8
|
572 int center_y = height / 2;
|
nuclear@8
|
573
|
nuclear@8
|
574 int dx = x - center_x;
|
nuclear@18
|
575 int dy = use_vr ? 0 : y - center_y;
|
nuclear@8
|
576
|
nuclear@22
|
577 if(use_vr && fullscreen) {
|
nuclear@22
|
578 dy = 0;
|
nuclear@22
|
579 }
|
nuclear@22
|
580
|
nuclear@8
|
581 if(!dx && !dy) {
|
nuclear@8
|
582 return;
|
nuclear@8
|
583 }
|
nuclear@8
|
584
|
nuclear@9
|
585 float dtheta_deg = dy * 0.1;
|
nuclear@9
|
586 float dphi_deg = dx * 0.1;
|
nuclear@9
|
587
|
nuclear@9
|
588 cam.input_rotate(DEG_TO_RAD(dtheta_deg), DEG_TO_RAD(dphi_deg), 0);
|
nuclear@9
|
589
|
nuclear@18
|
590 glutWarpPointer(center_x, center_y);
|
nuclear@8
|
591 glutPostRedisplay();
|
nuclear@0
|
592 }
|
nuclear@0
|
593
|
nuclear@0
|
594 static void sball_rotate(int rx, int ry, int rz)
|
nuclear@0
|
595 {
|
nuclear@0
|
596 }
|
nuclear@1
|
597
|
nuclear@1
|
598 static bool parse_args(int argc, char **argv)
|
nuclear@1
|
599 {
|
nuclear@1
|
600 for(int i=1; i<argc; i++) {
|
nuclear@1
|
601 if(argv[i][0] == '-') {
|
nuclear@1
|
602 if(strcmp(argv[i], "-vr") == 0) {
|
nuclear@1
|
603 use_vr = true;
|
nuclear@1
|
604 } else if(strcmp(argv[i], "-novr") == 0) {
|
nuclear@1
|
605 use_vr = false;
|
nuclear@1
|
606 } else {
|
nuclear@1
|
607 fprintf(stderr, "invalid option: %s\n", argv[i]);
|
nuclear@1
|
608 return false;
|
nuclear@1
|
609 }
|
nuclear@1
|
610 } else {
|
nuclear@1
|
611 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
|
nuclear@1
|
612 return false;
|
nuclear@1
|
613 }
|
nuclear@1
|
614 }
|
nuclear@1
|
615 return true;
|
nuclear@1
|
616 }
|
nuclear@18
|
617
|
nuclear@18
|
618 static void printfps()
|
nuclear@18
|
619 {
|
nuclear@18
|
620 static unsigned int last_upd, frames;
|
nuclear@18
|
621 unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
|
nuclear@18
|
622 unsigned int dmsec = msec - last_upd;
|
nuclear@18
|
623
|
nuclear@18
|
624 frames++;
|
nuclear@18
|
625
|
nuclear@18
|
626 if(dmsec > 2000) {
|
nuclear@18
|
627 float dt = (float)dmsec / 1000.0f;
|
nuclear@18
|
628
|
nuclear@18
|
629 printf("fps: %.2f \r", (float)frames / dt);
|
nuclear@18
|
630 fflush(stdout);
|
nuclear@18
|
631
|
nuclear@18
|
632 frames = 0;
|
nuclear@18
|
633 last_upd = msec;
|
nuclear@18
|
634 }
|
nuclear@18
|
635 }
|
nuclear@18
|
636
|
nuclear@18
|
637 static int next_pow2(int x)
|
nuclear@18
|
638 {
|
nuclear@18
|
639 x--;
|
nuclear@18
|
640 x = (x >> 1) | x;
|
nuclear@18
|
641 x = (x >> 2) | x;
|
nuclear@18
|
642 x = (x >> 4) | x;
|
nuclear@18
|
643 x = (x >> 8) | x;
|
nuclear@18
|
644 x = (x >> 16) | x;
|
nuclear@18
|
645 return x + 1;
|
nuclear@18
|
646 }
|