diff --git a/hypgraph.cpp b/hypgraph.cpp index 90fde66b..c3df74cf 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -403,7 +403,6 @@ EX void vr_sphere(hyperpoint& ret, hyperpoint& H, eModel md) { ld d = sqhypot_d(3, ret); ret /= abs(d); } - models::apply_vr(ret[2], ret[1]); } void vr_disk(hyperpoint& ret, hyperpoint& H) { @@ -431,8 +430,6 @@ void vr_disk(hyperpoint& ret, hyperpoint& H) { ret[1] = ax * H[1] / dd; ret[2] = ay; } - - models::apply_vr(ret[2], ret[1]); } EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { @@ -723,12 +720,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { } } - #if CAP_VR - if(vrhr::rendering()) { - models::apply_vr(ret[2], ret[1]); - return; - } - #endif + if(vrhr::rendering()) return; swap(ret[1], ret[2]); @@ -760,8 +752,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ld v = intval(H, Hypc); ret *= pow(v, (pconf.depth_scaling-1) / 2); } - models::apply_vr(ret[2], ret[1]); - break; + return; } #endif diff --git a/models.cpp b/models.cpp index 3a1d59e8..ddd2611c 100644 --- a/models.cpp +++ b/models.cpp @@ -120,7 +120,7 @@ EX namespace models { EX ld rotation_xy2 = 90; EX int do_rotate = 1; EX ld ocos, osin, ocos_yz, osin_yz; - EX ld cos_ball, sin_ball, cos_vr, sin_vr; + EX ld cos_ball, sin_ball; EX bool model_straight, model_straight_yz; #if HDR @@ -132,8 +132,6 @@ EX namespace models { void apply_orientation_yz(A& x, A& y) { if(!model_straight_yz) tie(x,y) = make_pair(x*ocos_yz + y*osin_yz, y*ocos_yz - x*osin_yz); } template void apply_ball(A& x, A& y) { tie(x,y) = make_pair(x*cos_ball + y*sin_ball, y*cos_ball - x*sin_ball); } - template - void apply_vr(A& x, A& y) { tie(x,y) = make_pair(x*cos_vr + y*sin_vr, y*cos_vr - x*sin_vr); } #endif EX transmatrix rotmatrix() { @@ -153,8 +151,6 @@ EX namespace models { EX void configure() { ld ball = -pconf.ballangle * degree; cos_ball = cos(ball), sin_ball = sin(ball); - ld vr = -pconf.vr_angle * degree; - cos_vr = cos(vr), sin_vr = sin(vr); ocos = cos(pconf.model_orientation * degree); osin = sin(pconf.model_orientation * degree); ocos_yz = cos(pconf.model_orientation_yz * degree); @@ -412,6 +408,8 @@ EX namespace models { } }; } + + bool set_vr_settings = true; EX void model_menu() { cmode = sm::SIDE | sm::MAYDARK | sm::CENTER; @@ -437,8 +435,16 @@ EX namespace models { dialog::lastItem().value += " " + its(rotation) + "°" + its(rotation_xz) + "°" + its(rotation_xy2) + "°"; dialog::add_action([] { edit_rotation(rotation); }); + bool vr_settings = vrhr::active() && set_vr_settings; + + if(vrhr::active()) { + dialog::addBoolItem_action(XLAT("edit VR or non-VR settings"), set_vr_settings, 'V'); + if(set_vr_settings) dialog::items.back().value = "VR"; + else dialog::items.back().value = "non-VR"; + } + // if(vpmodel == mdBand && sphere) - if(!in_perspective_v()) { + if(!in_perspective_v() && !vr_settings) { dialog::addSelItem(XLAT("scale factor"), fts(vpconf.scale), 'z'); dialog::add_action(editScale); } @@ -480,7 +486,7 @@ EX namespace models { }); } - if(GDIM == 3 && vpmodel != mdPerspective) { + if(GDIM == 3 && vpmodel != mdPerspective && !vr_settings) { const string cliphelp = XLAT( "Your view of the 3D model is naturally bounded from four directions by your window. " "Here, you can also set up similar bounds in the Z direction. Radius of the ball/band " @@ -535,7 +541,7 @@ EX namespace models { dialog::addBoolItem_action(XLAT("use atan to make it finite"), vpconf.use_atan, 'x'); } - if(vpmodel == mdBall) { + if(vpmodel == mdBall && !vr_settings) { dialog::addSelItem(XLAT("projection in ball model"), fts(vpconf.ballproj), 'x'); dialog::add_action([] () { dialog::editNumber(vpconf.ballproj, 0, 100, .1, 0, XLAT("projection in ball model"), @@ -562,11 +568,35 @@ EX namespace models { }); } - if(is_3d(vpconf) && GDIM == 2) { + if(is_3d(vpconf) && GDIM == 2 && !vr_settings) { dialog::addSelItem(XLAT("camera rotation in 3D models"), fts(vpconf.ballangle) + "°", 'b'); dialog::add_action(config_camera_rotation); } + if(vr_settings) { + dialog::addSelItem(XLAT("VR: rotate the 3D model"), fts(vpconf.vr_angle) + "°", 'B'); + dialog::add_action([] { + dialog::editNumber(vpconf.vr_angle, 0, 90, 5, 0, XLAT("VR: rotate the 3D model"), + "How the VR model should be rotated." + ); + }); + dialog::addSelItem(XLAT("VR: shift the 3D model"), fts(vpconf.vr_zshift), 'Z'); + dialog::add_action([] { + dialog::editNumber(vpconf.vr_zshift, 0, 5, 0.1, 1, XLAT("VR: shift the 3D model"), + "How the VR model should be shifted forward, in units. " + "The Poincaré disk has the size of 1 unit. You probably do not want this in perspective projections, but " + "it is useful to see e.g. the Poincaré ball not from the center." + ); + }); + dialog::addSelItem(XLAT("VR: scale the 3D model"), fts(vpconf.vr_scale_factor) + "m", 'S'); + dialog::add_action([] { + dialog::editNumber(vpconf.vr_scale_factor, 0, 5, 0.1, 1, XLAT("VR: scale the 3D model"), + "How the VR model should be scaled. At scale 1, 1 unit = 1 meter. Does not affect perspective projections, " + "where the 'absolute unit' setting is used instead." + ); + }); + } + if(vpmodel == mdHyperboloid) { dialog::addSelItem(XLAT("maximum z coordinate to show"), fts(vpconf.top_z), 'l'); dialog::add_action([](){ diff --git a/vr.cpp b/vr.cpp index c297f5fd..e2bae768 100644 --- a/vr.cpp +++ b/vr.cpp @@ -346,8 +346,8 @@ void track_all() { ld p = ilerp(h1[2], h2[2], -ui_depth); hyperpoint pxo = lerp(h1, h2, p); hyperpoint px = pxo; - px[0] /= ui_size; - px[1] /= -ui_size; + px[0] /= ui_size * ui_size_unit; + px[1] /= -ui_size * ui_size_unit; px[0] += current_display->xsize/2; px[1] += current_display->ysize/2; mousex = px[0]; @@ -755,7 +755,11 @@ EX void clear() { } EX ld ui_depth = 1.5; -EX ld ui_size = 0.002; +EX ld ui_size = 2; + +#if HDR +const ld ui_size_unit = 0.001; +#endif EX void in_vr_ui(reaction_t what) { @@ -778,8 +782,8 @@ EX void in_vr_ui(reaction_t what) { hmd_mvp = Id; hmd_mvp = xpush(-xsi/2) * ypush(-ysi/2) * hmd_mvp; transmatrix Sca = Id; - Sca[0][0] *= ui_size; - Sca[1][1] *= -ui_size; + Sca[0][0] *= ui_size * ui_size_unit; + Sca[1][1] *= -ui_size * ui_size_unit; Sca[2][2] *= 0; hmd_mvp = Sca * hmd_mvp; hmd_mvp = zpush(-ui_depth) * hmd_mvp; @@ -853,6 +857,8 @@ EX void gen_mv() { hmd_mv = NLP * hmd_mv; } hmd_mv = sm * hmd_mv; + + if(pconf.vr_angle) hmd_mv = cspin(1, 2, -pconf.vr_angle * degree) * hmd_mv; if(pconf.vr_zshift) hmd_mv = euclidean_translate(0, 0, -pconf.vr_zshift) * hmd_mv; hmd_mv = mu * hmd_mv; if(hsm == eHeadset::model_viewing) { @@ -1010,18 +1016,50 @@ EX void show_vr_settings() { "Elements of the HyperRogue world have fixed size in terms of absolute units, " "so reducing the absolute unit makes them smaller. " "If you are playing in the Euclidean mode, this feature just scales everything " - "(e.g., in the cube tiling, the 'absolute unit' is just the edge of the cube)." + "(e.g., in the cube tiling, the 'absolute unit' is just the edge of the cube). " + "Only perspective projections are affected, other models use the 'VR scale' setting " + "from the Projections menu." )); dialog::scaleLog(); }); + + dialog::addSelItem(XLAT("projection"), current_proj_name(), 'M'); + dialog::add_action_push(models::model_menu); - if(hsm == eHeadset::reference) { + if(among(hsm, eHeadset::reference, eHeadset::model_viewing)) { hyperpoint h = hmd_at * inverse(hmd_ref_at) * C0; dialog::addSelItem(XLAT("reset the reference point"), state ? fts(hypot_d(3, h)) + "m" : "", 'r'); dialog::add_action([] { hmd_ref_at = hmd_at; }); } else dialog::addBreak(100); + + dialog::addSelItem(XLAT("pointer length"), fts(pointer_length) + "m", 'p'); + dialog::add_action([] { + dialog::editNumber(pointer_length, 0, 2, 0.1, 1, XLAT("pointer length"), + XLAT( + "If the pointer length is 0.5m, the object pointed to is 0.5 meter from the controller. " + "This is used in situations where the controller is used as a 3D mouse, e.g., " + "the drawing tool in three-dimensional geometries. When pointing at two-dimensional surfaces, " + "this is not relevant (the pointer is as long as needed to hit the surface.)." + )); + }); + + dialog::addSelItem(XLAT("UI size"), fts(ui_size) + "mm", 'u'); + dialog::add_action([] { + dialog::editNumber(ui_size, 0, 10, 0.1, 2, XLAT("UI size"), + XLAT( + "How big is a pixel of the user interface (HUD and menus). The user interface is as big as the window on the desktop." + )); + }); + + dialog::addSelItem(XLAT("UI depth"), fts(ui_depth) + "m", 'U'); + dialog::add_action([] { + dialog::editNumber(ui_depth, 0, 2, 0.1, 1, XLAT("UI depth"), + XLAT( + "How far to show the user interface (HUD and menus)." + )); + }); dialog::addBack(); dialog::display(); @@ -1070,7 +1108,25 @@ auto hooka = addHook(hooks_args, 100, readArgs); #if CAP_CONFIG void addconfig() { addsaver(enabled, "vr-enabled"); - addparam(absolute_unit_in_meters, "vr-abs-unit"); + + addparamsaver(absolute_unit_in_meters, "vr-abs-unit"); + + addparamsaver(pconf.vr_scale_factor, "vr_scale"); + addparamsaver(pconf.vr_zshift, "vr_zshift"); + addparamsaver(pconf.vr_angle, "vr_angle"); + + auto& rconf = vid.rug_config; + addparamsaver(rconf.vr_scale_factor, "rug_vr_scale"); + addparamsaver(rconf.vr_zshift, "rug_vr_shift"); + addparamsaver(rconf.vr_angle, "rug_vr_angle"); + + addparamsaver(vrhr::pointer_length, "vr_pointer_length"); + addparamsaver(vrhr::ui_depth, "vr_ui_depth"); + addparamsaver(vrhr::ui_size, "vr_ui_size"); + + addsaverenum(vrhr::hsm, "vr-headset-mode"); + addsaverenum(vrhr::eyes, "vr-eyes-mode"); + addsaverenum(vrhr::cscr, "vr-screen-mode"); } auto hookc = addHook(hooks_configfile, 100, addconfig); #endif