nuclear@15: #include nuclear@2: #include "game.h" nuclear@13: #include "gameopt.h" nuclear@2: #include "opengl.h" nuclear@2: #include "camera.h" nuclear@2: #include "texture.h" nuclear@4: #include "vr/vr.h" nuclear@2: nuclear@7: static void game_render_eye(int eye); nuclear@2: static void draw_scene(); nuclear@6: static bool setup_rtarg(int x, int y); nuclear@15: static void draw_box(float sz); nuclear@15: static void draw_pyramid(float basesz, float height); nuclear@15: nuclear@6: nuclear@7: static Texture *rtarg; nuclear@6: static unsigned int fbo, rtarg_depth; nuclear@7: static int rtwidth, rtheight; nuclear@2: nuclear@2: static const float move_speed = 10.0f; nuclear@2: nuclear@2: static int fb_width, fb_height; nuclear@2: static FlyCamera cam; nuclear@2: static Texture floor_tex; nuclear@2: static bool keystate[256]; nuclear@13: static float player_height = 1.68; nuclear@2: nuclear@2: bool game_init() nuclear@2: { nuclear@13: if(opt.vr) { nuclear@13: vr_init(); nuclear@13: if(opt.vr_module) { nuclear@13: vr_use_module_named(opt.vr_module); nuclear@13: } nuclear@13: nuclear@13: player_height = vr_get_optf(VR_OPT_EYE_HEIGHT); nuclear@13: } nuclear@4: nuclear@2: glEnable(GL_DEPTH_TEST); nuclear@2: glEnable(GL_CULL_FACE); nuclear@2: glEnable(GL_LIGHTING); nuclear@2: glEnable(GL_LIGHT0); nuclear@12: glEnable(GL_NORMALIZE); nuclear@2: nuclear@2: glClearColor(0.1, 0.1, 0.1, 1); nuclear@2: nuclear@6: nuclear@2: if(!floor_tex.load("data/tiles.png")) { nuclear@2: return false; nuclear@2: } nuclear@2: nuclear@13: cam.input_move(0, player_height, 0); nuclear@2: return true; nuclear@2: } nuclear@2: nuclear@2: void game_cleanup() nuclear@2: { nuclear@2: floor_tex.destroy(); nuclear@13: if(opt.vr) { nuclear@13: vr_shutdown(); nuclear@13: } nuclear@6: nuclear@6: if(fbo) { nuclear@6: glDeleteFramebuffers(1, &fbo); nuclear@6: glDeleteRenderbuffers(1, &rtarg_depth); nuclear@7: delete rtarg; nuclear@6: } nuclear@2: } nuclear@2: nuclear@2: void game_update(unsigned int msec) nuclear@2: { nuclear@2: static unsigned int prev_msec; nuclear@2: float dt = (msec - prev_msec) / 1000.0f; nuclear@2: float offs = dt * move_speed; nuclear@2: prev_msec = msec; nuclear@2: nuclear@2: Vector3 move; nuclear@2: float roll = 0.0f; nuclear@2: nuclear@2: if(keystate['d'] || keystate['D']) { nuclear@2: move.x += offs; nuclear@2: } nuclear@2: if(keystate['a'] || keystate['A']) { nuclear@2: move.x -= offs; nuclear@2: } nuclear@2: if(keystate['s'] || keystate['S']) { nuclear@2: move.z += offs; nuclear@2: } nuclear@2: if(keystate['w'] || keystate['W']) { nuclear@2: move.z -= offs; nuclear@2: } nuclear@2: if(keystate['e'] || keystate['E']) { nuclear@2: roll += dt; nuclear@2: } nuclear@2: if(keystate['q'] || keystate['Q']) { nuclear@2: roll -= dt; nuclear@2: } nuclear@2: nuclear@2: cam.input_move(move.x, move.y, move.z); nuclear@2: cam.input_rotate(0, 0, roll); nuclear@2: } nuclear@2: nuclear@7: void game_render() nuclear@2: { nuclear@13: if(opt.vr) { nuclear@13: glBindFramebuffer(GL_FRAMEBUFFER, fbo); nuclear@13: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@6: nuclear@13: glViewport(0, 0, rtwidth / 2.0, rtheight); nuclear@13: vr_begin(VR_EYE_LEFT); nuclear@13: game_render_eye(-1); nuclear@13: vr_end(); nuclear@7: nuclear@13: glViewport(rtwidth / 2, 0, rtwidth / 2.0, rtheight); nuclear@13: vr_begin(VR_EYE_RIGHT); nuclear@13: game_render_eye(1); nuclear@13: vr_end(); nuclear@7: nuclear@13: glBindFramebuffer(GL_FRAMEBUFFER, 0); nuclear@13: glViewport(0, 0, fb_width, fb_height); nuclear@8: nuclear@13: vr_output_texture(rtarg->get_texture_id(), 0, 0, (float)rtwidth / (float)rtarg->get_width(), nuclear@13: (float)rtheight / (float)rtarg->get_height()); nuclear@13: } else { nuclear@13: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@13: nuclear@13: game_render_eye(0); nuclear@13: } nuclear@9: nuclear@9: vr_swap_buffers(); nuclear@7: } nuclear@7: nuclear@7: static void game_render_eye(int eye) nuclear@7: { nuclear@4: float mat[16]; nuclear@2: Matrix4x4 view_matrix = cam.get_matrix().inverse(); nuclear@2: nuclear@2: glMatrixMode(GL_PROJECTION); nuclear@2: glLoadIdentity(); nuclear@11: if(eye == 0 || !vr_proj_matrix(eye < 0 ? 0 : 1, 0.5, 500.0, mat)) { nuclear@4: gluPerspective(60.0, (float)fb_width / (float)fb_height, 0.5, 500.0); nuclear@11: } else { nuclear@7: glLoadMatrixf(mat); nuclear@11: } nuclear@2: nuclear@2: glMatrixMode(GL_MODELVIEW); nuclear@11: if(eye == 0 || !vr_view_matrix(eye < 0 ? 0 : 1, mat)) { nuclear@4: glLoadIdentity(); nuclear@11: } else { nuclear@18: glLoadMatrixf(mat); nuclear@11: } nuclear@4: glMultTransposeMatrixf(view_matrix[0]); nuclear@2: nuclear@2: draw_scene(); nuclear@2: } nuclear@2: nuclear@2: void game_reshape(int x, int y) nuclear@2: { nuclear@2: glViewport(0, 0, x, y); nuclear@2: fb_width = x; nuclear@2: fb_height = y; nuclear@6: nuclear@7: int lxres = vr_get_opti(VR_OPT_LEYE_XRES); nuclear@7: if(lxres) { nuclear@7: int lyres = vr_get_opti(VR_OPT_LEYE_YRES); nuclear@7: int rxres = vr_get_opti(VR_OPT_REYE_XRES); nuclear@7: int ryres = vr_get_opti(VR_OPT_REYE_YRES); nuclear@7: nuclear@7: rtwidth = lxres + rxres; nuclear@7: rtheight = lyres > ryres ? lyres : ryres; nuclear@7: } else { nuclear@7: rtwidth = x; nuclear@7: rtheight = y; nuclear@7: } nuclear@7: nuclear@7: setup_rtarg(rtwidth, rtheight); nuclear@2: } nuclear@2: nuclear@17: void game_keyboard(int key, bool pressed) nuclear@2: { nuclear@2: if(pressed) { nuclear@2: switch(key) { nuclear@2: case 27: nuclear@2: exit(0); nuclear@9: nuclear@9: case ' ': nuclear@9: vr_recenter(); nuclear@9: break; nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: if(key < 256) { nuclear@2: keystate[key] = pressed; nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: static int prev_x, prev_y; nuclear@2: static bool bnstate[32]; nuclear@2: nuclear@2: void game_mouse(int bn, bool pressed, int x, int y) nuclear@2: { nuclear@2: bnstate[bn] = pressed; nuclear@2: prev_x = x; nuclear@2: prev_y = y; nuclear@2: } nuclear@2: nuclear@2: void game_motion(int x, int y) nuclear@2: { nuclear@2: int dx = x - prev_x; nuclear@2: int dy = y - prev_y; nuclear@2: prev_x = x; nuclear@2: prev_y = y; nuclear@2: nuclear@2: if(!dx && !dy) return; nuclear@2: nuclear@2: if(bnstate[0]) { nuclear@2: float xrot = dy * 0.5; nuclear@2: float yrot = dx * 0.5; nuclear@2: cam.input_rotate(DEG_TO_RAD(xrot), 0, 0); nuclear@2: cam.input_rotate(0, DEG_TO_RAD(yrot), 0); nuclear@2: } nuclear@2: } nuclear@2: nuclear@3: void game_mwheel(int dir) nuclear@3: { nuclear@3: cam.input_move(0, dir * 0.1, 0); nuclear@3: } nuclear@3: nuclear@2: void game_6dof_move(float x, float y, float z) nuclear@2: { nuclear@2: cam.input_move(x, y, z); nuclear@2: } nuclear@2: nuclear@2: void game_6dof_rotate(float x, float y, float z) nuclear@2: { nuclear@2: cam.input_rotate(x, y, z); nuclear@2: } nuclear@2: nuclear@2: static void draw_scene() nuclear@2: { nuclear@2: float lpos[] = {-20, 30, 10, 1}; nuclear@2: glLightfv(GL_LIGHT0, GL_POSITION, lpos); nuclear@2: nuclear@2: glEnable(GL_TEXTURE_2D); nuclear@13: bind_texture(&floor_tex); nuclear@2: nuclear@2: glMatrixMode(GL_TEXTURE); nuclear@2: glScalef(8, 8, 8); nuclear@2: nuclear@2: glBegin(GL_QUADS); nuclear@2: glNormal3f(0, 1, 0); nuclear@2: glTexCoord2f(0, 0); glVertex3f(-25, 0, 25); nuclear@2: glTexCoord2f(1, 0); glVertex3f(25, 0, 25); nuclear@2: glTexCoord2f(1, 1); glVertex3f(25, 0, -25); nuclear@2: glTexCoord2f(0, 1); glVertex3f(-25, 0, -25); nuclear@2: glEnd(); nuclear@2: glDisable(GL_TEXTURE_2D); nuclear@2: glLoadIdentity(); nuclear@2: nuclear@2: glMatrixMode(GL_MODELVIEW); nuclear@2: nuclear@12: for(int i=0; i<4; i++) { nuclear@12: glPushMatrix(); nuclear@12: glTranslatef(i & 1 ? -10 : 10, 0, i & 2 ? -10 : 10); nuclear@15: draw_pyramid(2.0, 2.0); nuclear@12: glPopMatrix(); nuclear@12: } nuclear@2: } nuclear@6: nuclear@6: static bool setup_rtarg(int x, int y) nuclear@6: { nuclear@6: int tex_width = next_pow2(x); nuclear@6: int tex_height = next_pow2(y); nuclear@6: nuclear@6: /* create render targets for each eye */ nuclear@6: if(!fbo) { nuclear@6: glGenFramebuffers(1, &fbo); nuclear@6: glGenRenderbuffers(1, &rtarg_depth); nuclear@7: rtarg = new Texture; nuclear@6: } nuclear@6: nuclear@6: glBindFramebuffer(GL_FRAMEBUFFER, fbo); nuclear@6: nuclear@6: glBindRenderbuffer(GL_RENDERBUFFER, rtarg_depth); nuclear@6: glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, tex_width, tex_height); nuclear@6: glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtarg_depth); nuclear@6: nuclear@7: rtarg->create2d(tex_width, tex_height); nuclear@7: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, nuclear@7: rtarg->get_texture_id(), 0); nuclear@6: nuclear@6: if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { nuclear@6: fprintf(stderr, "incomplete framebuffer!\n"); nuclear@6: return false; nuclear@6: } nuclear@6: glBindFramebuffer(GL_FRAMEBUFFER, 0); nuclear@7: nuclear@7: printf("created render target %dx%d (texture: %dx%d)\n", x, y, tex_width, tex_height); nuclear@6: return true; nuclear@6: } nuclear@15: nuclear@15: static void draw_box(float sz) nuclear@15: { nuclear@15: float hsz = sz / 2.0; nuclear@15: nuclear@15: glBegin(GL_QUADS); nuclear@15: glNormal3f(0, 0, 1); nuclear@15: glVertex3f(-hsz, -hsz, hsz); nuclear@15: glVertex3f(hsz, -hsz, hsz); nuclear@15: glVertex3f(hsz, hsz, hsz); nuclear@15: glVertex3f(-hsz, hsz, hsz); nuclear@15: glNormal3f(1, 0, 0); nuclear@15: glVertex3f(hsz, -hsz, hsz); nuclear@15: glVertex3f(hsz, -hsz, -hsz); nuclear@15: glVertex3f(hsz, hsz, -hsz); nuclear@15: glVertex3f(hsz, hsz, hsz); nuclear@15: glNormal3f(0, 0, -1); nuclear@15: glVertex3f(hsz, -hsz, -hsz); nuclear@15: glVertex3f(-hsz, -hsz, -hsz); nuclear@15: glVertex3f(-hsz, hsz, -hsz); nuclear@15: glVertex3f(hsz, hsz, -hsz); nuclear@15: glNormal3f(-1, 0, 0); nuclear@15: glVertex3f(-hsz, -hsz, -hsz); nuclear@15: glVertex3f(-hsz, -hsz, hsz); nuclear@15: glVertex3f(-hsz, hsz, hsz); nuclear@15: glVertex3f(-hsz, hsz, -hsz); nuclear@15: glNormal3f(0, 1, 0); nuclear@15: glVertex3f(-hsz, hsz, hsz); nuclear@15: glVertex3f(hsz, hsz, hsz); nuclear@15: glVertex3f(hsz, hsz, -hsz); nuclear@15: glVertex3f(-hsz, hsz, -hsz); nuclear@15: glNormal3f(0, -1, 0); nuclear@15: glVertex3f(-hsz, -hsz, -hsz); nuclear@15: glVertex3f(hsz, -hsz, -hsz); nuclear@15: glVertex3f(hsz, -hsz, hsz); nuclear@15: glVertex3f(-hsz, -hsz, hsz); nuclear@15: glEnd(); nuclear@15: } nuclear@15: nuclear@15: static void draw_pyramid(float basesz, float height) nuclear@16: { nuclear@16: float hsz = basesz / 2.0; nuclear@16: float theta = atan(hsz / height); nuclear@16: float nx = cos(theta); nuclear@16: float ny = sin(theta); nuclear@16: nuclear@15: glBegin(GL_TRIANGLES); nuclear@15: glNormal3f(0, ny, nx); nuclear@15: glVertex3f(-hsz, 0, hsz); nuclear@15: glVertex3f(hsz, 0, hsz); nuclear@15: glVertex3f(0, height, 0); nuclear@15: glNormal3f(nx, ny, 0); nuclear@15: glVertex3f(hsz, 0, hsz); nuclear@15: glVertex3f(hsz, 0, -hsz); nuclear@15: glVertex3f(0, height, 0); nuclear@15: glNormal3f(0, ny, -nx); nuclear@15: glVertex3f(hsz, 0, -hsz); nuclear@15: glVertex3f(-hsz, 0, -hsz); nuclear@15: glVertex3f(0, height, 0); nuclear@15: glNormal3f(-nx, ny, 0); nuclear@15: glVertex3f(-hsz, 0, -hsz); nuclear@15: glVertex3f(-hsz, 0, hsz); nuclear@15: glVertex3f(0, height, 0); nuclear@15: glEnd(); nuclear@16: }