X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=blobdiff_plain;f=src%2Fapp.cc;h=07ecdecaf0a43a3630f4f56e6ce65ea57a0852d2;hp=9a46f4ad46b9202902bb47c6de529bd28ec41a99;hb=5c69b226e45df981db338dd859ef1d95e9be8f96;hpb=dda1406df303fd1ec73344fbcce34c6197138642 diff --git a/src/app.cc b/src/app.cc index 9a46f4a..07ecdec 100644 --- a/src/app.cc +++ b/src/app.cc @@ -15,6 +15,7 @@ #include "opt.h" #include "post.h" #include "renderer.h" +#include "rtarg.h" #include "avatar.h" #include "vrinput.h" #include "exman.h" @@ -33,6 +34,7 @@ static Ray calc_pick_ray(int x, int y); long time_msec; int win_width, win_height; +int vp_width, vp_height; float win_aspect; bool fb_srgb; bool opt_gear_wireframe; @@ -40,10 +42,10 @@ bool opt_gear_wireframe; TextureSet texman; SceneSet sceneman; -unsigned int sdr_ltmap, sdr_ltmap_notex; - int fpexcept_enabled; +unsigned int dbg_key_pending; + static Avatar avatar; static float cam_dist = 0.0; @@ -80,10 +82,15 @@ ExSelection exsel_grab_left, exsel_grab_right; static ExhibitSlot exslot_left, exslot_right; #define exslot_mouse exslot_right +static bool pointing; + static Renderer *rend; +static RenderTarget *goatvr_rtarg; static Ray last_pick_ray; +static bool post_scene_init_pending = true; + bool app_init(int argc, char **argv) { @@ -120,6 +127,8 @@ bool app_init(int argc, char **argv) have_handtracking = goatvr_have_handtracking(); goatvr_recenter(); + + goatvr_rtarg = new RenderTarget; } if(fb_srgb) { @@ -164,34 +173,31 @@ bool app_init(int argc, char **argv) avatar.body_rot = rad_to_deg(acos(dot(dir, Vec3(0, 0, 1)))); exman = new ExhibitManager; - /* - if(!exman->load(mscn, "data/exhibits")) { - //return false; - } - */ + // exhibits are loaded in post_scene_init, because they need access to the scene graph + if(!exui_init()) { error_log("failed to initialize exhibit ui system\n"); return false; } exui_setnode(&exslot_left.node); - - if(!(sdr_ltmap_notex = create_program_load("sdr/lightmap.v.glsl", "sdr/lightmap-notex.p.glsl"))) { - return false; - } - set_uniform_int(sdr_ltmap_notex, "texmap", MTL_TEX_DIFFUSE); - set_uniform_int(sdr_ltmap_notex, "lightmap", MTL_TEX_LIGHTMAP); - - if(!(sdr_ltmap = create_program_load("sdr/lightmap.v.glsl", "sdr/lightmap-tex.p.glsl"))) { - return false; + if(have_handtracking) { + exui_scale(2); + exui_rotation(Vec3(-deg_to_rad(35), 0, 0)); } - set_uniform_int(sdr_ltmap, "texmap", MTL_TEX_DIFFUSE); - set_uniform_int(sdr_ltmap, "lightmap", MTL_TEX_LIGHTMAP); if(!fb_srgb) { sdr_post_gamma = create_program_load("sdr/post_gamma.v.glsl", "sdr/post_gamma.p.glsl"); } rend = new Renderer; + if(!rend->init()) { + return false; + } + if(opt.reflect) { + rend->ropt |= RENDER_MIRRORS; + } else { + rend->ropt &= ~RENDER_MIRRORS; + } rend->set_scene(mscn); glUseProgram(0); @@ -206,6 +212,17 @@ bool app_init(int argc, char **argv) return true; } +// post_scene_init is called after the scene has completed loading +static void post_scene_init() +{ + mscn->update(0); // update once to calculate node matrices + + int num_mir = mscn->calc_mirror_planes(); + info_log("found %d mirror planes\n", num_mir); + + exman->load(mscn, "data/exhibits"); +} + void app_cleanup() { if(mscn->music) { @@ -215,6 +232,7 @@ void app_cleanup() app_grab_mouse(false); if(opt.vr) { + delete goatvr_rtarg; goatvr_shutdown(); } destroy_vrhands(); @@ -257,9 +275,28 @@ static void update(float dt) texman.update(); sceneman.update(); + if(post_scene_init_pending && !sceneman.pending()) { + post_scene_init_pending = false; + post_scene_init(); + } + mscn->update(dt); exman->update(dt); - exui_update(dt); + + // use goatvr sticks for joystick input + int num_vr_sticks = goatvr_num_sticks(); + if(num_vr_sticks > 0) { + float p[2]; + goatvr_stick_pos(0, p); + joy_move.x = p[0]; + joy_move.y = -p[1]; + } + if(num_vr_sticks > 1) { + float p[2]; + goatvr_stick_pos(1, p); + joy_look.x = p[0]; + } + float speed = walk_speed * dt; Vec3 dir; @@ -274,8 +311,8 @@ static void update(float dt) jmove_lensq -= jdeadsq; float mag = len * len; - dir.x += mag * joy_move.x / len * 2.0 * speed; - dir.z += mag * joy_move.y / len * 2.0 * speed; + dir.x += mag * joy_move.x / len * speed; + dir.z += mag * joy_move.y / len * speed; } if(jlook_lensq > jdeadsq) { float len = sqrt(jlook_lensq); @@ -308,11 +345,8 @@ static void update(float dt) avatar.pos.y -= speed; } - float theta = M_PI * avatar.body_rot / 180.0f; - Vec3 newpos; - newpos.x = avatar.pos.x + cos(theta) * dir.x - sin(theta) * dir.z; - newpos.y = avatar.pos.y; - newpos.z = avatar.pos.z + sin(theta) * dir.x + cos(theta) * dir.z; + Vec3 walk_dir = avatar.calc_walk_dir(dir.z, dir.x); + Vec3 newpos = avatar.pos + walk_dir; if(noclip) { avatar.pos = newpos; @@ -339,6 +373,12 @@ static void update(float dt) floor_y = avatar.pos.y - user_eye_height; } + if(have_headtracking) { + Quat qhead; + goatvr_head_orientation(&qhead.x); + avatar.tracked_head_rotation(qhead); + } + // TODO move to the avatar system // calculate mouselook view matrix mouse_view_matrix = Mat4::identity; @@ -349,28 +389,108 @@ static void update(float dt) mouse_view_matrix.pre_rotate_y(deg_to_rad(avatar.body_rot)); mouse_view_matrix.pre_translate(-avatar.pos.x, -avatar.pos.y, -avatar.pos.z); - // check if an exhibit is hovered-over by mouse or 6dof (only if we don't have one grabbed) - if(!exsel_grab_mouse) { - // XXX note: using previous view/proj matrix lattency shouldn't be an issue but - // make sure state-creep doesn't get us - // XXX also this mouse-picking probably should only be active in non-VR mode - Ray ray = calc_pick_ray(prev_mx, prev_my); - exsel_hover = exman->select(ray); - } - // update hand-tracking if(have_handtracking) { update_vrhands(&avatar); + + ExSelection *exsel_grab[] = { &exsel_grab_left, &exsel_grab_right }; + ExhibitSlot *exslot[] = { &exslot_left, &exslot_right }; + + for(int i=0; i<2; i++) { + if(vrhand[i].valid) { + exslot[i]->node.set_position(vrhand[i].pos); + exslot[i]->node.set_rotation(vrhand[i].rot * exslot[i]->grab_rot); + + bool act_grab = goatvr_action(i, GOATVR_ACTION_GRAB) != 0; + + ExSelection sel; + sel = exman->select(Sphere(vrhand[i].pos, 10)); + + if(!*exsel_grab[i]) { + // we don't have an exhibit grabbed + if(act_grab) { + // grab an exhibit + *exsel_grab[i] = sel; + //SceneNode *objnode = sel.ex->node->find_object_node(); + //exslot[i]->rotation = normalize(sel.ex->node->get_rotation()); + exslot[i]->grab_rot = inverse(vrhand[i].rot); + exslot[i]->attach_exhibit(sel.ex, EXSLOT_ATTACH_TRANSIENT); + if(exsel_active) { + exsel_active = ExSelection::null; // cancel active on grab + } + } else { + // just hover + exsel_hover = sel; + } + } else { + // we have an exhibit grabbed + if(!act_grab) { + // drop it + Exhibit *ex = exsel_grab[i]->ex; + exslot[i]->detach_exhibit(); + + ExhibitSlot *slot = exman->nearest_empty_slot(vrhand[i].pos, 100); + if(!slot) { + debug_log("no empty slot nearby\n"); + if(ex->prev_slot && ex->prev_slot->empty()) { + slot = ex->prev_slot; + debug_log("using previous slot\n"); + } + } + + if(slot) { + Quat rot = normalize(exslot[i]->node.get_rotation()); + ex->node->set_rotation(rot); + slot->attach_exhibit(ex); + } else { + // nowhere to put it, stash it for later + exman->stash_exhibit(ex); + debug_log("no slots available, stashing\n"); + } + + *exsel_grab[i] = ExSelection::null; + exslot[i]->grab_rot = Quat::identity; + } + } + } + } + + // if there are no grabs, and we're pointing with the right finger, override active + if(!exsel_grab_left && !exsel_grab_right) { + if(goatvr_action(1, GOATVR_ACTION_POINT)) { + Ray ray; + ray.origin = vrhand[1].pos; + ray.dir = rotate(Vec3(0, 0, -1), vrhand[1].rot); + exsel_active = exman->select(ray); + pointing = true; + } else { + exsel_active = ExSelection::null; + pointing = false; + } + } + } else { + // check if an exhibit is hovered-over by mouse (only if we don't have one grabbed) + if(!exsel_grab_mouse) { + Ray ray = calc_pick_ray(prev_mx, prev_my); + exsel_hover = exman->select(ray); + } + // TODO do this properly // set the position of the left hand at a suitable position for the exhibit UI dir = rotate(Vec3(-0.46, -0.1, -1), Vec3(0, 1, 0), deg_to_rad(-avatar.body_rot)); exslot_left.node.set_position(avatar.pos + dir * 30); // magic: distance in front + Quat rot; + rot.set_rotation(Vec3(0, 1, 0), deg_to_rad(-avatar.body_rot)); + exslot_left.node.set_rotation(rot); } if(!exslot_right.empty()) exslot_right.node.update(dt); // always update the left slot, because it's the anchor point of the exhibit ui exslot_left.node.update(dt); + + // need to call this *after* we have updated the active exhibit (if any) + exui_update(dt); } void app_display() @@ -382,7 +502,7 @@ void app_display() ImGui::GetIOPtr()->DeltaTime = dt; ImGui::NewFrame(); - ImGui::ShowTestWindow(); + //ImGui::ShowTestWindow(); } glClearColor(1, 1, 1, 1); @@ -392,11 +512,23 @@ void app_display() goatvr_draw_start(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + unsigned int gfbo = goatvr_get_fbo(); + update(dt); for(int i=0; i<2; i++) { // for each eye goatvr_draw_eye(i); + if(gfbo) { + vp_width = goatvr_get_fb_eye_width(i); + vp_height = goatvr_get_fb_eye_height(i); + + // this is a lightweight operation + goatvr_rtarg->create_wrap_fbo(gfbo, vp_width, vp_height); + push_render_target(goatvr_rtarg, RT_FAKE); + } else { + vp_width = win_width / 2; + } proj_matrix = goatvr_projection_matrix(i, NEAR_CLIP, FAR_CLIP); glMatrixMode(GL_PROJECTION); @@ -407,16 +539,26 @@ void app_display() glLoadMatrixf(view_matrix[0]); draw_scene(); + /* if(have_handtracking) { draw_vrhands(); } + */ if(debug_gui) { ImGui::Render(); } + + if(gfbo) { + pop_render_target(RT_FAKE); + } } + goatvr_draw_done(); + vp_width = win_width; + vp_height = win_height; + if(should_swap) { app_swap_buffers(); } @@ -457,25 +599,28 @@ static void draw_scene() rend->draw(); exman->draw(); - /* if(have_handtracking) { - Mat4 head_xform = inverse(mouse_view_matrix);//goatvr_head_matrix(); - Mat4 head_dir_xform = head_xform.upper3x3(); - glUseProgram(0); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_LIGHTING); glBegin(GL_LINES); for(int i=0; i<2; i++) { - if(hand[i].valid) { + // skip drawing the left hand when we're showing the exhibit gui + if(exsel_active && i == 0) continue; + + if(vrhand[i].valid) { glColor3f(i, 1 - i, i); } else { glColor3f(0.5, 0.5, 0.5); } - Vec3 v = head_xform * hand[i].pos; - Vec3 dir = head_dir_xform * rotate(Vec3(0, 0, -1), hand[i].rot) * 20.0f; - Vec3 up = head_dir_xform * rotate(Vec3(0, 1, 0), hand[i].rot) * 10.0f; - Vec3 right = head_dir_xform * rotate(Vec3(1, 0, 0), hand[i].rot) * 10.0f; + Vec3 v = vrhand[i].pos; + Vec3 dir = rotate(Vec3(0, 0, -1), vrhand[i].rot) * 10.0f; + Vec3 up = rotate(Vec3(0, 1, 0), vrhand[i].rot) * 5.0f; + Vec3 right = rotate(Vec3(1, 0, 0), vrhand[i].rot) * 5.0f; + + if(i == 1 && pointing) { + dir *= 1000.0f; + } glVertex3f(v.x, v.y, v.z); glVertex3f(v.x + dir.x, v.y + dir.y, v.z + dir.z); @@ -487,7 +632,6 @@ static void draw_scene() glEnd(); glPopAttrib(); } - */ if(debug_gui && dbg_sel_node) { AABox bvol = dbg_sel_node->get_bounds(); @@ -525,6 +669,9 @@ void app_reshape(int x, int y) glViewport(0, 0, x, y); goatvr_set_fb_size(x, y, 1.0f); debug_gui_reshape(x, y); + + vp_width = x; + vp_height = y; } void app_keyboard(int key, bool pressed) @@ -614,8 +761,45 @@ void app_keyboard(int key, bool pressed) show_message("VR recenter\n"); break; - case 'x': - exman->load(mscn, "data/exhibits"); + case KEY_UP: + exui_scroll(-1); + break; + + case KEY_DOWN: + exui_scroll(1); + break; + + case KEY_LEFT: + exui_change_tab(-1); + break; + + case KEY_RIGHT: + exui_change_tab(1); + break; + + case '\t': + if(exsel_grab_mouse) { + Exhibit *ex = exsel_grab_mouse.ex; + exslot_mouse.detach_exhibit(); + exman->stash_exhibit(ex); + exsel_grab_mouse = ExSelection::null; + } else { + Exhibit *ex = exman->unstash_exhibit(); + if(ex) { + exslot_mouse.attach_exhibit(ex, EXSLOT_ATTACH_TRANSIENT); + exsel_grab_mouse = ex; + + Vec3 fwd = avatar.get_body_fwd(); + exslot_mouse.node.set_position(avatar.pos + fwd * 100); + } + } + break; + + case KEY_F5: + case KEY_F6: + case KEY_F7: + case KEY_F8: + dbg_key_pending |= 1 << (key - KEY_F5); break; } } @@ -668,12 +852,12 @@ void app_mouse_button(int bn, bool pressed, int x, int y) exslot_mouse.detach_exhibit(); - ExhibitSlot *slot = exman->nearest_empty_slot(pos, 100); + ExhibitSlot *slot = exman->nearest_empty_slot(pos, 300); if(!slot) { debug_log("no empty slot nearby\n"); if(ex->prev_slot && ex->prev_slot->empty()) { slot = ex->prev_slot; - debug_log("using previous slot"); + debug_log("using previous slot\n"); } } @@ -706,7 +890,7 @@ void app_mouse_button(int bn, bool pressed, int x, int y) static inline void mouse_look(float dx, float dy) { float scrsz = (float)win_height; - avatar.body_rot += dx * 512.0 / scrsz; + avatar.set_body_rotation(avatar.body_rot + dx * 512.0 / scrsz); avatar.head_alt += dy * 512.0 / scrsz; if(avatar.head_alt < -90) avatar.head_alt = -90;