ExhibitSlots and exhibit placement (initial)
[laserbrain_demo] / src / app.cc
index 59d713c..8865012 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <limits.h>
 #include <assert.h>
 #include <goatvr.h>
 #include "app.h"
@@ -72,7 +73,11 @@ static ExhibitManager *exman;
 static BlobExhibit *blobs;
 static bool show_blobs;
 
-ExSelection exsel_grab, exsel_hover;
+ExSelection exsel_active, exsel_hover;
+ExSelection exsel_grab_left, exsel_grab_right;
+#define exsel_grab_mouse exsel_grab_right
+static ExhibitSlot exslot_left, exslot_right;
+#define exslot_mouse exslot_right
 
 static Renderer *rend;
 
@@ -221,6 +226,9 @@ void app_cleanup()
 
        delete rend;
 
+       /* this must be destroyed before the scene graph to detach exhibit nodes
+        * before the scene tries to delete them recursively
+        */
        delete exman;
 
        texman.clear();
@@ -333,7 +341,7 @@ static void update(float dt)
                floor_y = avatar.pos.y - user_eye_height;
        }
 
-       // TODO move to avatar
+       // TODO move to the avatar system
        // calculate mouselook view matrix
        mouse_view_matrix = Mat4::identity;
        mouse_view_matrix.pre_translate(0, 0, -cam_dist);
@@ -343,12 +351,17 @@ 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
-       // 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);
+       // 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);
+       }
+
+       if(!exslot_left.empty()) exslot_left.node.update(dt);
+       if(!exslot_right.empty()) exslot_right.node.update(dt);
 
        // update hand-tracking
        if(have_handtracking) {
@@ -601,6 +614,8 @@ void app_keyboard(int key, bool pressed)
 
 void app_mouse_button(int bn, bool pressed, int x, int y)
 {
+       static int press_x, press_y;
+
        if(debug_gui) {
                debug_gui_mbutton(bn, pressed, x, y);
                return; // ignore mouse events while GUI is visible
@@ -611,13 +626,64 @@ void app_mouse_button(int bn, bool pressed, int x, int y)
        bnstate[bn] = pressed;
 
        if(bn == 0) {
-               if(!pressed) {
-                       if(exsel_grab.ex) {
-                               exsel_grab.ex = 0;
-                       } else {
-                               Ray ray = calc_pick_ray(x, y);
-                               exsel_grab = exman->select(ray);
+               ExSelection sel;
+               Ray ray = calc_pick_ray(x, y);
+               sel = exman->select(ray);
+
+               if(pressed) {
+                       if(sel && (app_get_modifiers() & MOD_CTRL)) {
+                               exsel_grab_mouse = sel;
+                               Vec3 pos = sel.ex->node->get_position();
+                               debug_log("grabbing... (%g %g %g)\n", pos.x, pos.y, pos.z);
+                               exslot_mouse.node.set_position(pos);
+                               exslot_mouse.node.set_rotation(sel.ex->node->get_rotation());
+                               exslot_mouse.attach_exhibit(sel.ex, EXSLOT_ATTACH_TRANSIENT);
+                               if(exsel_active) {
+                                       exsel_active = ExSelection::null;       // cancel active on grab
+                               }
+                       }
+                       press_x = x;
+                       press_y = y;
+
+               } else {
+                       if(exsel_grab_mouse) {
+                               // cancel grab on mouse release
+                               debug_log("releasing...\n");
+                               Exhibit *ex = exsel_grab_mouse.ex;
+                               Vec3 pos = exslot_mouse.node.get_position();
+                               debug_log("release location: %g %g %g\n", pos.x, pos.y, pos.z);
+
+                               ExhibitSlot *slot = exman->nearest_empty_slot(pos);
+                               if(!slot) {
+                                       debug_log("no nearby slot\n");
+                                       if(ex->prev_slot && ex->prev_slot->empty()) {
+                                               slot = ex->prev_slot;
+                                               debug_log("previous slot available though\n");
+                                       }
+                               }
+
+                               if(slot) {
+                                       slot->attach_exhibit(ex);
+                               } else {
+                                       // nowhere to put it, so stash it for later
+                                       exslot_mouse.detach_exhibit();
+                                       exman->stash_exhibit(ex);
+                                       debug_log("no slots available, stashing\n");
+                               }
+
+                               exsel_grab_mouse = ExSelection::null;
                        }
+
+                       if(abs(press_x - x) < 5 && abs(press_y - y) < 5) {
+                               exsel_active = sel;     // select or deselect active exhibit
+                               if(sel) {
+                                       debug_log("selecting...\n");
+                               } else {
+                                       debug_log("deselecting...\n");
+                               }
+                       }
+
+                       press_x = press_y = INT_MIN;
                }
        }
 }
@@ -652,11 +718,11 @@ void app_mouse_motion(int x, int y)
 
        if(!dx && !dy) return;
 
-       if(exsel_grab.ex) {
-               Vec3 pos = exsel_grab.ex->node->get_node_position();
+       if(exsel_grab_mouse) {
+               Vec3 pos = exslot_mouse.node.get_node_position();
                Vec3 dir = transpose(view_matrix.upper3x3()) * Vec3(dx * 1.0, dy * -1.0, 0);
 
-               exsel_grab.ex->node->set_position(pos + dir);
+               exslot_mouse.node.set_position(pos + dir);
        }
 
        if(bnstate[2]) {