From fb2a3a7931d06b68583da5ab177b31da1cbde785 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 10 Feb 2023 19:04:32 +0100 Subject: [PATCH] embeddings:: switching should now keep as much as possible --- config.cpp | 30 +++++++++++---------------- embeddings.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++---- geometry.cpp | 48 +++++++++++++++++++++++++++++++------------ 3 files changed, 98 insertions(+), 35 deletions(-) diff --git a/config.cpp b/config.cpp index 423b475c..2fd259c9 100644 --- a/config.cpp +++ b/config.cpp @@ -840,16 +840,16 @@ EX void initConfig() { param_f(geom3::euclid_embed_scale, "euclid_embed_scale", "euclid_embed_scale") -> editable(0, 2, 0.05, "Euclidean embedding scale", "How to scale the Euclidean map, relatively to the 3D absolute unit.", 'X') -> set_sets([] { dialog::bound_low(0.05); }) - -> set_reaction([] { if(vid.always3) { for(auto m: allmaps) m->on_dim_change(); }}); + -> set_reaction(geom3::apply_settings_full); param_f(geom3::euclid_embed_scale_y, "euclid_embed_scale_y", "euclid_embed_scale_y") -> editable(0, 2, 0.05, "Euclidean embedding scale Y/X", "This scaling factor affects only the Y coordinate.", 'Y') -> set_sets([] { dialog::bound_low(0.05); }) - -> set_reaction([] { if(vid.always3) { for(auto m: allmaps) m->on_dim_change(); }}); + -> set_reaction(geom3::apply_settings_full); param_f(geom3::euclid_embed_rotate, "euclid_embed_rotate", "euclid_embed_rotate") -> editable(0, 360, 15, "Euclidean embedding rotation", "How to rotate the Euclidean embedding, in degrees.", 'F') - -> set_reaction([] { if(vid.always3) { for(auto m: allmaps) m->on_dim_change(); }}); + -> set_reaction(geom3::apply_settings_full); param_enum(embedded_shift_method_choice, "embedded_shift_method", "embedded_shift_method", smcBoth) -> editable({ @@ -863,23 +863,15 @@ EX void initConfig() { param_b(geom3::inverted_embedding, "inverted_3d", false) -> editable("invert convex/concave", 'I') - -> set_reaction([] { if(vid.always3) { geom3::switch_fpp(); geom3::switch_fpp(); } }); + -> set_reaction(geom3::apply_settings_full); param_b(geom3::flat_embedding, "flat_3d", false) -> editable("flat, not equidistant", 'F') - -> set_reaction([] { if(vid.always3) { geom3::switch_fpp(); geom3::switch_fpp(); } }); + -> set_reaction(geom3::apply_settings_full); param_enum(geom3::spatial_embedding, "spatial_embedding", "spatial_embedding", geom3::seDefault) ->editable(geom3::spatial_embedding_options, "3D embedding method", 'E') - ->set_reaction([] { - if(vid.always3) { - geom3::switch_fpp(); - geom3::switch_fpp(); - delete_sky(); - // not sure why this is needed... - resetGL(); - } - }); + ->set_reaction(geom3::apply_settings_full); param_b(memory_saving_mode, "memory_saving_mode", (ISMOBILE || ISPANDORA || ISWEB) ? 1 : 0); param_i(reserve_limit, "memory_reserve", 128); @@ -2280,7 +2272,7 @@ EX void display_embedded_errors() { T0[1][0] = geometry == gEuclid ? 10 : 0; euc::eu_input.twisted = false; euc::build_torus3(); - geom3::switch_fpp(); geom3::switch_fpp(); start_game(); }); }); + geom3::apply_settings_full(); start_game(); }); }); return; } } @@ -2295,7 +2287,7 @@ EX void display_embedded_errors() { T0[0][1] = T0[1][0] = T0[1][1] = 0; euc::eu_input.twisted = false; euc::build_torus3(); - geom3::switch_fpp(); geom3::switch_fpp(); start_game(); }); }); + geom3::apply_settings_full(); start_game(); }); }); return; } } @@ -2626,7 +2618,8 @@ EX int config3 = addHook(hooks_configfile, 100, [] { "with parameter %2.", fts(current_camera_level), fts(tan_auto(vid.depth) / tan_auto(current_camera_level))); } dialog::addHelp(help); - }); + }) + ->set_reaction(geom3::apply_settings_light); param_f(vid.camera, "camera", "3D camera level", 1) ->editable(0, 5, .1, "", "", 'c') ->modif([] (float_setting* x) { x->menu_item_name = (GDIM == 2 ? "Camera level above the plane" : "Z shift"); }) @@ -2660,7 +2653,8 @@ EX int config3 = addHook(hooks_configfile, 100, [] { dialog::add_action([] () { vid.gp_autoscale_heights = !vid.gp_autoscale_heights; }); - }); + }) + ->set_reaction(geom3::apply_settings_light); param_f(vid.rock_wall_ratio, "rock_wall_ratio", "3D rock-wall ratio", .9) ->editable(0, 1, .1, "Rock-III to wall ratio", "", 'r') ->set_extra([] { dialog::addHelp(XLAT( diff --git a/embeddings.cpp b/embeddings.cpp index b9af6c0a..43f94d33 100644 --- a/embeddings.cpp +++ b/embeddings.cpp @@ -1113,13 +1113,60 @@ void embedding_method::set_radar_transform() { } EX void swapmatrix(transmatrix& T) { - if(embedded_plane) T = swapper->emb->base_to_actual(T); - else T = swapper->emb->actual_to_base(T); + if(geom3::swap_direction == +1) T = cgi.emb->base_to_actual(T); + if(geom3::swap_direction == -1) T = cgi.emb->actual_to_base(T); } EX void swappoint(hyperpoint& h) { - if(embedded_plane) h = swapper->emb->base_to_actual(h); - else h = swapper->emb->actual_to_base(h); + if(geom3::swap_direction == +1) h = cgi.emb->base_to_actual(h); + if(geom3::swap_direction == -1) h = cgi.emb->actual_to_base(h); + } + +struct embedded_matrix_data { + transmatrix saved; + hyperpoint logical_coordinates; + transmatrix rotation; + }; + +map mdata; + +EX void swapmatrix_iview(transmatrix& ori, transmatrix& V) { + indenter id(2); + if(geom3::swap_direction == -1) { + auto& data = mdata[&V]; + data.logical_coordinates = cgi.emb->intermediate_to_logical * cgi.emb->actual_to_intermediate(V*tile_center()); + data.rotation = inverse(cgi.emb->map_relative_push(V*tile_center())) * V; + + data.logical_coordinates[2] = ilerp(cgi.FLOOR, cgi.WALL, data.logical_coordinates[2]); + + if(nisot::local_perspective_used) data.rotation = data.rotation * ori; + swapmatrix(V); + data.rotation = data.rotation * cgi.emb->logical_scaled_to_intermediate; + data.saved = V; + } + if(geom3::swap_direction == 1) { + if(!mdata.count(&V)) { swapmatrix(V); ori = Id; return; } + auto& data = mdata[&V]; + if(!eqmatrix(data.saved, V)) { swapmatrix(V); ori = Id; return; } + data.logical_coordinates[2] = lerp(cgi.FLOOR, cgi.WALL, data.logical_coordinates[2]); + V = cgi.emb->intermediate_to_actual_translation( cgi.emb->logical_to_intermediate * data.logical_coordinates ); + ori = Id; + auto rot = data.rotation; + rot = rot * cgi.emb->intermediate_to_logical_scaled; + if(nisot::local_perspective_used) ori = ori * rot; + else V = V * rot; + } + } + +EX void swapmatrix_view(transmatrix& lp, transmatrix& V) { + if(!geom3::swap_direction) return; + if(geom3::swap_direction == +1) fix4(V); + V = inverse(V); + lp = inverse(lp); + swapmatrix_iview(lp, V); + if(geom3::swap_direction == -1) fix4(V); + V = inverse(V); + lp = inverse(lp); } void embedding_method::auto_configure() { diff --git a/geometry.cpp b/geometry.cpp index 42983631..3a044efe 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -1070,17 +1070,28 @@ EX namespace geom3 { EX namespace geom3 { + /** direction of swapping: +1 => from 2D to 3D; -1 => from 3D to 2D; 0 => make everything right */ + EX int swap_direction; + + EX void swapdim(int dir) { + swap_direction = dir; + decide_lpu(); + swapmatrix_view(NLP, View); + swapmatrix_view(NLP, current_display->which_copy); + callhooks(hooks_swapdim); + for(auto m: allmaps) m->on_dim_change(); + } + #if MAXMDIM >= 4 EX void switch_always3() { if(dual::split(switch_always3)) return; #if CAP_GL && CAP_RUG if(rug::rugged) rug::close(); #endif - swapper = &cgi; + if(vid.always3) swapdim(-1); vid.always3 = !vid.always3; apply_always3(); - swapmatrix(View); - callhooks(hooks_swapdim); + if(vid.always3) swapdim(+1); } #endif @@ -1121,14 +1132,10 @@ EX namespace geom3 { emb->auto_configure(); check_cgi(); cgi.prepare_basics(); - swapper = &cgi; - swapmatrix(View); - swapmatrix(current_display->which_copy); - callhooks(hooks_swapdim); - for(auto m: allmaps) m->on_dim_change(); + swapdim(+1); } else { - swapper = &cgi; + swapdim(-1); vid.always3 = false; apply_always3(); vid.wall_height = .3; @@ -1136,15 +1143,30 @@ EX namespace geom3 { vid.camera = 1; vid.depth = 1; if(among(pmodel, mdPerspective, mdGeodesic)) pmodel = mdDisk; - swapmatrix(View); - swapmatrix(current_display->which_copy); - callhooks(hooks_swapdim); - for(auto m: allmaps) m->on_dim_change(); + swapdim(0); } View = models::rotmatrix() * View; #endif } + EX void apply_settings_full() { + if(vid.always3) { + geom3::switch_fpp(); + delete_sky(); + // not sure why this is needed... + resetGL(); + geom3::switch_fpp(); + } + } + + EX void apply_settings_light() { + if(vid.always3) { + geom3::switch_always3(); + check_cgi(); cgi.prepare_basics(); + geom3::switch_always3(); + } + } + EX } EX geometry_information *cgip;