diff --git a/3d-models.cpp b/3d-models.cpp index 0361d72c..1ad8dc12 100644 --- a/3d-models.cpp +++ b/3d-models.cpp @@ -34,9 +34,8 @@ vector geometry_information::get_shape(hpcshape sh) { hyperpoint get_center(const vector& vh) { hyperpoint h = Hypc; for(auto h1: vh) h = h + h1; - if(geom3::euc_in_product()) return h / isize(vh); - if(geom3::euc_cylinder()) h /= isize(vh); - return normalize_flat(h); + h /= isize(vh); + return cgi.emb->normalize_flat(h); } EX ld zc(ld z) { @@ -129,7 +128,7 @@ void geometry_information::add_texture(hpcshape& sh) { vector scaleshape(const vector& vh, ld s) { vector res; - for(hyperpoint h: vh) res.push_back(normalize_flat(h * s + shcenter * (1-s))); + for(hyperpoint h: vh) res.push_back(cgi.emb->normalize_flat(h * s + shcenter * (1-s))); return res; } @@ -156,13 +155,15 @@ void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) { auto body26 = body[26]; body.clear(); + auto& T = cgi.emb->intermediate_to_logical; + bool foundplus = false, foundminus = false; for(hyperpoint h: fullbody) { - if(h[1] > 0.14 * S) { + if((T*h)[1] > 0.14 * S) { if(foundplus) ; else foundplus = true, body.push_back(body7); } - else if(h[1] < -0.14 * S) { + else if((T*h)[1] < -0.14 * S) { if(foundminus) ; else foundminus = true, body.push_back(body26); } @@ -173,19 +174,20 @@ void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) { bool armused = false; arm.clear(); for(hyperpoint h: fullbody) { - if(h[1] < 0.08 * S) ; - else if(h[0] > -0.03 * S) { + if((T*h)[1] < 0.08 * S) ; + else if((T*h)[0] > -0.03 * S) { if(armused) ; else armused = true, arm.push_back(arm8); } else arm.push_back(h); } - + auto hand0 = hand[0]; hand.clear(); hand.push_back(hand0); for(hyperpoint h: fullbody) { - if(h[1] + h[0] > 0.13 * S) hand.push_back(h); + auto h1 = T*h; + if(h1[1] + h1[0] > 0.13 * S) hand.push_back(h); } bshape(sh, PPR::MONSTER_BODY); @@ -261,7 +263,7 @@ void geometry_information::addtri(array hs, int kind) { bool ok = true; ld zzes[3]; for(int s=0; s<3; s++) { - hs[s] = normalize_flat(hs[s]); + hs[s] = cgi.emb->normalize_flat(hs[s]); hyperpoint h = hs[s]; ld zz = zc(0.78); hsh[s] = abs(h[1]); @@ -269,7 +271,7 @@ void geometry_information::addtri(array hs, int kind) { zz -= h[0] * h[0] / 0.10 / 0.10 * 0.01 / S / S * SH; if(abs(h[1]) > 0.14*S) ok = false, zz -= revZ * (abs(h[1])/S - 0.14) * SH; if(abs(h[0]) > 0.08*S) ok = false, zz -= revZ * (abs(h[0])/S - 0.08) * (abs(h[0])/S - 0.08) * 25 * SH; - h = normalize_flat(h); + h = cgi.emb->normalize_flat(h); if(!gproduct || kind != 1) ht[s] = lzpush(zz) * h; else ht[s] = h; if(hsh[s] < 0.1*S) shi[s] = 0.5; @@ -494,10 +496,10 @@ void geometry_information::make_skeletal(hpcshape& sh, ld push) { hyperpoint yzspin(ld alpha, hyperpoint h) { if(gproduct) return product::direct_exp(cspin(1, 2, alpha) * product::inverse_exp(h)); - else if(embedded_plane && moved_center()) { - h = gpushxto0(tile_center()) * h; + else if(embedded_plane && cgi.emb->center_z()) { + h = gpushxto0(cgi.emb->tile_center()) * h; h = cspin(1, 2, alpha) * h; - h = rgpushxto0(tile_center()) * h; + h = rgpushxto0(cgi.emb->tile_center()) * h; return h; } else return cspin(1, 2, alpha) * h; @@ -564,7 +566,7 @@ void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push, for(int i=0; inormalize_flat(gbody[lastid[i]] * (i - lastid[i]) + gbody[nextid[i]] * (nextid[i] - i)); } bshape(sh, PPR::MONSTER_BODY); @@ -633,7 +635,7 @@ void geometry_information::slimetriangle(hyperpoint a, hyperpoint b, hyperpoint dynamicval d(vid.texture_step, 8); ld sca = 1; if(mhybrid) sca = .5; - if(geom3::euc_in_noniso()) sca *= .3; + if(cgi.emb->is_euc_in_noniso()) sca *= .3; texture_order([&] (ld x, ld y) { ld z = 1-x-y; ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8) * sca; @@ -747,8 +749,8 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye hyperpoint center = Hypc; int c = 0; for(int i=eye.s; i 0) center += hpc[i], c++; - if(geom3::euc_in_product()) center /= c; - else center = normalize_flat(center); + center /= c; + center = cgi.emb->normalize_flat(center); // center /= (eye.e - eye.s); ld rad = 0; for(int i=eye.s; i 0) rad += hdist(center, hpc[i]); @@ -761,7 +763,7 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye vector pss; - for(int i=head.s; icenter_z()) * hpc[i])); ld zmid = 0; for(hyperpoint& h: pss) zmid += h[2]; diff --git a/arbitrile.cpp b/arbitrile.cpp index 917348d3..8cec9925 100644 --- a/arbitrile.cpp +++ b/arbitrile.cpp @@ -2136,7 +2136,7 @@ EX void swap_vertices() { for(auto& p: {¤t, &slided}) for(auto& s: p->shapes) for(auto& v: s.vertices) - swapmatrix(v); + swappoint(v); } #if MAXMDIM >= 4 diff --git a/cell.cpp b/cell.cpp index f4bb307e..fdcd217f 100644 --- a/cell.cpp +++ b/cell.cpp @@ -51,7 +51,7 @@ public: virtual transmatrix spin_to(cell *c, int d, ld bonus=0); virtual transmatrix spin_from(cell *c, int d, ld bonus=0); - virtual double spacedist(cell *c, int i) { return hdist(tile_center(), adj(c, i) * tile_center()); } + virtual double spacedist(cell *c, int i); virtual bool strict_tree_rules() { return false; } @@ -118,6 +118,8 @@ struct hrmap_hyperbolic : hrmap_standard { }; #endif +double hrmap::spacedist(cell *c, int i) { return hdist(tile_center(), adj(c, i) * tile_center()); } + heptagon *hrmap::create_step(heptagon *h, int direction) { throw hr_exception("create_step called unexpectedly"); return NULL; @@ -404,8 +406,12 @@ EX bool is_in_disk(cell *c) { EX void initcells() { DEBB(DF_INIT, ("initcells")); - if(embedded_plane) return IPF( initcells() ); - + if(embedded_plane) { + IPF(initcells()); + currentmap->on_dim_change(); + return; + } + hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap); if(res) currentmap = res; #if CAP_SOLV diff --git a/celldrawer.cpp b/celldrawer.cpp index 34467094..9fed4159 100644 --- a/celldrawer.cpp +++ b/celldrawer.cpp @@ -1919,7 +1919,7 @@ void celldrawer::check_rotations() { else ds.total += unshift(tC0(V)); ds.qty++; - ds.point = normalize_flat(ds.total); + ds.point = cgi.emb->normalize_flat(ds.total); if(mproduct) ds.point = orthogonal_move(ds.point, ds.depth / ds.qty); if(side == 2) for(int i=0; i<3; i++) ds.point[i] = -ds.point[i]; if(side == 1) ds.point = spin(-90._deg) * ds.point; diff --git a/config.cpp b/config.cpp index 52ffb9aa..e9b52270 100644 --- a/config.cpp +++ b/config.cpp @@ -2365,7 +2365,7 @@ EX void show3D() { } if(WDIM == 2) { - if(geom3::euc_in_noniso()) { + if(cgi.emb->is_euc_in_noniso()) { add_edit(geom3::euclid_embed_scale); add_edit(geom3::euclid_embed_scale_y); add_edit(geom3::euclid_embed_rotate); diff --git a/control.cpp b/control.cpp index febfb9f6..1030141c 100644 --- a/control.cpp +++ b/control.cpp @@ -83,7 +83,7 @@ EX bool mouseout2() { EX movedir vectodir(hyperpoint P) { transmatrix U = unshift(ggmatrix(cwt.at)); - if(embedded_plane && geom3::same_in_same()) U = current_display->radar_transform * U; + if(embedded_plane && cgi.emb->is_same_in_same()) U = current_display->radar_transform * U; P = direct_exp(lp_iapply(P)); @@ -123,7 +123,7 @@ EX void remission() { } EX hyperpoint move_destination_vec(int d) { - if(WDIM == 2 && (!embedded_plane || geom3::same_in_same())) return spin(-d * 45._deg) * smalltangent(); + if(WDIM == 2 && (!embedded_plane || cgi.emb->is_same_in_same())) return spin(-d * 45._deg) * smalltangent(); else if(d&1) return cspin(0, 1, d > 4 ? 45._deg : -45._deg) * smalltangent(); else return cspin(0, 2, d * 45._deg) * smalltangent(); } diff --git a/drawing.cpp b/drawing.cpp index dc20ee6e..25b59b32 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -2456,7 +2456,7 @@ EX void drawqueue() { #endif #if MAXMDIM >= 4 && CAP_GL - if(embedded_plane && (hyperbolic || geom3::sph_in_euc() || geom3::euc_in_noniso() || geom3::hyp_in_solnih()) && !vrhr::rendering()) make_air(); + if(embedded_plane && (hyperbolic || cgi.emb->is_sph_in_low() || cgi.emb->is_in_noniso()) && !vrhr::rendering()) make_air(); #endif #if CAP_VR diff --git a/embeddings.cpp b/embeddings.cpp new file mode 100644 index 00000000..8385c2dc --- /dev/null +++ b/embeddings.cpp @@ -0,0 +1,955 @@ +#include "hyper.h" + +namespace hr { + +EX namespace geom3 { + #if HDR + enum eSpatialEmbedding { + seNone, + seDefault, + seLowerCurvature, + seMuchLowerCurvature, + seProduct, + seNil, + seSol, seNIH, seSolN, + seCliffordTorus, + seProductH, + seProductS, + seSL2, + seCylinderE, + seCylinderH, + seCylinderHE, + seCylinderHoro, + seCylinderNil + }; + #endif + + EX vector> spatial_embedding_options = { + {"2D engine", "Use HyperRogue's 2D engine to simulate same curvature. Works well in top-down and third-person perspective. The Hypersian Rug mode can be used to project this to a surface."}, + {"same curvature", "Embed as an equidistant surface in the 3D version of the same geometry."}, + {"lower curvature", "Embed as a surface in a space of lower curvature."}, + {"much lower curvature", "Embed sphere as a sphere in hyperbolic space."}, + {"product", "Add one extra dimension in the Euclidean way."}, + {"Nil", "Embed Euclidean plane into Nil."}, + {"Sol", "Embed Euclidean or hyperbolic plane into Sol."}, + {"stretched hyperbolic", "Embed Euclidean or hyperbolic plane into stretched hyperbolic geometry."}, + {"stretched Sol", "Embed Euclidean or hyperbolic plane into stretched Sol geometry."}, + {"Clifford Torus", "Embed Euclidean rectangular torus into S3."}, + {"hyperbolic product", "Embed Euclidean or hyperbolic plane in the H2xR product space."}, + {"spherical product", "Embed Euclidean cylinder or spherical plane in the H2xR product space."}, + {"SL(2,R)", "Embed Euclidean plane in twisted product geometry."}, + {"cylinder", "Embed Euclidean cylinder in Euclidean space."}, + {"hyperbolic cylinder", "Embed Euclidean cylinder in hyperbolic space."}, + {"product cylinder", "Embed Euclidean cylinder in H2xR space."}, + {"Nil cylinder", "Embed Euclidean cylinder in Nil."}, + {"horocylinder", "Embed Euclidean as a horocylinder in H2xR space."}, + }; + + EX eSpatialEmbedding spatial_embedding = seDefault; + EX ld euclid_embed_scale = 1; + EX ld euclid_embed_scale_y = 1; + EX ld euclid_embed_rotate = 0; + EX bool auto_configure = true; + EX bool flat_embedding = false; + EX bool inverted_embedding = false; + + EX ld euclid_embed_scale_mean() { return euclid_embed_scale * sqrt(euclid_embed_scale_y); } + EX void set_euclid_embed_scale(ld x) { euclid_embed_scale = x; euclid_embed_scale_y = 1; euclid_embed_rotate = 0; } + + EX bool supports_flat() { return among(spatial_embedding, seDefault, seProductH, seProductS); } + EX bool supports_invert() { return among(spatial_embedding, seDefault, seLowerCurvature, seMuchLowerCurvature, seNil, seSol, seNIH, seSolN, seProductH, seProductS); } + + EX vector ginf_backup; + + EX eGeometryClass mgclass() { + return (embedded_plane ? ginf_backup : ginf)[geometry].g.kind; + } + + EX eGeometryClass ggclass() { + return (flipped ? ginf_backup : ginf)[geometry].g.kind; + } + + EX bool any_cylinder(eSpatialEmbedding e) { + return among(e, seCylinderE, seCylinderH, seCylinderHE, seCylinderHoro, seCylinderNil); + } + + EX bool in_product() { + return ggclass() == gcProduct; + } + + EX bool flipped; + + EX geometry_information* unflipped; + + EX void light_flip(bool f) { + if(f != flipped) { + if(!flipped) unflipped = cgip; + swap(ginf[geometry].g, geom3::ginf_backup[geometry].g); + swap(ginf[geometry].flags, geom3::ginf_backup[geometry].flags); + if(!flipped) cgip = unflipped; + flipped = f; + } + } + + #if HDR + template auto in_flipped(const T& f) -> decltype(f()) { + light_flip(true); + finalizer ff([] { light_flip(false); }); + return f(); + } + + template auto in_not_flipped(const T& f) -> decltype(f()) { + light_flip(false); + finalizer ff([] { light_flip(true); }); + return f(); + } + + #define IPF(x) geom3::in_flipped([&] { return (x); }) + #endif + + EX void apply_always3() { + if(!vid.always3 && !ginf_backup.empty()) { + ginf = ginf_backup; + ginf_backup.clear(); + } + if(vid.always3 && ginf_backup.empty()) { + ginf_backup = ginf; + for(geometryinfo& gi: ginf) { + auto &g = gi.g; + if(vid.always3 && g.gameplay_dimension == 2 && g.graphical_dimension == 2) { + g.graphical_dimension++; + g.homogeneous_dimension++; + g.sig[3] = g.sig[2]; + g.sig[2] = g.sig[1]; + + if(among(spatial_embedding, seProduct, seProductH, seProductS) && g.kind != gcEuclid) { + g.kind = gcProduct; + g.homogeneous_dimension--; + g.sig[2] = g.sig[3]; + } + + if(among(spatial_embedding, seProductH, seProductS) && g.kind == gcEuclid) { + g.kind = gcProduct; + g.homogeneous_dimension--; + g.sig[2] = spatial_embedding == seProductH ? -1 : 1; + } + + if(spatial_embedding == seLowerCurvature) { + if(g.kind == gcEuclid) g = ginf[gSpace534].g; + if(g.kind == gcSphere) g = ginf[gCubeTiling].g; + g.gameplay_dimension = 2; + } + + if(spatial_embedding == seMuchLowerCurvature) { + g = ginf[gSpace534].g; + g.gameplay_dimension = 2; + } + + bool ieuclid = g.kind == gcEuclid; + + if(spatial_embedding == seNil && ieuclid) { + g = ginf[gNil].g; + g.gameplay_dimension = 2; + } + + if(spatial_embedding == seCliffordTorus && ieuclid) { + g = ginf[gCell120].g; + g.gameplay_dimension = 2; + } + + bool ieuc_or_binary = ieuclid || (gi.flags & qBINARY); + + if(spatial_embedding == seSol && ieuc_or_binary) { + g = ginf[gSol].g; + g.gameplay_dimension = 2; + } + + if(spatial_embedding == seNIH && ieuc_or_binary) { + g = ginf[gNIH].g; + g.gameplay_dimension = 2; + } + + if(spatial_embedding == seSolN && ieuc_or_binary) { + g = ginf[gSolN].g; + g.gameplay_dimension = 2; + } + + if(spatial_embedding == seSL2 && ieuclid) { + g = giSL2; + g.gameplay_dimension = 2; + } + + if(spatial_embedding == seCylinderH && ieuclid) { + g = ginf[gSpace534].g; + g.gameplay_dimension = 2; + } + } + } + } + } + + EX void configure_clifford_torus() { + rug::clifford_torus ct; + + if(hypot_d(2, ct.xh) < 1e-6 || hypot_d(2, ct.yh) < 1e-6) { + euclid_embed_scale = TAU / 20.; + euclid_embed_scale_y = 1; + euclid_embed_rotate = 0; + vid.depth = 45._deg - 1; + vid.wall_height = 0.2; + vid.eye = vid.wall_height / 2 - vid.depth; + return; + } + + euclid_embed_scale = TAU / hypot_d(2, ct.xh); + euclid_embed_scale_y = TAU / hypot_d(2, ct.yh) / euclid_embed_scale; + euclid_embed_rotate = atan2(ct.xh[1], ct.xh[0]) / degree; + + ld alpha = atan2(ct.xfactor, ct.yfactor); + + vid.depth = alpha - 1; + vid.wall_height = min(1 / euclid_embed_scale_mean(), (90._deg - alpha) * 0.9); + vid.eye = vid.wall_height / 2 - vid.depth; + } + + EX void configure_cylinder() { + rug::clifford_torus ct; + hyperpoint vec; + if(sqhypot_d(2, ct.yh) > 1e-6) vec = ct.yh; + else if(sqhypot_d(2, ct.xh) > 1e-6) vec = ct.xh; + else vec = hyperpoint(10, 0, 0, 0); + + euclid_embed_scale = TAU / hypot_d(2, vec); + euclid_embed_scale_y = 1; + euclid_embed_rotate = atan2(vec[1], vec[0]) / degree; + } + +EX } + + #if HDR + struct embedding_method { + virtual ld center_z() { return 0; } + virtual hyperpoint tile_center() { ld z = center_z(); if(z == 0) return C0; else return zpush0(z); } + virtual transmatrix intermediate_to_actual_translation(hyperpoint i) = 0; + virtual hyperpoint intermediate_to_actual(hyperpoint i) { return intermediate_to_actual_translation(i) * tile_center(); } + virtual hyperpoint actual_to_intermediate(hyperpoint a) = 0; + virtual hyperpoint orthogonal_move(const hyperpoint& a, ld z); + virtual transmatrix map_relative_push(hyperpoint h); + virtual ld get_logical_z(hyperpoint a) { return (intermediate_to_logical_scaled * actual_to_intermediate(a))[2]; } + virtual hyperpoint logical_to_actual(hyperpoint l) { return intermediate_to_actual(logical_to_intermediate * l); } + virtual hyperpoint base_to_actual(hyperpoint h) = 0; + virtual transmatrix base_to_actual(const transmatrix &T) = 0; + virtual hyperpoint actual_to_base(hyperpoint h) = 0; + virtual transmatrix actual_to_base(const transmatrix &T) = 0; + virtual hyperpoint normalize_flat(hyperpoint a) { return flatten(normalize(a)); } + virtual hyperpoint flatten(hyperpoint a) { auto i = actual_to_intermediate(a); auto l = intermediate_to_logical * i; l[2] = center_z(); i = logical_to_intermediate * l; return intermediate_to_actual(i); } + virtual transmatrix get_radar_transform(const transmatrix& V); + virtual transmatrix get_lsti() { return Id; } + virtual transmatrix get_lti() { return logical_scaled_to_intermediate; } + + virtual bool is_euc_in_product() { return false; } + virtual bool is_product_embedding() { return false; } + virtual bool is_euc_in_sl2() { return false; } + virtual bool is_same_in_same() { return false; } + virtual bool is_sph_in_low() { return false; } + virtual bool is_hyp_in_solnih() { return false; } + virtual bool is_euc_in_hyp() { return false; } + virtual bool is_euc_in_sph() { return false; } + virtual bool is_euc_in_nil() { return false; } + virtual bool is_euc_in_noniso() { return false; } + virtual bool is_in_noniso() { return false; } + virtual bool is_depth_limited() { return false; } + virtual bool is_cylinder() { return false; } + virtual bool no_spin() { return false; } + + /* convert the tangent space in logical coordinates to actual coordinates */ + transmatrix logical_to_intermediate; + + /* convert the tangent space in actual coordinates to logical coordinates */ + transmatrix intermediate_to_logical; + + /* convert the tangent space in logical coordinates to actual coordinates */ + transmatrix logical_scaled_to_intermediate; + + /* convert the tangent space in actual coordinates to logical coordinates */ + transmatrix intermediate_to_logical_scaled; + + void prepare_lta(); + void auto_configure(); + }; + + #endif + +EX geometry_information *swapper; + +struct auaua : embedding_method { int z; }; + +transmatrix embedding_method::map_relative_push(hyperpoint a) { + auto i = actual_to_intermediate(a); + return intermediate_to_actual_translation(i); + } + +hyperpoint embedding_method::orthogonal_move(const hyperpoint& a, ld z) { + auto i = actual_to_intermediate(a); + auto l = intermediate_to_logical_scaled * i; + l[2] += z; + i = logical_scaled_to_intermediate * l; + return intermediate_to_actual(i); + } + +/** dummy 'embedding method' used when no embedding is used (2D engine or 3D map) */ + +struct emb_none : embedding_method { + hyperpoint actual_to_intermediate(hyperpoint a) override { return a; } + hyperpoint intermediate_to_actual(hyperpoint i) override { return i; } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { return rgpushxto0(i); } + transmatrix base_to_actual(const transmatrix& T) override { return T; } + hyperpoint base_to_actual(hyperpoint h) override { return h; } + transmatrix actual_to_base(const transmatrix& T) override { return T; } + hyperpoint actual_to_base(hyperpoint h) override { return h; } + hyperpoint orthogonal_move(const hyperpoint& h, ld z) { + if(GDIM == 2) return scale_point(h, geom3::scale_at_lev(z)); + if(gproduct) return scale_point(h, exp(z)); + if(sl2) return slr::translate(h) * cpush0(2, z); + if(nil) return nisot::translate(h) * cpush0(2, z); + if(translatable) return hpxy3(h[0], h[1], h[2] + z); + /* copied from emb_same_in_same */ + ld u = 1; + if(h[2]) z += asin_auto(h[2]), u /= cos_auto(asin_auto(h[2])); + u *= cos_auto(z); + return hpxy3(h[0] * u, h[1] * u, sinh(z)); + } + }; + +/** embed in the 3D variant of the same geometry */ + +struct emb_same_in_same : auaua { + virtual bool is_same_in_same() { return true; } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { return rgpushxto0(i); } + hyperpoint actual_to_intermediate(hyperpoint a) override { return a; } + hyperpoint flatten(hyperpoint h) override { if(abs(h[2]) > 1e-6) println(hlog, "h2 = ", h[2]); return h; } + hyperpoint orthogonal_move(const hyperpoint& h, ld z) override { + ld u = 1; + if(h[2]) z += asin_auto(h[2]), u /= cos_auto(asin_auto(h[2])); + u *= cos_auto(z); + return hpxy3(h[0] * u, h[1] * u, sinh(z)); + } + transmatrix base_to_actual(const transmatrix &T0) override { + auto T = T0; + for(int i=0; i<4; i++) T[i][3] = T[i][2], T[i][2] = 0; + for(int i=0; i<4; i++) T[3][i] = T[2][i], T[i][2] = 0; + for(int i=0; i<4; i++) T[i][2] = T[2][i] = 0; + T[2][2] = 1; + return T; + } + transmatrix actual_to_base(const transmatrix &T0) override { + auto T = T0; + for(int i=0; i<4; i++) T[i][2] = T[i][3], T[i][3] = 0; + for(int i=0; i<4; i++) T[2][i] = T[3][i], T[i][3] = 0; + T[3][3] = 1; + fixmatrix(T); + for(int i=0; i 0 ? 1 : -1); + ld x = -asinh(S); + h = lorentz(0, 3, -x) * lorentz(1, 2, x) * h; + ld y = h[3]*h[3] > h[2]*h[2] ? atanh(h[1] / h[3]) : atanh(h[0] / h[2]); + h = lorentz(0, 2, -y) * lorentz(1, 3, -y) * h; + ld z = atan2(h[2], h[3]); + return hyperpoint(x, y, z, 0); + } + + bool is_euc_in_sl2() override { return true; } + bool no_spin() override { return true; } + transmatrix get_lsti() override { return cspin90(2, 1); } + hyperpoint actual_to_intermediate(hyperpoint a) override { return esl2_ati(a); } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { return esl2_zpush(i[2]) * xpush(i[0]) * ypush(i[1]); } + + ld get_logical_z(hyperpoint a) override { return esl2_ati(a)[1]; } + hyperpoint orthogonal_move(const hyperpoint& a, ld z) override { + hyperpoint h1 = esl2_ati(a); + h1[1] += z; + return esl2_ita0(h1); + } + hyperpoint flatten(hyperpoint h) { + hyperpoint h1 = esl2_ati(h); + h1[1] = 0; + return esl2_ita0(h1); + } + }; + +struct emb_euc_cylinder : emb_euclid_noniso { + bool is_cylinder() override { return true; } + ld center_z() override { return 1; } + bool is_depth_limited() override { return true; } + transmatrix get_lsti() override { return cspin90(0, 1); } + hyperpoint actual_to_intermediate(hyperpoint a) override { + ld z0 = hypot(a[1], a[2]); + ld x0 = a[0]; + if(hyperbolic) x0 = asinh(x0 / acosh(z0)); + ld y0 = z0 ? atan2(a[1], a[2]) : 0; + return hyperpoint(x0, y0, z0, 1); + } + ld get_logical_z(hyperpoint a) override { return hypot(a[1], a[2]) - 1; } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { + return xpush(i[0]) * cspin(1, 2, i[1]) * zpush(i[2]); + } + hyperpoint orthogonal_move(const hyperpoint& a, ld z) override { + auto hf = a / a[3]; + ld z0 = hypot(a[1], a[2]); + if(!z0) return hf; + ld f = ((z0 + z) / z0); + hf[1] *= f; hf[2] *= f; + return hf; + } + hyperpoint flatten(hyperpoint h) { + h /= h[3]; + ld z = hypot(h[1], h[2]); + if(z > 0) h[1] /= z, h[2] /= z; + return h; + } + }; + +struct emb_euc_in_sph : emb_euclid_noniso { + bool is_euc_in_sph() override { return true; } + ld center_z() override { return 1; } + hyperpoint actual_to_intermediate(hyperpoint a) override { + ld tx = hypot(a[0], a[2]); + ld ty = hypot(a[1], a[3]); + ld x0 = atan2(a[0], a[2]); + ld y0 = atan2(a[1], a[3]); + ld z0 = atan2(tx, ty); + return hyperpoint(x0, y0, z0, 1); + } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { + return cspin(0, 2, i[0]) * cspin(1, 3, i[1]) * cspin(2, 3, i[2]); + } + }; + +struct emb_euc_in_nil : emb_euclid_noniso { + bool is_euc_in_nil() override { return true; } + hyperpoint actual_to_intermediate(hyperpoint a) override { return a; } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { return rgpushxto0(i); } + transmatrix get_lsti() override { return cspin90(2, 1); } + hyperpoint orthogonal_move(const hyperpoint& a, ld z) override { return nisot::translate(a) * cpush0(1, z); } + }; + +struct emb_euc_in_solnih : emb_euclid_noniso { + hyperpoint actual_to_intermediate(hyperpoint a) override { return a; } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { return rgpushxto0(i); } + }; + +struct emb_hyp_in_solnih : embedding_method { + bool is_hyp_in_solnih() override { return true; } + bool is_in_noniso() override { return true; } + transmatrix intermediate_to_actual_translation(hyperpoint i) override { return rgpushxto0(i); } + hyperpoint actual_to_intermediate(hyperpoint a) override { return a; } + transmatrix base_to_actual(const transmatrix &T) override { + auto T1 = T; + auto h = get_column(T1, 2); + return rgpushxto0(base_to_actual(h)); + } + hyperpoint base_to_actual(hyperpoint h) override { + // copied from deparabolic13 + h /= (1 + h[2]); + h[0] -= 1; + h /= sqhypot_d(2, h); + h[0] += .5; + ld hx = log(2) + log(-h[0]); + if(cgclass == gcNIH) hx /= log(3); + if(cgclass == gcSolN) hx /= log(3); + ld hy = h[1] * 2; + return point31(0, -hy, hx); + } + transmatrix actual_to_base(const transmatrix& T) override { + return Id; /* TBD actual computation */ + } + hyperpoint actual_to_base(hyperpoint h) override { + return C02; /* TBD actual computation */ + } + transmatrix get_lsti() override { return cspin90(0, 1) * cspin90(1, 2) * cspin90(0, 1); } + hyperpoint orthogonal_move(const hyperpoint& a, ld z) override { return nisot::translate(a) * cpush0(0, z); } + }; + +/* the remaining methods */ +/*=======================*/ + +void embedding_method::prepare_lta() { + bool b = geom3::flipped; + if(b) geom3::light_flip(false); + + logical_scaled_to_intermediate = get_lsti(); + logical_to_intermediate = get_lti(); + intermediate_to_logical = inverse(logical_to_intermediate); + intermediate_to_logical_scaled = inverse(logical_scaled_to_intermediate); + if(b) geom3::light_flip(true); + } + +/** pick the embedding_method for the current setting */ +EX unique_ptr make_embed() { + + embedding_method *emb1; + using namespace geom3; + + if(!embedded_plane) + emb1 = new emb_none; + else if(any_cylinder(spatial_embedding) && mgclass() == gcEuclid) + emb1 = new emb_euc_cylinder; + else if(mgclass() == ggclass()) + emb1 = new emb_same_in_same; + else if(mgclass() == gcSphere && among(ggclass(), gcHyperbolic, gcEuclid)) + emb1 = new emb_sphere_in_low; + else if(mgclass() == gcEuclid && ggclass() == gcSphere) + emb1 = new emb_euc_in_sph; + else if(mgclass() == gcEuclid && ggclass() == gcSL2) + emb1 = new emb_euc_in_sl2; + else if(mgclass() == gcHyperbolic && among(ggclass(), gcSol, gcNIH, gcSolN)) + emb1 = new emb_hyp_in_solnih; + else if(mgclass() == gcEuclid && ggclass() == gcProduct) + emb1 = new emb_euc_in_product; + else if(ggclass() == gcProduct) + emb1 = new emb_product_embedding; + else if(mgclass() == gcEuclid && ggclass() == gcNil) + emb1 = new emb_euc_in_nil; + else if(mgclass() == gcEuclid && ggclass() == gcHyperbolic) + emb1 = new emb_euc_in_hyp; + else if(mgclass() == gcEuclid && among(ggclass(), gcSol, gcNIH, gcSolN)) + emb1 = new emb_euc_in_solnih; + else + throw hr_exception("unknown embedding"); + + unique_ptr emb(emb1); + + emb->prepare_lta(); + return emb; + } + +EX hyperpoint orthogonal_move(hyperpoint h, ld z ) { return cgi.emb->orthogonal_move(h, z); } + +EX transmatrix unswap_spin(transmatrix T) { + return cgi.emb->intermediate_to_logical_scaled * T * cgi.emb->logical_scaled_to_intermediate; + } + +/** rotate by alpha degrees in the XY plane */ +EX transmatrix spin(ld alpha) { + if(cgi.emb->no_spin()) return Id; + return cgi.emb->logical_scaled_to_intermediate * cspin(0, 1, alpha) * cgi.emb->intermediate_to_logical_scaled; + } + +/** rotate by 90 degrees in the XY plane */ +EX transmatrix spin90() { + if(cgi.emb->no_spin()) return Id; + return cgi.emb->logical_scaled_to_intermediate * cspin90(0, 1) * cgi.emb->intermediate_to_logical_scaled; + } + +/** rotate by 180 degrees in the XY plane */ +EX transmatrix spin180() { + if(cgi.emb->no_spin()) return Id; + return cgi.emb->logical_scaled_to_intermediate * cspin180(0, 1) * cgi.emb->intermediate_to_logical_scaled; + } + +/** rotate by 270 degrees in the XY plane */ +EX transmatrix spin270() { + if(cgi.emb->no_spin()) return Id; + return cgi.emb->logical_scaled_to_intermediate * cspin90(1, 0) * cgi.emb->intermediate_to_logical_scaled; + } + +EX transmatrix lzpush(ld z) { + if(cgi.emb->logical_to_intermediate[2][0]) return cpush(0, z); + if(cgi.emb->logical_to_intermediate[2][1]) return cpush(1, z); + return cpush(2, z); + } + +EX transmatrix lxpush(ld alpha) { + if(embedded_plane) { + geom3::light_flip(true); + auto t = cpush(0, alpha); + geom3::light_flip(false); + return cgi.emb->base_to_actual(t); + } + return cpush(0, alpha); + } + +EX hyperpoint lxpush0(ld x) { return lxpush(x) * tile_center(); } + +EX transmatrix lspintox(const hyperpoint& H) { + if(cgi.emb->no_spin()) return Id; + if(embedded_plane) { + hyperpoint H1 = cgi.emb->intermediate_to_logical_scaled * H; + return cgi.emb->logical_scaled_to_intermediate * spintoc(H1, 0, 1) * cgi.emb->intermediate_to_logical_scaled; + } + if(WDIM == 2 || gproduct) return spintoc(H, 0, 1); + transmatrix T1 = spintoc(H, 0, 1); + return spintoc(T1*H, 0, 2) * T1; + } + +EX transmatrix lrspintox(const hyperpoint& H) { + if(cgi.emb->no_spin()) return Id; + if(embedded_plane) { + hyperpoint H1 = cgi.emb->intermediate_to_logical_scaled * H; + return cgi.emb->logical_scaled_to_intermediate * rspintoc(H1, 0, 1) * cgi.emb->intermediate_to_logical_scaled; + } + if(WDIM == 2 || gproduct) return rspintoc(H, 0, 1); + transmatrix T1 = spintoc(H, 0, 1); + return rspintoc(H, 0, 1) * rspintoc(T1*H, 0, 2); + } + +/** tangent vector in logical direction Z */ +EX hyperpoint lztangent(ld z) { + return cgi.emb->logical_to_intermediate * ctangent(2, z); + } + +EX hyperpoint tile_center() { return cgi.emb->tile_center(); } + +EX hyperpoint lspinpush0(ld alpha, ld x) { + bool f = embedded_plane; + if(f) geom3::light_flip(true); + if(embedded_plane) throw hr_exception("still embedded plane"); + hyperpoint h = xspinpush0(alpha, x); + if(f) geom3::light_flip(false); + if(f) return cgi.emb->base_to_actual(h); + return h; + } + +EX hyperpoint xspinpush0(ld alpha, ld x) { + if(embedded_plane) return lspinpush0(alpha, x); + if(sl2) return slr::polar(x, -alpha, 0); + hyperpoint h = Hypc; + h[LDIM] = cos_auto(x); + h[0] = sin_auto(x) * cos(alpha); + h[1] = sin_auto(x) * -sin(alpha); + return h; + } + +EX transmatrix xspinpush(ld dir, ld dist) { + if(embedded_plane) { + geom3::light_flip(true); + transmatrix T = spin(dir) * xpush(dist) * spin(-dir); + geom3::light_flip(false); + return cgi.emb->base_to_actual(T); + } + else if(euclid) + return eupush(cos(dir) * dist, -sin(dir) * dist); + else + return spin(dir) * xpush(dist) * spin(-dir); + } + +EX const transmatrix& lmirror() { + if(cgi.emb->is_euc_in_product()) return Id; + if(cgi.emb->logical_to_intermediate[2][1]) return MirrorZ; + if(cgi.emb->is_hyp_in_solnih()) return MirrorZ; + return Mirror; + } + +transmatrix embedding_method::get_radar_transform(const transmatrix& V) { + if(cgi.emb->is_euc_in_sl2()) { + return inverse(actual_view_transform * V); + } + else if(nonisotropic) { + transmatrix T = actual_view_transform * V; + ld z = -tC0(view_inverse(T)) [2]; + transmatrix R = actual_view_transform; + R = logical_scaled_to_intermediate * R; + if(R[1][2] || R[2][2]) + R = cspin(1, 2, -atan2(R[1][2], R[2][2])) * R; + if(R[0][2] || R[2][2]) + R = cspin(0, 2, -atan2(R[0][2], R[2][2])) * R; + if(is_hyp_in_solnih()) R = Id; + R = intermediate_to_logical_scaled * R; + return inverse(R) * zpush(-z); + } + else if(gproduct) { + transmatrix T = V; + ld z = zlevel(tC0(inverse(T))); + + transmatrix R = NLP; + if(R[1][2] || R[2][2]) + R = cspin(1, 2, -atan2(R[1][2], R[2][2])) * R; + if(R[0][2] || R[2][2]) + R = cspin(0, 2, -atan2(R[0][2], R[2][2])) * R; + + return R * zpush(z); + } + else if(is_euc_in_sph()) { + return inverse(V); + } + else if(is_cylinder()) { + return inverse(V); + } + else { + transmatrix T = actual_view_transform * V; + transmatrix U = view_inverse(T); + + if(T[0][2] || T[1][2]) + T = spin(-atan2(T[0][2], T[1][2])) * T; + if(T[1][2] || T[2][2]) + T = cspin(1, 2, -atan2(T[1][2], T[2][2])) * T; + + ld z = -asin_auto(tC0(view_inverse(T)) [2]); + T = zpush(-z) * T; + + return T * U; + } + } + +EX void swapmatrix(transmatrix& T) { + if(embedded_plane) T = swapper->emb->base_to_actual(T); + else T = swapper->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); + } + +void embedding_method::auto_configure() { + using namespace geom3; + ld ms = min(cgi.scalefactor, 1); + vid.depth = ms; + vid.wall_height = 1.5 * ms; + if(sphere && msphere) { + vid.depth = 30 * degree; + vid.wall_height = 60 * degree; + } + vid.human_wall_ratio = 0.8; + if(mgclass() == gcEuclid && allowIncreasedSight() && vid.use_smart_range == 0) { + genrange_bonus = gamerange_bonus = sightrange_bonus = cgi.base_distlimit * 3/2; + } + vid.camera = 0; + vid.eye = 0; + if(is_sph_in_low()) { + vid.depth = 0; + vid.wall_height = -1; + vid.eye = -0.5; + if(inverted_embedding) { + vid.wall_height = 1.4; + vid.eye = 0.2; + vid.depth = 0.5; + } + } + if(supports_flat() && flat_embedding) { + vid.eye += vid.depth / 2; + vid.depth = 0; + } + if(spatial_embedding == seDefault && !flat_embedding && inverted_embedding) { + vid.eye += vid.depth * 1.5; + vid.depth *= -1; + } + if((is_euc_in_hyp() || is_euc_in_noniso()) && inverted_embedding) { + vid.wall_height *= -1; + vid.eye = -2 * vid.depth; + } + if(is_euc_in_nil() || is_euc_in_sl2()) { + vid.depth = 0; + vid.eye = vid.wall_height / 2; + } + if(is_euc_in_hyp() && spatial_embedding == seMuchLowerCurvature) { + vid.eye = inverted_embedding ? -vid.depth : vid.depth; + vid.depth = 0; + } + if(msphere && spatial_embedding == seProduct) { + vid.depth = 0; + vid.wall_height = 2; + vid.eye = 2; + } + if(pmodel == mdDisk) pmodel = nonisotropic ? mdGeodesic : mdPerspective; + if(cgflags & qIDEAL && vid.texture_step < 32) + vid.texture_step = 32; +#if CAP_RACING + racing::player_relative = true; +#endif + if(hyperbolic && is_same_in_same() && spatial_embedding == seLowerCurvature) { + vid.eye += vid.depth; + vid.depth *= 2; + if(inverted_embedding) { + vid.eye = 1; + vid.depth *= -1; + vid.wall_height *= -1; + } + } + if(hyperbolic && is_same_in_same() && spatial_embedding == seMuchLowerCurvature) { + vid.eye += vid.depth; + vid.depth *= 3; + if(inverted_embedding) { + vid.eye = 2; + vid.depth *= -1; + vid.wall_height *= -1; + } + } + if(spatial_embedding == seCliffordTorus) configure_clifford_torus(); + if(spatial_embedding == seProductS) configure_cylinder(); + if(spatial_embedding == seCylinderE) configure_cylinder(); + if(spatial_embedding == seCylinderH) configure_cylinder(); + } + +} diff --git a/euclid.cpp b/euclid.cpp index e723d41c..0f8a4b1c 100644 --- a/euclid.cpp +++ b/euclid.cpp @@ -137,14 +137,10 @@ EX namespace euc { map eucdata; void compute_tmatrix() { - bool b = geom3::flipped; cgi.prepare_basics(); - if(b) geom3::light_flip(false); shifttable = get_shifttable(); tmatrix.resize(S7); - for(int i=0; ibase_to_actual(Mat); return Mat; } diff --git a/floorshapes.cpp b/floorshapes.cpp index 6f1bf115..43332a1f 100644 --- a/floorshapes.cpp +++ b/floorshapes.cpp @@ -346,7 +346,7 @@ void geometry_information::bshape_regular(floorshape &fsh, int id, int sides, ld hpcpush(xspinpush0(-M_PI/sides, size)); chasmifyPoly(dlow_table[k], dhi_table[k], k); - if(geom3::euc_in_noniso()) { + if(cgi.emb->is_euc_in_noniso()) { fsh.gpside[k].resize(c->type); for(int i=0; itype; i++) { sizeto(fsh.gpside[k][i], id); @@ -704,12 +704,12 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i }); } if(!vid.pseudohedral) for(int t=0; tnormalize_flat(a); hyperpoint c = orthogonal_move(b, dfloor_table[k]); cgi.hpcpush(c); }); @@ -745,7 +745,7 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i auto TC0 = tile_center(); hyperpoint v1 = may_kleinize(hpc[s+t]) - TC0; hyperpoint v2 = may_kleinize(hpc[s+t+1]) - TC0; - texture_order([&] (ld x, ld y) { hpcpush(orthogonal_move(normalize_flat(TC0 + v1 * x + v2 * y), top + h * (x+y))); }); + texture_order([&] (ld x, ld y) { hpcpush(orthogonal_move(cgi.emb->normalize_flat(TC0 + v1 * x + v2 * y), top + h * (x+y))); }); } } diff --git a/geom-exp.cpp b/geom-exp.cpp index 8f0afb4b..bce83315 100644 --- a/geom-exp.cpp +++ b/geom-exp.cpp @@ -542,7 +542,7 @@ EX string geometry_name(eGeometryClass gc) { } EX string geometry_name() { - if(embedded_plane && geom3::same_in_same()) + if(cgi.emb->is_same_in_same()) return geometry_name(geom3::mgclass()); else if(embedded_plane && gproduct) return geometry_name(geom3::mgclass()) + " (x E)"; diff --git a/geometry.cpp b/geometry.cpp index 86c24eb8..81e12048 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -144,6 +144,8 @@ struct subcellshape { enum class ePipeEnd {sharp, ball}; +struct embedding_method; + /** basic geometry parameters */ struct geometry_information { @@ -199,18 +201,8 @@ struct geometry_information { vector heptmove, hexmove, invhexmove; int base_distlimit; - - /* convert the tangent space in logical coordinates to actual coordinates */ - transmatrix logical_to_intermediate; - - /* convert the tangent space in actual coordinates to logical coordinates */ - transmatrix intermediate_to_logical; - - /* convert the tangent space in logical coordinates to actual coordinates */ - transmatrix logical_scaled_to_intemediate; - - /* convert the tangent space in actual coordinates to logical coordinates */ - transmatrix intermediate_to_logical_scaled; + + unique_ptr emb; /** size of the Sword (from Orb of the Sword), used in the shmup mode */ ld sword_size; @@ -452,8 +444,6 @@ hpcshape void prepare_shapes(); void prepare_usershapes(); - void prepare_lta(); - void hpcpush(hyperpoint h); void hpc_connect_ideal(hyperpoint a, hyperpoint b); void hpcsquare(hyperpoint h1, hyperpoint h2, hyperpoint h3, hyperpoint h4); @@ -591,28 +581,6 @@ EX bool is_reg3_variation(eVariation var) { return var == eVariation::coxeter; } -void geometry_information::prepare_lta() { - auto& lta = logical_to_intermediate; - bool b = geom3::flipped; - if(b) geom3::light_flip(false); - lta = Id; - if(embedded_plane) { - if(geom3::euc_vertical()) lta = cspin90(2, 1) * lta; - if(geom3::hyp_in_solnih()) lta = cspin90(0, 1) * cspin90(1, 2) * cspin90(0, 1) * lta; - if(geom3::euc_cylinder()) lta = cspin90(0, 1) * lta; - } - logical_scaled_to_intemediate = lta; - if(geom3::euc_in_noniso()) { - lta = Id; - lta[0][0] *= geom3::euclid_embed_scale; - lta[1][1] *= geom3::euclid_embed_scale * geom3::euclid_embed_scale_y; - lta = logical_scaled_to_intemediate * cspin(0, 1, geom3::euclid_embed_rotate * degree) * lta; - } - intermediate_to_logical = inverse(lta); - intermediate_to_logical_scaled = inverse(logical_scaled_to_intemediate); - if(b) geom3::light_flip(true); - } - void geometry_information::prepare_basics() { DEBBI(DF_INIT | DF_POLY | DF_GEOM, ("prepare_basics")); @@ -628,8 +596,10 @@ void geometry_information::prepare_basics() { heptshape = nullptr; xp_order = 0; - - prepare_lta(); + + emb = make_embed(); + bool geuclid = euclid; + bool ghyperbolic = hyperbolic; if(arcm::in() && !mproduct) ginf[gArchimedean].cclass = gcHyperbolic; @@ -802,13 +772,13 @@ void geometry_information::prepare_basics() { } #endif - if(geom3::euc_in_hyp()) { + if(meuclid && ghyperbolic) { scalefactor *= exp(-vid.depth); } - if(geom3::euc_in_noniso()) scalefactor *= geom3::euclid_embed_scale; - if(geom3::sph_in_euc()) scalefactor *= (1 + vid.depth); - if(geom3::sph_in_hyp()) scalefactor *= sinh(1 + vid.depth); + if(cgi.emb->is_euc_in_noniso()) scalefactor *= geom3::euclid_embed_scale; + if(msphere && geuclid) scalefactor *= (1 + vid.depth); + if(msphere && ghyperbolic) scalefactor *= sinh(1 + vid.depth); if(scale_used()) { scalefactor *= vid.creature_scale; @@ -884,20 +854,6 @@ void geometry_information::prepare_basics() { #endif } -EX transmatrix xspinpush(ld dir, ld dist) { - if(WDIM == 2 && GDIM == 3) { - geom3::light_flip(true); - transmatrix T = spin(dir) * xpush(dist) * spin(-dir); - geom3::light_flip(false); - swapmatrix(T); - return T; - } - else if(euclid) - return eupush(cos(dir) * dist, -sin(dir) * dist); - else - return spin(dir) * xpush(dist) * spin(-dir); - } - EX purehookset hooks_swapdim; EX namespace geom3 { @@ -1064,7 +1020,7 @@ EX namespace geom3 { reduce = (GDIM == 3 ? human_height * .3 : 0); int sgn = vid.wall_height > 0 ? 1 : -1; - ld ees = geom3::euc_in_noniso() ? geom3::euclid_embed_scale_mean() : 1; + ld ees = cgi.emb->is_euc_in_noniso() ? geom3::euclid_embed_scale_mean() : 1; STUFF = lev_to_factor(0) - sgn * max(orbsize * ees * 0.3, zhexf * ees * .6); @@ -1089,10 +1045,8 @@ EX namespace geom3 { SKY = LOWSKY - sgn * 5; /* in spherical/cylindrical case, make sure that the high stuff does not go through the center */ - bool depth_limit = geom3::mgclass() == gcSphere && geom3::ggclass() != gcSphere; - depth_limit |= euc_cylinder(); - if(depth_limit) { + if(cgi.emb->is_depth_limited()) { ld max_high = lerp(-FLOOR, -1, 0.8); ld max_high2 = lerp(-FLOOR, -1, 0.9); if(HIGH < max_high) HIGH = max_high; @@ -1110,245 +1064,25 @@ EX namespace geom3 { if(sgn < 0) INFDEEP = -1; } - if(geom3::euc_in_hyp() && sgn < 0) INFDEEP = FLOOR - 5; + if(cgi.emb->is_euc_in_hyp() && sgn < 0) INFDEEP = FLOOR - 5; } } EX namespace geom3 { - #if HDR - enum eSpatialEmbedding { - seNone, - seDefault, - seLowerCurvature, - seMuchLowerCurvature, - seProduct, - seNil, - seSol, seNIH, seSolN, - seCliffordTorus, - seProductH, - seProductS, - seSL2, - seCylinder - }; - #endif - - EX vector> spatial_embedding_options = { - {"2D engine", "Use HyperRogue's 2D engine to simulate same curvature. Works well in top-down and third-person perspective. The Hypersian Rug mode can be used to project this to a surface."}, - {"same curvature", "Embed as an equidistant surface in the 3D version of the same geometry."}, - {"lower curvature", "Embed as a surface in a space of lower curvature."}, - {"much lower curvature", "Embed sphere as a sphere in hyperbolic space."}, - {"product", "Add one extra dimension in the Euclidean way."}, - {"Nil", "Embed Euclidean plane into Nil."}, - {"Sol", "Embed Euclidean or hyperbolic plane into Sol."}, - {"stretched hyperbolic", "Embed Euclidean or hyperbolic plane into stretched hyperbolic geometry."}, - {"stretched Sol", "Embed Euclidean or hyperbolic plane into stretched Sol geometry."}, - {"Clifford Torus", "Embed Euclidean rectangular torus into S3."}, - {"hyperbolic product", "Embed Euclidean or hyperbolic plane in the H2xR product space."}, - {"spherical product", "Embed Euclidean cylinder or spherical plane in the H2xR product space."}, - {"SL(2,R)", "Embed Euclidean plane in twisted product geometry."}, - {"cylinder", "Embed Euclidean cylinder in Euclidean space."}, - }; - - EX eSpatialEmbedding spatial_embedding = seDefault; - EX ld euclid_embed_scale = 1; - EX ld euclid_embed_scale_y = 1; - EX ld euclid_embed_rotate = 0; - EX bool auto_configure = true; - EX bool flat_embedding = false; - EX bool inverted_embedding = false; - - EX ld euclid_embed_scale_mean() { return euclid_embed_scale * sqrt(euclid_embed_scale_y); } - EX void set_euclid_embed_scale(ld x) { euclid_embed_scale = x; euclid_embed_scale_y = 1; euclid_embed_rotate = 0; } - - EX bool supports_flat() { return among(spatial_embedding, seDefault, seProductH, seProductS); } - EX bool supports_invert() { return among(spatial_embedding, seDefault, seLowerCurvature, seMuchLowerCurvature, seNil, seSol, seNIH, seSolN, seProductH, seProductS); } - - EX vector ginf_backup; - - EX eGeometryClass mgclass() { - return (embedded_plane ? ginf_backup : ginf)[geometry].g.kind; - } - - EX eGeometryClass ggclass() { - return (flipped ? ginf_backup : ginf)[geometry].g.kind; - } - - EX bool euc_in_hyp() { - return ggclass() == gcHyperbolic && mgclass() == gcEuclid; - } - - EX bool euc_in_nil() { - return ggclass() == gcNil && mgclass() == gcEuclid; - } - - EX bool euc_in_product() { - return ggclass() == gcProduct && mgclass() == gcEuclid; - } - - EX bool euc_in_sl2() { - return ggclass() == gcSL2 && mgclass() == gcEuclid; - } - - EX bool euc_vertical() { - return mgclass() == gcEuclid && among(ggclass(), gcNil, gcProduct, gcSL2); - } - - EX bool euc_in_solnih() { - return among(ggclass(), gcSol, gcNIH, gcSolN) && mgclass() == gcEuclid; - } - - EX bool hyp_in_solnih() { - return among(ggclass(), gcSol, gcNIH, gcSolN) && mgclass() == gcHyperbolic; - } - - EX bool euc_in_noniso() { - if(spatial_embedding == seCylinder) return mgclass() == gcEuclid; - return among(ggclass(), gcNil, gcSol, gcNIH, gcSolN, gcSphere, gcProduct, gcSL2) && mgclass() == gcEuclid; - } - - EX bool euc_cylinder() { - return spatial_embedding == seCylinder && mgclass() == gcEuclid; - } - - EX bool sph_in_euc() { - return ggclass() == gcEuclid && mgclass() == gcSphere; - } - - EX bool euc_in_sph() { - return ggclass() == gcSphere && mgclass() == gcEuclid; - } - - EX bool sph_in_hyp() { - return ggclass() == gcHyperbolic && mgclass() == gcSphere; - } - - EX bool sph_in_low() { - return mgclass() == gcSphere && among(ggclass(), gcHyperbolic, gcEuclid); - } - - EX bool in_product() { - return ggclass() == gcProduct; - } - - EX bool same_in_same() { - return mgclass() == ggclass() && !among(spatial_embedding, seCylinder); - } - - EX bool flipped; - - EX void light_flip(bool f) { - if(f != flipped) { - swap(ginf[geometry].g, geom3::ginf_backup[geometry].g); - swap(ginf[geometry].flags, geom3::ginf_backup[geometry].flags); - flipped = f; - } - } - - #if HDR - template auto in_flipped(const T& f) -> decltype(f()) { - light_flip(true); - finalizer ff([] { light_flip(false); }); - return f(); - } - - template auto in_not_flipped(const T& f) -> decltype(f()) { - light_flip(false); - finalizer ff([] { light_flip(true); }); - return f(); - } - - #define IPF(x) geom3::in_flipped([&] { return (x); }) - #endif - - EX void apply_always3() { - if(!vid.always3 && !ginf_backup.empty()) { - ginf = ginf_backup; - ginf_backup.clear(); - } - if(vid.always3 && ginf_backup.empty()) { - ginf_backup = ginf; - for(geometryinfo& gi: ginf) { - auto &g = gi.g; - if(vid.always3 && g.gameplay_dimension == 2 && g.graphical_dimension == 2) { - g.graphical_dimension++; - g.homogeneous_dimension++; - g.sig[3] = g.sig[2]; - g.sig[2] = g.sig[1]; - - if(among(spatial_embedding, seProduct, seProductH, seProductS) && g.kind != gcEuclid) { - g.kind = gcProduct; - g.homogeneous_dimension--; - g.sig[2] = g.sig[3]; - } - - if(among(spatial_embedding, seProductH, seProductS) && g.kind == gcEuclid) { - g.kind = gcProduct; - g.homogeneous_dimension--; - g.sig[2] = spatial_embedding == seProductH ? -1 : 1; - } - - if(spatial_embedding == seLowerCurvature) { - if(g.kind == gcEuclid) g = ginf[gSpace534].g; - if(g.kind == gcSphere) g = ginf[gCubeTiling].g; - g.gameplay_dimension = 2; - } - - if(spatial_embedding == seMuchLowerCurvature) { - g = ginf[gSpace534].g; - g.gameplay_dimension = 2; - } - - bool ieuclid = g.kind == gcEuclid; - - if(spatial_embedding == seNil && ieuclid) { - g = ginf[gNil].g; - g.gameplay_dimension = 2; - } - - if(spatial_embedding == seCliffordTorus && ieuclid) { - g = ginf[gCell120].g; - g.gameplay_dimension = 2; - } - - bool ieuc_or_binary = ieuclid || (gi.flags & qBINARY); - - if(spatial_embedding == seSol && ieuc_or_binary) { - g = ginf[gSol].g; - g.gameplay_dimension = 2; - } - - if(spatial_embedding == seNIH && ieuc_or_binary) { - g = ginf[gNIH].g; - g.gameplay_dimension = 2; - } - - if(spatial_embedding == seSolN && ieuc_or_binary) { - g = ginf[gSolN].g; - g.gameplay_dimension = 2; - } - - if(spatial_embedding == seSL2 && ieuclid) { - g = giSL2; - g.gameplay_dimension = 2; - } - } - } - } - } - #if MAXMDIM >= 4 -EX void switch_always3() { + EX void switch_always3() { if(dual::split(switch_always3)) return; #if CAP_GL && CAP_RUG if(rug::rugged) rug::close(); #endif + swapper = &cgi; vid.always3 = !vid.always3; apply_always3(); swapmatrix(View); callhooks(hooks_swapdim); } -#endif + #endif EX void switch_tpp() { if(dual::split(switch_fpp)) return; @@ -1383,89 +1117,18 @@ EX void switch_always3() { if(!vid.always3) { vid.always3 = true; apply_always3(); - ld ms = min(cgi.scalefactor, 1); - vid.depth = ms; - vid.wall_height = 1.5 * ms; - if(sphere && same_in_same()) { - vid.depth = 30 * degree; - vid.wall_height = 60 * degree; - } - vid.human_wall_ratio = 0.8; - if(mgclass() == gcEuclid && allowIncreasedSight() && vid.use_smart_range == 0) { - genrange_bonus = gamerange_bonus = sightrange_bonus = cgi.base_distlimit * 3/2; - } - vid.camera = 0; - vid.eye = 0; - if(sph_in_low()) { - vid.depth = 0; - vid.wall_height = -1; - vid.eye = -0.5; - if(inverted_embedding) { - vid.wall_height = 1.4; - vid.eye = 0.2; - vid.depth = 0.5; - } - } - if(supports_flat() && flat_embedding) { - vid.eye += vid.depth / 2; - vid.depth = 0; - } - if(spatial_embedding == seDefault && !flat_embedding && inverted_embedding) { - vid.eye += vid.depth * 1.5; - vid.depth *= -1; - } - if((euc_in_hyp() || euc_in_noniso()) && inverted_embedding) { - vid.wall_height *= -1; - vid.eye = -2 * vid.depth; - } - if(euc_in_nil() || euc_in_sl2()) { - vid.depth = 0; - vid.eye = vid.wall_height / 2; - } - if(euc_in_hyp() && spatial_embedding == seMuchLowerCurvature) { - vid.eye = inverted_embedding ? -vid.depth : vid.depth; - vid.depth = 0; - } - if(msphere && spatial_embedding == seProduct) { - vid.depth = 0; - vid.wall_height = 2; - vid.eye = 2; - } - if(pmodel == mdDisk) pmodel = nonisotropic ? mdGeodesic : mdPerspective; + auto emb = make_embed(); + 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(); - if(cgflags & qIDEAL && vid.texture_step < 32) - vid.texture_step = 32; -#if CAP_RACING - racing::player_relative = true; -#endif - check_cgi(); - cgi.prepare_basics(); - if(hyperbolic && same_in_same() && spatial_embedding == seLowerCurvature) { - vid.eye += vid.depth; - vid.depth *= 2; - if(inverted_embedding) { - vid.eye = 1; - vid.depth *= -1; - vid.wall_height *= -1; - } - } - if(hyperbolic && same_in_same() && spatial_embedding == seMuchLowerCurvature) { - vid.eye += vid.depth; - vid.depth *= 3; - if(inverted_embedding) { - vid.eye = 2; - vid.depth *= -1; - vid.wall_height *= -1; - } - } - if(spatial_embedding == seCliffordTorus) configure_clifford_torus(); - if(spatial_embedding == seProductS) configure_cylinder(); - if(spatial_embedding == seCylinder) configure_cylinder(); } else { + swapper = &cgi; vid.always3 = false; apply_always3(); vid.wall_height = .3; @@ -1482,42 +1145,6 @@ EX void switch_always3() { #endif } - EX void configure_clifford_torus() { - rug::clifford_torus ct; - - if(hypot_d(2, ct.xh) < 1e-6 || hypot_d(2, ct.yh) < 1e-6) { - euclid_embed_scale = TAU / 20.; - euclid_embed_scale_y = 1; - euclid_embed_rotate = 0; - vid.depth = 45._deg - 1; - vid.wall_height = 0.2; - vid.eye = vid.wall_height / 2 - vid.depth; - return; - } - - euclid_embed_scale = TAU / hypot_d(2, ct.xh); - euclid_embed_scale_y = TAU / hypot_d(2, ct.yh) / euclid_embed_scale; - euclid_embed_rotate = atan2(ct.xh[1], ct.xh[0]) / degree; - - ld alpha = atan2(ct.xfactor, ct.yfactor); - - vid.depth = alpha - 1; - vid.wall_height = min(1 / euclid_embed_scale_mean(), (90._deg - alpha) * 0.9); - vid.eye = vid.wall_height / 2 - vid.depth; - } - - EX void configure_cylinder() { - rug::clifford_torus ct; - hyperpoint vec; - if(sqhypot_d(2, ct.yh) > 1e-6) vec = ct.yh; - else if(sqhypot_d(2, ct.xh) > 1e-6) vec = ct.xh; - else vec = hyperpoint(10, 0, 0, 0); - - euclid_embed_scale = TAU / hypot_d(2, vec); - euclid_embed_scale_y = 1; - euclid_embed_rotate = atan2(vec[1], vec[0]) / degree; - } - EX } EX geometry_information *cgip; diff --git a/geometry2.cpp b/geometry2.cpp index e1d2bd37..7a4cab7e 100644 --- a/geometry2.cpp +++ b/geometry2.cpp @@ -239,7 +239,7 @@ void horo_distance::become(hyperpoint h1) { #endif else if(mhybrid || sl2) a = 0, b = hdist(h1, C0); - else if(geom3::euc_in_product()) + else if(cgi.emb->is_euc_in_product()) a = 0, b = hdist(h1, C0); else a = 0, b = intval(h1, tile_center()); @@ -251,7 +251,7 @@ horo_distance::horo_distance(shiftpoint h1, const shiftmatrix& T) { else #endif if(sn::in() || mhybrid || nil || sl2) become(inverse_shift(T, h1)); - else if(geom3::euc_in_product()) + else if(cgi.emb->is_euc_in_product()) a = 0, b = hdist(h1.h, unshift(T * tile_center(), h1.shift)); else a = 0, b = intval(h1.h, unshift(T * tile_center(), h1.shift)); @@ -446,7 +446,7 @@ EX bool no_easy_spin() { return NONSTDVAR || arcm::in() || WDIM == 3 || bt::in() || kite::in(); } -EX bool dont_inverse() { return meuclid && PURE && geom3::euc_in_noniso(); } +EX bool dont_inverse() { return PURE && cgi.emb->is_euc_in_noniso(); } ld hrmap_standard::spin_angle(cell *c, int d) { if(WDIM == 3) return SPIN_NOT_AVAILABLE; @@ -471,7 +471,7 @@ EX transmatrix iddspin(cell *c, int d, ld bonus IS(0)) { return currentmap->spin EX ld cellgfxdist(cell *c, int d) { return currentmap->spacedist(c, d); } EX transmatrix ddspin_side(cell *c, int d, ld bonus IS(0)) { - if(geom3::euc_in_noniso() || geom3::hyp_in_solnih()) + if(cgi.emb->is_in_noniso()) return spin(bonus); if(kite::in()) { if(embedded_plane) return spin(bonus); @@ -484,7 +484,7 @@ EX transmatrix ddspin_side(cell *c, int d, ld bonus IS(0)) { } EX transmatrix iddspin_side(cell *c, int d, ld bonus IS(0)) { - if(geom3::euc_in_noniso() || geom3::hyp_in_solnih()) + if(cgi.emb->is_in_noniso()) return spin(bonus); if(kite::in()) { if(embedded_plane) return spin(bonus); @@ -589,7 +589,7 @@ hyperpoint hrmap_standard::get_corner(cell *c, int cid, ld cf) { } #endif if(PURE) { - if(geom3::euc_in_noniso()) { + if(cgi.emb->is_euc_in_noniso()) { return lspinpush0(spin_angle(c, cid) + M_PI/S7, cgi.hcrossf * 3 / cf); } return ddspin(c,cid,M_PI/S7) * lxpush0(cgi.hcrossf * 3 / cf); diff --git a/goldberg.cpp b/goldberg.cpp index 633c45c1..01f47c34 100644 --- a/goldberg.cpp +++ b/goldberg.cpp @@ -646,7 +646,7 @@ EX namespace gp { } if(sp>SG3) sp -= SG6; - return normalize_flat(spin(TAU*sp/S7) * cornmul(T, corner)); + return cgi.emb->normalize_flat(spin(TAU*sp/S7) * cornmul(T, corner)); } transmatrix dir_matrix(int i) { diff --git a/graph.cpp b/graph.cpp index 9a5bc9aa..5f04322b 100644 --- a/graph.cpp +++ b/graph.cpp @@ -349,13 +349,6 @@ EX transmatrix lpispin() { return spin180(); } -EX const transmatrix& lmirror() { - if(geom3::euc_in_product()) return Id; - if(geom3::euc_vertical()) return MirrorZ; - if(geom3::hyp_in_solnih()) return MirrorZ; - return Mirror; - } - EX void drawPlayerEffects(const shiftmatrix& V, const shiftmatrix& Vparam, cell *c, eMonster m) { bool onplayer = m == moPlayer; if(!onplayer && !items[itOrbEmpathy]) return; @@ -692,7 +685,7 @@ transmatrix otherbodyparts(const shiftmatrix& V, color_t col, eMonster who, doub shiftmatrix Tright, Tleft; - if(GDIM == 2 || mhybrid || geom3::euc_in_product()) { + if(GDIM == 2 || mhybrid || cgi.emb->is_euc_in_product()) { Tright = VFOOT * xpush(rightfoot); Tleft = VFOOT * lmirror() * xpush(-rightfoot); } @@ -700,7 +693,7 @@ transmatrix otherbodyparts(const shiftmatrix& V, color_t col, eMonster who, doub else { shiftmatrix V1 = V; if(WDIM == 2) V1 = V1 * lzpush(cgi.GROIN); - int zdir = geom3::euc_in_nil() ? 1 : 2; + int zdir = cgi.emb->is_euc_in_nil() ? 1 : 2; Tright = V1 * cspin(0, zdir, rightfoot/ leg_length); Tleft = V1 * lmirror() * cspin(zdir, 0, rightfoot / leg_length); Tright = V1; Tleft = V1 * lmirror(); @@ -774,8 +767,8 @@ EX shiftmatrix face_the_player(const shiftmatrix V) { if(mproduct) return orthogonal_move(V, cos(ptick(750)) * cgi.plevel / 16); if(mhybrid) return V * zpush(cos(ptick(750)) * cgi.plevel / 16); transmatrix dummy; /* used only in prod anyways */ - if(geom3::euc_vertical()) return V; - if(geom3::euc_in_sph()) return V; + if(cgi.emb->logical_to_intermediate[2][1]) return V; + if(cgi.emb->is_euc_in_sph()) return V; if(nonisotropic && !embedded_plane) return shiftless(spin_towards(unshift(V), dummy, C0, 2, 0)); #if CAP_VR if(vrhr::enabled) { @@ -784,8 +777,8 @@ EX shiftmatrix face_the_player(const shiftmatrix V) { return shiftless(cspin90(1, 2) * lrspintox(cspin90(2, 1) * uh) * xpush(hdist0(uh)) * cspin90(0, 2) * spin270()); } #endif - if(embedded_plane && geom3::sph_in_low()) return shiftless(map_relative_push(unshift(V * zpush0(1))) * zpush(-1)); - if(embedded_plane && geom3::euc_cylinder()) return shiftless(map_relative_push(unshift(V * zpush0(1))) * zpush(-1)); + if(embedded_plane && cgi.emb->is_sph_in_low()) return shiftless(cgi.emb->map_relative_push(unshift(V * zpush0(1))) * zpush(-1)); + if(embedded_plane && cgi.emb->is_cylinder()) return shiftless(cgi.emb->map_relative_push(unshift(V * zpush0(1))) * zpush(-1)); return rgpushxto0(tC0(V)); } @@ -2635,7 +2628,8 @@ EX bool applyAnimation(cell *c, shiftmatrix& V, double& footphase, int layer) { } else { transmatrix T = inverse(a.wherenow); - if(moved_center()) T = lzpush(-1) * T; + ld z = cgi.emb->center_z(); + if(z) T = lzpush(-z) * T; hyperpoint wnow; if(a.attacking == 1 || a.attacking == 3) @@ -2644,7 +2638,7 @@ EX bool applyAnimation(cell *c, shiftmatrix& V, double& footphase, int layer) { wnow = T * TC0; shift_v_towards(T, shiftless(wnow), aspd, shift_method(smaAnimation)); - if(moved_center()) T = lzpush(1) * T; + if(z) T = lzpush(1) * T; a.wherenow = inverse(T); fixmatrix(a.wherenow); @@ -3128,7 +3122,7 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col if(!nospins) { shiftmatrix& where = (c->monst == moMirrorSpirit && inmirrorcount) ? ocwtV : cwtV; - if(geom3::euc_in_product()) { } + if(cgi.emb->is_euc_in_product()) { } else if(WDIM == 2 || mproduct) { hyperpoint V0 = inverse_shift(Vs, where * tile_center()); ld z = 0; @@ -3474,7 +3468,7 @@ EX int countMinesAround(cell *c) { } EX transmatrix applyPatterndir(cell *c, const patterns::patterninfo& si) { - if(NONSTDVAR || bt::in() || geom3::euc_in_noniso()) return Id; + if(NONSTDVAR || bt::in() || cgi.emb->is_euc_in_noniso()) return Id; transmatrix V = ddspin180(c, si.dir); if(si.reflect) V = V * lmirror(); if(euclid) return V; @@ -3733,7 +3727,7 @@ EX bool placeSidewall(cell *c, int i, int sidepar, const shiftmatrix& V, color_t else if(sidepar == SIDE_BSHA) prio = PPR::BSHALLOW; else prio = PPR::REDWALL-2+4*(sidepar-SIDE_SLEV); - if(geom3::euc_in_noniso() || geom3::hyp_in_solnih()) { + if(cgi.emb->is_in_noniso()) { draw_shapevec(c, V, qfi.fshape->gpside[sidepar][i], col, prio); return false; } @@ -5060,7 +5054,7 @@ EX void make_actual_view() { } hyperpoint h = tC0(view_inverse(actual_view_transform * View)); - camera_level = get_logical_z(h); + camera_level = cgi.emb->get_logical_z(h); camera_sign = cgi.FLOOR > cgi.WALL; } @@ -5073,56 +5067,7 @@ EX void make_actual_view() { } #endif #if MAXMDIM >= 4 - if(embedded_plane) { - if(geom3::euc_in_sl2()) { - current_display->radar_transform = inverse(actual_view_transform * View); - } - else if(nonisotropic) { - transmatrix T = actual_view_transform * View; - ld z = -tC0(view_inverse(T)) [2]; - transmatrix R = actual_view_transform; - R = cgi.logical_scaled_to_intemediate * R; - if(R[1][2] || R[2][2]) - R = cspin(1, 2, -atan2(R[1][2], R[2][2])) * R; - if(R[0][2] || R[2][2]) - R = cspin(0, 2, -atan2(R[0][2], R[2][2])) * R; - if(geom3::hyp_in_solnih()) R = Id; - R = cgi.intermediate_to_logical_scaled * R; - current_display->radar_transform = inverse(R) * zpush(-z); - } - else if(gproduct) { - transmatrix T = View; - ld z = zlevel(tC0(inverse(T))); - - transmatrix R = NLP; - if(R[1][2] || R[2][2]) - R = cspin(1, 2, -atan2(R[1][2], R[2][2])) * R; - if(R[0][2] || R[2][2]) - R = cspin(0, 2, -atan2(R[0][2], R[2][2])) * R; - - current_display->radar_transform = R * zpush(z); - } - else if(geom3::euc_in_sph()) { - current_display->radar_transform = inverse(View); - } - else if(geom3::euc_cylinder()) { - current_display->radar_transform = inverse(View); - } - else { - transmatrix T = actual_view_transform * View; - transmatrix U = view_inverse(T); - - if(T[0][2] || T[1][2]) - T = spin(-atan2(T[0][2], T[1][2])) * T; - if(T[1][2] || T[2][2]) - T = cspin(1, 2, -atan2(T[1][2], T[2][2])) * T; - - ld z = -asin_auto(tC0(view_inverse(T)) [2]); - T = zpush(-z) * T; - - current_display->radar_transform = T * U; - } - } + if(embedded_plane) current_display->radar_transform = cgi.emb->get_radar_transform(View); #endif Viewbase = View; } @@ -5223,7 +5168,7 @@ EX void center_multiplayer_map(const vector& hs) { hyperpoint h = Hypc; for(auto h1: hs) h += h1; h /= isize(hs); - h = normalize_flat(h); + h = cgi.emb->normalize_flat(h); cwtV = shiftless(rgpushxto0(h)); if(isize(hs) == 2) { set_multi = true; diff --git a/hyper.cpp b/hyper.cpp index e46b5a3f..611ba20d 100644 --- a/hyper.cpp +++ b/hyper.cpp @@ -78,6 +78,7 @@ #include "system.cpp" #include "debug.cpp" #include "geometry.cpp" +#include "embeddings.cpp" #include "geometry2.cpp" #include "polygons.cpp" #include "3d-models.cpp" diff --git a/hyperpoint.cpp b/hyperpoint.cpp index 07a6abc9..d1d54e9e 100644 --- a/hyperpoint.cpp +++ b/hyperpoint.cpp @@ -391,8 +391,7 @@ EX hyperpoint hpxy(ld x, ld y) { geom3::light_flip(true); hyperpoint h = hpxy(x, y); geom3::light_flip(false); - swapmatrix(h); - return h; + return cgi.emb->base_to_actual(h); } if(sl2) return hyperpoint(x, y, 0, sqrt(1+x*x+y*y)); if(rotspace) return hyperpoint(x, y, 0, sqrt(1-x*x-y*y)); @@ -455,7 +454,7 @@ EX ld hypot_d(int d, const hyperpoint& h) { */ EX transmatrix to_other_side(hyperpoint h1, hyperpoint h2) { - if(geom3::sph_in_low() && !geom3::flipped) { + if(cgi.emb->is_sph_in_low() && !geom3::flipped) { geom3::light_flip(true); h1 = normalize(h1); h2 = normalize(h2); @@ -565,92 +564,6 @@ EX hyperpoint ultra_normalize(hyperpoint H) { return normalize(H); } -/** used in esl2_ita */ -EX transmatrix esl2_zpush(ld z) { return cspin(2, 3, z) * cspin(0, 1, z); } - -/** see esl2_ita; equal to esl2_ita * C0 */ -EX hyperpoint esl2_ita0(hyperpoint h1) { - return esl2_zpush(h1[2]) * xpush(h1[0]) * ypush0(h1[1]); - } - -/** in embedded-in-sl2, convert from intermediate to actual coordinates */ -EX transmatrix esl2_ita(hyperpoint h1) { - return esl2_zpush(h1[2]) * xpush(h1[0]) * ypush(h1[1]); - } - -/** in embedded-in-sl2, convert from actual to intermediate coordinates */ -EX hyperpoint esl2_ati(hyperpoint h) { - ld a1 = (h[0] * h[3] - h[1] * h[2]) / (-h[2] * h[2] - h[1] * h[1] -h[0] * h[0] - h[3] * h[3]); - // a1 is S*sqrt(1+S*S) / (1+2*S*S), where S = sinh(-x) and C = cosh(-x); U is S*S - ld a = a1 * a1; - ld b = 4 * a - 1; - ld U = sqrt(.25 - a/b) - .5; - ld S = sqrt(U) * (a1 > 0 ? 1 : -1); - ld x = -asinh(S); - h = lorentz(0, 3, -x) * lorentz(1, 2, x) * h; - ld y = h[3]*h[3] > h[2]*h[2] ? atanh(h[1] / h[3]) : atanh(h[0] / h[2]); - h = lorentz(0, 2, -y) * lorentz(1, 3, -y) * h; - ld z = atan2(h[2], h[3]); - return hyperpoint(x, y, z, 0); - } - -/** normalize, and in product geometry, also flatten */ -EX hyperpoint normalize_flat(hyperpoint h) { - if(gproduct) { - if(geom3::euc_in_product()) { - ld bz = zlevel(h); - auto h1 = h / exp(bz); - ld bx = atan_auto(h1[0] / h1[2]); - return zpush(bz) * xpush(bx) * C0; - } - return product_decompose(h).second; - } - if(geom3::euc_in_nil()) h[1] = 0; - if(geom3::euc_in_sl2()) { - hyperpoint h1 = esl2_ati(h); - h1[1] = 0; - return esl2_ita0(h1); - } - else if(sl2) h = slr::translate(h) * zpush0(-atan2(h[2], h[3])); - if(geom3::euc_in_solnih()) h[2] = 0; - if(geom3::hyp_in_solnih()) h[0] = 0; - if(geom3::euc_in_sph()) { - ld tx = hypot(h[0], h[2]); - ld ty = hypot(h[1], h[3]); - h[0] = h[0] / tx * sin(1); - h[1] = h[1] / ty * cos(1); - h[2] = h[2] / tx * sin(1); - h[3] = h[3] / ty * cos(1); - return h; - } - if(geom3::euc_in_hyp()) { - h = normalize(h); - auto h1 = deparabolic13(h); - h1[2] = 0; - return parabolic13(h1); - } - if(geom3::euc_cylinder()) { - h /= h[3]; - ld z = h[1] * h[1] + h[2] * h[2]; - if(z > 0) h[1] /= z, h[2] /= z; - return h; - } - if(geom3::sph_in_euc()) { - ld z = hypot_d(3, h); - if(z > 0) h[0] /= z, h[1] /= z, h[2] /= z; - h[3] = 1; - return h; - } - if(geom3::sph_in_hyp()) { - ld z = hypot_d(3, h); - z = sinh(1) / z; - if(z > 0) h[0] *= z, h[1] *= z, h[2] *= z; - h[3] = cosh(1); - return h; - } - return normalize(h); - } - /** get the center of the line segment from H1 to H2 */ EX hyperpoint mid(const hyperpoint& H1, const hyperpoint& H2) { if(gproduct) { @@ -713,43 +626,6 @@ EX transmatrix cspin180(int a, int b) { return T; } -/** rotate by alpha degrees in the XY plane */ -EX transmatrix spin(ld alpha) { - if(embedded_plane && geom3::euc_in_product()) return Id; - if(embedded_plane && geom3::euc_in_sl2()) return Id; // just looks weird... - if(embedded_plane && geom3::euc_vertical()) return cspin(0, 2, alpha); - if(embedded_plane && geom3::hyp_in_solnih()) return cspin(1, 2, alpha); - return cspin(0, 1, alpha); - } - -EX transmatrix unswap_spin(transmatrix T) { - return cgi.intermediate_to_logical_scaled * T * cgi.logical_scaled_to_intemediate; - } - -/** rotate by 90 degrees in the XY plane */ -EX transmatrix spin90() { - if(embedded_plane && geom3::euc_in_product()) return Id; - if(embedded_plane && geom3::euc_vertical()) return cspin90(0, 2); - if(embedded_plane && geom3::hyp_in_solnih()) return cspin90(1, 2); - return cspin90(0, 1); - } - -/** rotate by 180 degrees in the XY plane */ -EX transmatrix spin180() { - if(embedded_plane && geom3::euc_in_product()) return Id; - if(embedded_plane && geom3::euc_vertical()) return cspin180(0, 2); - if(embedded_plane && geom3::hyp_in_solnih()) return cspin180(1, 2); - return cspin180(0, 1); - } - -/** rotate by 270 degrees in the XY plane */ -EX transmatrix spin270() { - if(embedded_plane && geom3::euc_in_product()) return Id; - if(embedded_plane && geom3::euc_vertical()) return cspin90(2, 0); - if(embedded_plane && geom3::hyp_in_solnih()) return cspin90(2, 1); - return cspin90(1, 0); - } - EX transmatrix random_spin3() { ld alpha2 = asin(randd() * 2 - 1); ld alpha = randd() * TAU; @@ -833,12 +709,6 @@ EX transmatrix cpush(int cid, ld alpha) { return T; } -EX transmatrix lzpush(ld z) { - if(geom3::hyp_in_solnih()) return cpush(0, z); - if(geom3::euc_vertical()) return cpush(1, z); - return cpush(2, z); - } - EX transmatrix cmirror(int cid) { transmatrix T = Id; T[cid][cid] = -1; @@ -848,17 +718,6 @@ EX transmatrix cmirror(int cid) { // push alpha units to the right EX transmatrix xpush(ld alpha) { return cpush(0, alpha); } -EX transmatrix lxpush(ld alpha) { - if(embedded_plane) { - geom3::light_flip(true); - auto t = cpush(0, alpha); - geom3::light_flip(false); - swapmatrix(t); - return t; - } - return cpush(0, alpha); - } - EX bool eqmatrix(transmatrix A, transmatrix B, ld eps IS(.01)) { for(int i=0; i= 4 -/** in the 3D space, move the point h orthogonally to the (x,y) plane by z units */ -EX hyperpoint orthogonal_move(const hyperpoint& h, ld z) { - if(geom3::euc_in_hyp()) { - hyperpoint hf = deparabolic13(h); - hf[2] += z; - return parabolic13(hf); - } - if(geom3::euc_in_nil()) { - return nisot::translate(h) * cpush0(1, z); - } - if(geom3::euc_in_solnih()) { - return nisot::translate(h) * cpush0(2, z); - } - if(geom3::sph_in_euc()) { - ld z0 = hypot_d(3, h); - ld f = ((z0 + z) / z0); - hyperpoint hf; - for(int i=0; i<3; i++) hf[i] = h[i] * f; - hf[3] = 1; - return hf; - } - if(geom3::euc_cylinder()) { - auto hf = h / h[3]; - ld z0 = hypot(h[1], h[2]); - if(!z0) return hf; - ld f = ((z0 + z) / z0); - hf[1] *= f; hf[2] *= f; - return hf; - } - if(geom3::hyp_in_solnih()) { - return nisot::translate(h) * cpush0(0, z); - } - if(geom3::sph_in_hyp()) { - ld z0 = acosh(h[3]); - ld f = sinh(z0 + z) / sinh(z0); - hyperpoint hf; - for(int i=0; i<3; i++) hf[i] = h[i] * f; - hf[3] = cosh(z0 + z); - return hf; - } - if(geom3::euc_in_sph()) { - // cspin(0,2,x) * cspin(1,3,y) * cspin0(2, 3, z) - ld tx = hypot(h[0], h[2]); - ld ty = hypot(h[1], h[3]); - ld z0 = atan2(ty, tx); - z0 -= z; - hyperpoint hf; - hf[0] = h[0] / tx * cos(z0); - hf[1] = h[1] / ty * sin(z0); - hf[2] = h[2] / tx * cos(z0); - hf[3] = h[3] / ty * sin(z0); - return hf; - } - if(geom3::euc_in_product()) { - ld bz = zlevel(h); - auto h1 = h / exp(bz); - ld by = asin_auto(h1[1]); - ld bx = atan_auto(h1[0] / h1[2]); - by += z; - return zpush(bz) * xpush(bx) * ypush(by) * C0; - } - if(geom3::euc_in_sl2()) { - hyperpoint h1 = esl2_ati(h); - h1[1] += z; - return esl2_ita0(h1); - } - if(GDIM == 2) return scale_point(h, geom3::scale_at_lev(z)); - if(gproduct) return scale_point(h, exp(z)); - if(sl2) return slr::translate(h) * cpush0(2, z); - if(!hyperbolic) return rgpushxto0(h) * cpush(2, z) * C0; - if(nil) return nisot::translate(h) * cpush0(2, z); - if(translatable) return hpxy3(h[0], h[1], h[2] + z); - ld u = 1; - if(h[2]) z += asin_auto(h[2]), u /= cos_auto(asin_auto(h[2])); - u *= cos_auto(z); - return hpxy3(h[0] * u, h[1] * u, sinh(z)); - } - -EX ld get_logical_z(hyperpoint h) { - if(geom3::euc_in_nil()) - return h[1]; - if(geom3::euc_in_solnih()) - return h[2]; - if(geom3::hyp_in_solnih()) - return h[0]; - if(geom3::euc_in_sl2()) - return esl2_ati(h)[1]; - if(geom3::euc_in_product()) { - ld bz = zlevel(h); - auto h1 = h / exp(bz); - return asin_auto(h1[1]); - } - if(geom3::euc_cylinder()) { - return hypot(h[1], h[2]) - 1; - } - if(gproduct) - return log(h[2]); - return asin_auto(h[2]) - (moved_center() ? 1 : 0); - } -#endif - // push alpha units vertically EX transmatrix ypush(ld alpha) { return cpush(1, alpha); } @@ -993,134 +750,10 @@ EX transmatrix matrix4(ld a, ld b, ld c, ld d, ld e, ld f, ld g, ld h, ld i, ld #endif } -#if MAXMDIM >= 4 -/** Transform a matrix between the 'embedded_plane' and underlying representation. Switches to the current variant. */ -EX void swapmatrix(transmatrix& T) { - if(geom3::euc_in_hyp() && !geom3::flipped) { - geom3::light_flip(true); - hyperpoint mov = T * C02; - transmatrix U = gpushxto0(mov) * T; - geom3::light_flip(false); - for(int i=0; i<4; i++) U[i][3] = U[3][i] = i == 3; - T = parabolic13(mov[0], mov[1]) * U; - } - else if(geom3::hyp_in_solnih()) { - // rotations are illegal anyway... - hyperpoint h = get_column(T, 2); - swapmatrix(h); - T = rgpushxto0(h); - return; - } - else if(geom3::sph_in_euc() || geom3::sph_in_hyp()) { - if(!geom3::flipped) { - for(int i=0; i<4; i++) T[i][3] = T[3][i] = i == 3; - } - } - else if(geom3::euc_cylinder()) { - if(!geom3::flipped) { - hyperpoint h1 = cgi.logical_to_intermediate * get_column(T, 2); - T = xpush(h1[0]) * cspin(1, 2, h1[1]); - return; - } - } - else if(geom3::euc_in_nil()) { - if(!geom3::flipped) { - hyperpoint h1 = cgi.logical_to_intermediate * get_column(T, 2); - // rotations are illegal anyway... - T = eupush(hyperpoint(h1[0], 0, h1[2], 1)); - return; - } - } - else if(geom3::euc_in_solnih()) { - if(!geom3::flipped) { - hyperpoint h1 = cgi.logical_to_intermediate * get_column(T, 2); - // rotations are illegal anyway... - T = eupush(hyperpoint(h1[0], h1[1], 0, 1)); - return; - } - } - else if(geom3::euc_in_product()) { - hyperpoint h1 = cgi.logical_to_intermediate * get_column(T, 2); - T = xpush(h1[0]) * zpush(h1[2]); - return; - } - else if(geom3::euc_in_sl2() && !geom3::flipped) { - hyperpoint h1 = cgi.logical_to_intermediate * get_column(T, 2); h1[1] = 0; - T = esl2_ita(h1); - return; - } - else if(geom3::in_product()) { - /* just do nothing */ - } - else if(geom3::euc_in_sph()) { - hyperpoint h1 = cgi.logical_to_intermediate * get_column(T, 2); - T = cspin(0, 2, h1[0]) * cspin(1, 3, h1[1]); - } - else { - for(int i=0; i<4; i++) swap(T[i][2], T[i][3]); - for(int i=0; i<4; i++) swap(T[2][i], T[3][i]); - if(GDIM == 3) { - for(int i=0; i<4; i++) T[i][2] = T[2][i] = 0; - T[2][2] = 1; - } - } - fixmatrix(T); - for(int i=0; iis_hyp_in_solnih() && !geom3::flipped) { return ypush(u); } else { @@ -1136,7 +769,7 @@ EX transmatrix parabolic1(ld u) { EX transmatrix parabolic13(ld u, ld v) { if(euclid) return eupush3(0, u, v); - else if(geom3::euc_in_hyp()) { + else if(cgi.emb->is_euc_in_hyp()) { ld diag = (u*u+v*v)/2; return matrix4( 1, 0, -u, u, @@ -1158,7 +791,7 @@ EX transmatrix parabolic13(ld u, ld v) { EX hyperpoint deparabolic13(hyperpoint h) { if(euclid) return h; - if(geom3::euc_in_hyp()) { + if(cgi.emb->is_euc_in_hyp()) { h /= (1 + h[LDIM]); h[2] -= 1; h /= sqhypot_d(LDIM, h); @@ -1174,7 +807,7 @@ EX hyperpoint deparabolic13(hyperpoint h) { EX hyperpoint parabolic13(hyperpoint h) { if(euclid) return h; - else if(geom3::euc_in_hyp()) { + else if(cgi.emb->is_euc_in_hyp()) { return parabolic13(h[0], h[1]) * cpush0(2, h[2]); } else if(LDIM == 3) @@ -1185,7 +818,7 @@ EX hyperpoint parabolic13(hyperpoint h) { EX transmatrix parabolic13_at(hyperpoint h) { if(euclid) return rgpushxto0(h); - else if(geom3::euc_in_hyp()) { + else if(cgi.emb->is_euc_in_hyp()) { return parabolic13(h[0], h[1]) * cpush(2, h[2]); } else if(LDIM == 3) @@ -1235,26 +868,6 @@ EX transmatrix rspintox(const hyperpoint& H) { return rspintoc(H, 0, 1) * rspintoc(T1*H, 0, 2); } -EX transmatrix lspintox(const hyperpoint& H) { - if(geom3::euc_in_product()) return Id; - if(geom3::euc_in_sl2()) return Id; - if(geom3::euc_vertical()) return spintoc(H, 0, 2); - if(geom3::hyp_in_solnih()) return spintoc(H, 1, 2); - if(WDIM == 2 || gproduct) return spintoc(H, 0, 1); - transmatrix T1 = spintoc(H, 0, 1); - return spintoc(T1*H, 0, 2) * T1; - } - -EX transmatrix lrspintox(const hyperpoint& H) { - if(geom3::euc_in_product()) return Id; - if(geom3::euc_in_sl2()) return Id; - if(geom3::euc_vertical()) return rspintoc(H, 0, 2); - if(geom3::hyp_in_solnih()) return rspintoc(H, 2, 1); - if(WDIM == 2 || gproduct) return rspintoc(H, 0, 1); - transmatrix T1 = spintoc(H, 0, 1); - return rspintoc(H, 0, 1) * rspintoc(T1*H, 0, 2); - } - /** for H on the X axis, this matrix pushes H to C0 * \see gpushxto0 */ @@ -1688,25 +1301,8 @@ EX hyperpoint scale_point(const hyperpoint& h, ld scale_factor) { return res; } -EX bool moved_center() { - if(geom3::sph_in_euc()) return true; - if(geom3::sph_in_hyp()) return true; - if(geom3::euc_in_sph()) return true; - if(geom3::euc_cylinder()) return true; - return false; - } - -/** Returns the intended center of the tile, relative to its local matrix. Usually C0 but may be different, e.g. when embedding a sphere in E3 or H3. */ -EX hyperpoint tile_center() { - if(geom3::sph_in_euc()) return C02 + C03; - if(geom3::euc_in_sph()) return zpush0(1); - if(geom3::sph_in_hyp()) return zpush0(1); - if(geom3::euc_cylinder()) return zpush0(1); - return C0; - } - EX transmatrix orthogonal_move(const transmatrix& t, double level) { - if(gproduct && !geom3::euc_in_product()) return scale_matrix(t, exp(level)); + if(gproduct && !cgi.emb->is_euc_in_product()) return scale_matrix(t, exp(level)); if(GDIM == 3) return t * lzpush(level); return scale_matrix(t, geom3::lev_to_factor(level)); } @@ -1821,7 +1417,7 @@ EX bool use_embedded_shift(eShiftMethodApplication sma) { EX eShiftMethod shift_method(eShiftMethodApplication sma) { if(gproduct) return smProduct; - if(embedded_plane && sma == smaObject) return geom3::same_in_same() ? smIsotropic : smEmbedded; + if(embedded_plane && sma == smaObject) return cgi.emb->is_same_in_same() ? smIsotropic : smEmbedded; if(embedded_plane && use_embedded_shift(sma)) return sl2 ? smESL2 : nonisotropic ? smLie : smEmbedded; if(!nonisotropic && !stretch::in() && !(!nisot::geodesic_movement && hyperbolic && bt::in())) return smIsotropic; if(!nisot::geodesic_movement && !embedded_plane) return smLie; @@ -1843,27 +1439,27 @@ EX transmatrix shift_object(transmatrix Position, const transmatrix& ori, const } case smEmbedded: { - if(geom3::euc_in_hyp() || geom3::sph_in_low()) { + if(cgi.emb->is_euc_in_hyp() || cgi.emb->is_sph_in_low()) { geom3::light_flip(true); transmatrix T = rgpushxto0(direct_exp(direction)); geom3::light_flip(false); - swapmatrix(T); - return Position * T; + return Position * cgi.emb->base_to_actual(T); } - if(geom3::euc_in_sph()) Position = inverse(View) * Position; + if(cgi.emb->is_euc_in_sph()) Position = inverse(View) * Position; - transmatrix rot = inverse(map_relative_push(Position * tile_center())) * Position; - if(moved_center()) rot = rot * lzpush(1); + transmatrix rot = inverse(cgi.emb->map_relative_push(Position * tile_center())) * Position; + ld z = cgi.emb->center_z(); + if(z) rot = rot * lzpush(z); transmatrix urot = unswap_spin(rot); geom3::light_flip(true); transmatrix T = rgpushxto0(direct_exp(urot * direction)); geom3::light_flip(false); - swapmatrix(T); + T = cgi.emb->base_to_actual(T); auto res = Position * inverse(rot) * T * rot; - if(geom3::euc_in_sph()) res = View * res; + if(cgi.emb->is_euc_in_sph()) res = View * res; return res; } default: throw hr_exception("unknown shift method in shift_object"); @@ -1875,7 +1471,7 @@ EX void apply_shift_object(transmatrix& Position, const transmatrix orientation, } EX void rotate_object(transmatrix& Position, transmatrix& orientation, transmatrix R) { - if(geom3::euc_in_product()) orientation = orientation * R; + if(cgi.emb->is_euc_in_product()) orientation = orientation * R; else if(gproduct && WDIM == 3) orientation = orientation * R; else Position = Position * R; } @@ -1931,16 +1527,6 @@ EX transmatrix transpose(transmatrix T) { return result; } -EX hyperpoint lspinpush0(ld alpha, ld x) { - bool f = embedded_plane; - if(f) geom3::light_flip(true); - if(embedded_plane) throw hr_exception("still embedded plane"); - hyperpoint h = xspinpush0(alpha, x); - if(f) geom3::light_flip(false); - if(f) swapmatrix(h); - return h; - } - #if HDR namespace slr { hyperpoint xyz_point(ld x, ld y, ld z); @@ -1960,7 +1546,6 @@ inline hyperpoint cpush0(int c, ld x) { } inline hyperpoint xpush0(ld x) { return cpush0(0, x); } -inline hyperpoint lxpush0(ld x) { return lxpush(x) * tile_center(); } inline hyperpoint ypush0(ld x) { return cpush0(1, x); } inline hyperpoint zpush0(ld x) { return cpush0(2, x); } @@ -1978,16 +1563,6 @@ inline shiftpoint tC0(const shiftmatrix &T) { } #endif -EX hyperpoint xspinpush0(ld alpha, ld x) { - if(embedded_plane) return lspinpush0(alpha, x); - if(sl2) return slr::polar(x, -alpha, 0); - hyperpoint h = Hypc; - h[LDIM] = cos_auto(x); - h[0] = sin_auto(x) * cos(alpha); - h[1] = sin_auto(x) * -sin(alpha); - return h; - } - /** tangent vector in the given direction */ EX hyperpoint ctangent(int c, ld x) { return point3(c==0?x:0, c==1?x:0, c==2?x:0); } @@ -1997,13 +1572,6 @@ EX hyperpoint xtangent(ld x) { return ctangent(0, x); } /** tangent vector in direction Z */ EX hyperpoint ztangent(ld z) { return ctangent(2, z); } -/** tangent vector in logical direction Z */ -EX hyperpoint lztangent(ld z) { - if(geom3::hyp_in_solnih()) return ctangent(0, z); - if(geom3::euc_vertical()) return ctangent(1, z); - return ctangent(2, z); - } - /** change the length of the targent vector */ EX hyperpoint tangent_length(hyperpoint dir, ld length) { ld r = hypot_d(GDIM, dir); @@ -2108,7 +1676,7 @@ EX unsigned bucketer(hyperpoint h) { auto d = product_decompose(h); h = d.second; dx += bucketer(d.first) * 50; - if(geom3::euc_in_product() && in_h2xe()) h /= h[2]; + if(cgi.emb->is_euc_in_product() && in_h2xe()) h /= h[2]; } dx += bucketer(h[0]) + 1000 * bucketer(h[1]) + 1000000 * bucketer(h[2]); if(MDIM == 4) dx += bucketer(h[3]) * 1000000001; diff --git a/hypgraph.cpp b/hypgraph.cpp index df042818..448ded00 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -1625,7 +1625,7 @@ EX bool in_smart_range(const shiftmatrix& T) { ld x = current_display->xcenter + current_display->radius * h1[0]; ld y = current_display->ycenter + current_display->radius * h1[1] * pconf.stretch; - bool culling = !geom3::euc_in_hyp(); + bool culling = !cgi.emb->is_euc_in_hyp(); bool inp = in_perspective(); if(culling) { @@ -1908,10 +1908,10 @@ EX hyperpoint vertical_vector() { if(gproduct && vid.fixed_yz) { return get_view_orientation() * lztangent(embedded_plane ? vid.wall_height : 1); } - if(embedded_plane && geom3::same_in_same()) + if(cgi.emb->is_same_in_same()) return get_view_orientation() * lztangent(vid.wall_height); - if(geom3::euc_in_sl2() || geom3::euc_in_sph()) { - transmatrix Rot = View * map_relative_push(inverse(View) * C0); + if(cgi.emb->is_euc_in_sl2() || cgi.emb->is_euc_in_sph()) { + transmatrix Rot = View * cgi.emb->map_relative_push(inverse(View) * C0); return Rot * lztangent(vid.wall_height); } if(embedded_plane && vid.fixed_yz && nonisotropic) { @@ -2033,19 +2033,19 @@ EX void adjust_eye(transmatrix& T, cell *c, ld sign) { geom3::do_auto_eye(); int sl = snakelevel(c); if(isWorm(c->monst) && sl < 3) sl++; - int i = moved_center() ? 1 : 0; + ld i = cgi.emb->center_z(); if(sl || vid.eye || i) T = T * lzpush(sign * (cgi.SLEV[sl] - cgi.FLOOR - vid.eye + i)); } /** achieve top-down perspective */ EX transmatrix default_spin() { - return cspin90(0, 1) * cgi.intermediate_to_logical_scaled; + return cspin90(0, 1) * cgi.emb->intermediate_to_logical_scaled; } EX bool shmup_inverted() { if(!embedded_plane) return false; - return (vid.wall_height < 0) ^ (geom3::euc_in_nil() || geom3::euc_in_sl2()); + return (vid.wall_height < 0) ^ (cgi.emb->is_euc_in_nil() || cgi.emb->is_euc_in_sl2()); } EX void centerpc(ld aspd) { @@ -2251,7 +2251,7 @@ EX void resetview() { if(WDIM == 2) vo = spin(M_PI + vid.fixed_facing_dir * degree) * vo; if(WDIM == 3) vo = cspin90(0, 2) * vo; - vo = cgi.intermediate_to_logical_scaled * vo; + vo = cgi.emb->intermediate_to_logical_scaled * vo; if(embedded_plane) vo = cspin90(1, 2) * vo; if(embedded_plane && vid.wall_height < 0) vo = cspin180(0, 1) * vo; @@ -2917,7 +2917,7 @@ EX namespace dq { EX queue> drawqueue; EX unsigned bucketer(const shiftpoint& T) { - if(geom3::euc_in_sl2()) { + if(cgi.emb->is_euc_in_sl2()) { auto T1 = T; optimize_shift(T1); return bucketer(T1.h) + unsigned(floor(T1.shift*81527+.5)); } @@ -3308,10 +3308,10 @@ EX void shift_v_by_vector(transmatrix& V, const hyperpoint H, eShiftMethod sm IS case smESL2: { hyperpoint H1 = esl2_ita0(lp_iapply(-H)); transmatrix IV = view_inverse(V); - transmatrix rot = V * map_relative_push(IV * C0); + transmatrix rot = V * cgi.emb->map_relative_push(IV * C0); transmatrix V1 = gpushxto0(H1) * gpushxto0(IV*C0); transmatrix IV1 = view_inverse(V1); - transmatrix rot1 = V1 * map_relative_push(IV1 * C0); + transmatrix rot1 = V1 * cgi.emb->map_relative_push(IV1 * C0); V = rot * inverse(rot1) * V1; return; } @@ -3344,10 +3344,10 @@ EX void shift_view(hyperpoint H, eShiftMethod sm IS(shift_method(smaManualCamera /** works in embedded_plane (except embedded product where shift_view works, and euc_in_sl2) */ EX void shift_v_embedded(transmatrix& V, const transmatrix T) { transmatrix IV = view_inverse(V); - transmatrix rot = V * map_relative_push(IV * C0); + transmatrix rot = V * cgi.emb->map_relative_push(IV * C0); transmatrix V1 = T * V; transmatrix IV1 = view_inverse(V1); - transmatrix rot1 = V1 * map_relative_push(IV1 * C0); + transmatrix rot1 = V1 * cgi.emb->map_relative_push(IV1 * C0); V = rot * inverse(rot1) * V1; } @@ -3364,54 +3364,6 @@ EX void shift_v_by_matrix(transmatrix& V, const transmatrix T, eShiftMethod sm) } } -/* like rgpushxto0 but keeps the map orientation correct */ -EX transmatrix map_relative_push(hyperpoint h) { - if(!embedded_plane) return rgpushxto0(h); - if(geom3::euc_in_product()) { - ld bz = zlevel(h); - auto h1 = h / exp(bz); - ld by = asin_auto(h1[1]); - ld bx = atan_auto(h1[0] / h1[2]); - return zpush(bz) * xpush(bx) * ypush(by); - } - if(geom3::same_in_same()) { - ld z = -asin_auto(h[2]); - ld u = 1 / cos_auto(z); - auto h1 = hpxy3(h[0] * u, h[1] * u, 0); - - transmatrix T = rgpushxto0(h1) * zpush(-z); - return T; - } - if(geom3::euc_in_hyp()) { - auto h1 = deparabolic13(h); - return parabolic13_at(h1); - } - if(msphere) { - ld z = hdist0(h); - geom3::light_flip(true); - auto h1 = normalize(h); - transmatrix T = rgpushxto0(h1); - geom3::light_flip(false); - return T * zpush(z); - } - if(geom3::euc_in_sl2()) { - auto h1 = esl2_ati(h); - return esl2_zpush(h1[2]) * xpush(h1[0]) * ypush(h1[1]); - } - if(geom3::euc_cylinder()) { - ld z0 = hypot(h[1], h[2]); - if(!z0) return Id; - transmatrix T = xpush(h[0]) * cspin(1, 2, atan2(h[1], h[2])) * zpush(z0); - return T; - } - if(geom3::euc_in_sph()) { - ld tx = hypot(h[0], h[2]); - ld ty = hypot(h[1], h[3]); - return cspin(0, 2, atan2(h[0], h[2])) * cspin(1, 3, atan2(h[1], h[3])) * cspin(2, 3, atan2(tx, ty)); - } - return rgpushxto0(h); - } - EX void shift_view_to(shiftpoint H, eShiftMethod sm IS(shift_method(smaManualCamera))) { shift_v_to(View, H, sm); shift_v_to(current_display->which_copy, H, sm); diff --git a/intra.cpp b/intra.cpp index 5e7022ca..2e310e2c 100644 --- a/intra.cpp +++ b/intra.cpp @@ -163,7 +163,7 @@ EX portal_data make_portal(cellwalker cw, int spin) { #if CAP_BT if(bt::in()) { for(auto h: fac) - println(hlog, PIU(deparabolic13(normalize_flat(h)))); + println(hlog, PIU(deparabolic13(cgi.emb->normalize_flat(h)))); if(cw.spin == cw.at->type - 2) fac.pop_back(); else @@ -176,7 +176,7 @@ EX portal_data make_portal(cellwalker cw, int spin) { else { hyperpoint ctr = Hypc; for(auto p: fac) ctr += product_decompose(p).second; - ctr = normalize_flat(ctr); + ctr = cgi.emb->normalize_flat(ctr); id.T = gpushxto0(ctr); } } @@ -185,8 +185,8 @@ EX portal_data make_portal(cellwalker cw, int spin) { id.v0 = Hypc; id.scale = cgi.plevel; for(auto p: fac) id.v0 += p; - id.v0 = normalize_flat(id.v0); - hyperpoint h = normalize_flat(fac[0]); + id.v0 = cgi.emb->normalize_flat(id.v0); + hyperpoint h = cgi.emb->normalize_flat(fac[0]); id.T = cspin90(1, 0) * spintox(gpushxto0(id.v0) * h) * gpushxto0(id.v0); if((id.T * C0)[0] > 0) id.T = spin180() * id.T; for(int i=0; i<3; i++) id.T[3][i] = id.T[i][3] = i==3; diff --git a/irregular.cpp b/irregular.cpp index 3195099b..ac1ad33d 100644 --- a/irregular.cpp +++ b/irregular.cpp @@ -1058,12 +1058,12 @@ EX array get_masters(cell *c) { EX void swap_vertices() { for(auto& c: cells) { - swapmatrix(c.p); + swappoint(c.p); swapmatrix(c.pusher); swapmatrix(c.rpusher); - for(auto& jp: c.jpoints) swapmatrix(jp); + for(auto& jp: c.jpoints) swappoint(jp); for(auto& rm: c.relmatrices) swapmatrix(rm.second); - for(auto& v: c.vertices) swapmatrix(v); + for(auto& v: c.vertices) swappoint(v); } } diff --git a/kite.cpp b/kite.cpp index 8d086bdf..ee954245 100644 --- a/kite.cpp +++ b/kite.cpp @@ -305,7 +305,7 @@ struct hrmap_kite : hrmap { if(emb) { geom3::light_flip(false); - for(auto& g: graphrules) swapmatrix(g.second); + for(auto& g: graphrules) g.second = cgi.emb->base_to_actual(g.second); geom3::light_flip(f); } diff --git a/nonisotropic.cpp b/nonisotropic.cpp index f18243e4..be839dfe 100644 --- a/nonisotropic.cpp +++ b/nonisotropic.cpp @@ -1370,7 +1370,7 @@ EX namespace hybrid { template auto in_underlying_geometry(const T& f) -> decltype(f()) { if(!mhybrid && !gproduct) return f(); if(embedded_plane) { - if(geom3::euc_in_product()) { + if(cgi.emb->is_euc_in_product()) { dynamicval dgc(cginf.g.kind, cginf.g.sig[2] < 0 ? gcHyperbolic : gcSphere); return f(); } diff --git a/polygons.cpp b/polygons.cpp index 70af6ab5..68870632 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -112,7 +112,7 @@ void geometry_information::chasmifyPoly(double fol, double fol2, int k) { if(zf == isize(points)-1) zf--; x -= zf; auto hp = points[zf] + (points[zf+1] - points[zf]) * x; - auto hf = normalize_flat(hp); + auto hf = cgi.emb->normalize_flat(hp); auto ho = orthogonal_move(hf, fol + (fol2-fol) * y); hpcpush(ho); }; @@ -931,7 +931,7 @@ void geometry_information::make_wall(int id, vector vertices, vector ld w = 0; for(int i=0; inormalize_flat(center); else center /= w; ld center_altitude = 0; @@ -963,7 +963,7 @@ void geometry_information::make_wall(int id, vector vertices, vector h = nilv::on_geodesic(center, nilv::on_geodesic(v1+center, v2+center, y / (x+y)), x + y); if(mproduct) { if(bt::in()) h = PIU( parabolic13(h) ); - h = orthogonal_move(normalize_flat(h), center_altitude * (1-x-y) + altitudes[a] * x + altitudes[b] * y); + h = orthogonal_move(cgi.emb->normalize_flat(h), center_altitude * (1-x-y) + altitudes[a] * x + altitudes[b] * y); hpcpush(h); return; } hpcpush(final_coords(h)); @@ -978,7 +978,7 @@ void geometry_information::make_wall(int id, vector vertices, vector hyperpoint h = (vertices[a] * (STEP-y) + vertices[(a+1)%n] * y)/STEP; if(mproduct) { if(bt::in()) h = PIU( parabolic13(h) ); - h = orthogonal_move(normalize_flat(h), (altitudes[a] * (STEP-y) + altitudes[(a+1)%n] * y) / STEP); + h = orthogonal_move(cgi.emb->normalize_flat(h), (altitudes[a] * (STEP-y) + altitudes[(a+1)%n] * y) / STEP); hpcpush(h); } else if(nil) diff --git a/radar.cpp b/radar.cpp index 7511ea84..5b5613a9 100644 --- a/radar.cpp +++ b/radar.cpp @@ -28,7 +28,7 @@ pair makeradar(shiftpoint h) { if(d) h1 = h1 * (d / vid.radarrange / hypot_d(3, h1)); } else if(mhyperbolic) { - if(geom3::hyp_in_solnih()) { + if(cgi.emb->is_hyp_in_solnih()) { geom3::light_flip(true); h1 = parabolic1(h1[1]) * xpush0(h1[0]); geom3::light_flip(false); @@ -38,11 +38,11 @@ pair makeradar(shiftpoint h) { for(int a=0; ais_same_in_same()) h1[2] = h1[LDIM]; + if(hyperbolic) h1 /= sinh(1); } else { - if(geom3::euc_in_hyp()) { + if(cgi.emb->is_euc_in_hyp()) { for(int a=0; a<3; a++) h1[a] = h1[a] / (1 + h1[3]); h1[2] -= 1; h1 *= 2 / sqhypot_d(3, h1); @@ -50,35 +50,35 @@ pair makeradar(shiftpoint h) { if(d > vid.radarrange) return {false, h1}; if(d) h1 = h1 / (vid.radarrange + cgi.scalefactor/4); } - else if(geom3::same_in_same()) { + else if(cgi.emb->is_same_in_same()) { if(d > vid.radarrange) return {false, h1}; if(d) h1 = h1 * (d / (vid.radarrange + cgi.scalefactor/4) / hypot_d(3, h1)); } - else if(geom3::euc_in_sph()) { + else if(cgi.emb->is_euc_in_sph()) { h1[0] = atan2(h.h[0], h.h[2]); h1[1] = atan2(h.h[1], h.h[3]); h1[2] = 0; - h1 = cgi.intermediate_to_logical * h1; + h1 = cgi.emb->intermediate_to_logical * h1; d = hypot_d(2, h1); if(d > vid.radarrange) return {false, h1}; if(d) h1 = h1 / (vid.radarrange + cgi.scalefactor/4); } - else if(geom3::euc_cylinder()) { + else if(cgi.emb->is_cylinder()) { h1[0] = h.h[0]; h1[1] = atan2(h.h[1], h.h[2]); h1[2] = 0; - h1 = cgi.intermediate_to_logical * h1; + h1 = cgi.emb->intermediate_to_logical * h1; d = hypot_d(2, h1); if(d > vid.radarrange) return {false, h1}; if(d) h1 = h1 / (vid.radarrange + cgi.scalefactor/4); } - else if(geom3::euc_in_sl2()) { - h1 = cgi.intermediate_to_logical * esl2_ati(unshift(h)); h1[1] = -h1[1]; + else if(cgi.emb->is_euc_in_sl2()) { + h1 = cgi.emb->intermediate_to_logical * esl2_ati(unshift(h)); h1[1] = -h1[1]; d = hypot_d(2, h1); if(d > vid.radarrange) return {false, h1}; if(d) h1 = h1 / (vid.radarrange + cgi.scalefactor/4); } - else if(geom3::euc_in_product()) { + else if(cgi.emb->is_euc_in_product()) { if(in_h2xe()) h1[0] = atanh(h.h[0] / h.h[2]); else @@ -86,7 +86,7 @@ pair makeradar(shiftpoint h) { h1[2] = - zlevel(h.h) - h.shift; h1[1] = 0; h1[3] = 0; - h1 = cgi.intermediate_to_logical * h1; + h1 = cgi.emb->intermediate_to_logical * h1; d = hypot_d(2, h1); if(d > vid.radarrange) return {false, h1}; if(d) h1 = h1 / (vid.radarrange + cgi.scalefactor/4); diff --git a/raycaster.cpp b/raycaster.cpp index 759e91d3..57957227 100644 --- a/raycaster.cpp +++ b/raycaster.cpp @@ -395,7 +395,7 @@ void raygen::compute_which_and_dist(int flat1, int flat2) { " mediump vec4 next_position = position + d * tangent;\n" " if(dot(next_position, tangent) < dot(m*next_position, m*tangent)) continue;\n" " d /= xspeed;\n"; - else if(geom3::sph_in_hyp()) fmain += + else if(cgi.emb->is_sph_in_low() && hyperbolic) fmain += " mediump float v = ((zpush_h3(-1.) * (position - m * position))[3] / (zpush_h3(-1.) * (m * tangent - tangent))[3]);\n" " if(v > 1. || v < -1.) continue;\n" " mediump float d = atanh(v);\n" @@ -412,7 +412,7 @@ void raygen::compute_which_and_dist(int flat1, int flat2) { " mediump float d = atan(v);\n" " mediump vec4 next_tangent = -position * sin(d) + tangent * cos(d);\n" " if(next_tangent[3] > (m * next_tangent)[3]) continue;\n"; - else if(geom3::sph_in_euc()) fmain += + else if(cgi.emb->is_sph_in_low() && euclid) fmain += " vec4 tctr = vec4(0, 0, 1, 0);\n" " mediump float deno = dot(position-tctr, tangent) - dot(m*position-tctr, m*tangent);\n" " if(deno < 1e-6 && deno > -1e-6) continue;\n" @@ -2119,7 +2119,7 @@ EX transmatrix get_ms(cell *c, int a, bool mirror) { } h = normalize(h); ld d = hdist0(h); - if(moved_center()) d -= 1; + d -= cgi.emb->center_z(); if(h[2] > 0) d = -d; if(mirror) return MirrorZ * lzpush(2*d); return lzpush(2*d); diff --git a/shaders.cpp b/shaders.cpp index 6952baef..dfac1b3b 100644 --- a/shaders.cpp +++ b/shaders.cpp @@ -450,7 +450,7 @@ shared_ptr write_shader(flagtype shader_flags) { if(shader_flags & GF_NO_FOG) { vmain += "// no fog used\n"; } - else if(GDIM == 3 && WDIM == 2 && hyperbolic && context_fog && geom3::same_in_same() && pmodel == mdPerspective) { + else if(GDIM == 3 && WDIM == 2 && hyperbolic && context_fog && cgi.emb->is_same_in_same() && pmodel == mdPerspective) { vsh += "uniform mediump mat4 uRadarTransform;\n" "uniform mediump sampler2D tAirMap;\n" @@ -582,7 +582,7 @@ void display_data::set_projection(int ed, ld shift) { if(sol && solv_all) id |= 1; if(in_h2xe()) id |= 1; if(in_s2xe()) id |= 2; - if(WDIM == 2 && GDIM == 3 && hyperbolic && context_fog && geom3::same_in_same()) id |= 1; + if(WDIM == 2 && GDIM == 3 && hyperbolic && context_fog && cgi.emb->is_same_in_same()) id |= 1; shared_ptr selected; if(matched_programs.count(id)) selected = matched_programs[id]; diff --git a/shmup.cpp b/shmup.cpp index f7a6a03d..4fd613cd 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -64,14 +64,8 @@ struct monster { int split_owner; ///< in splitscreen mode, which player handles this int split_tick; ///< in which tick was split_owner computed - void reset() { - nextshot = 0; - stunoff = 0; blowoff = 0; fragoff = 0; footphase = 0; - inertia = Hypc; ori = Id; vel = 0; - swordangle = 0; - if(geom3::euc_in_product()) ori = cgi.intermediate_to_logical_scaled; - } - + void reset(); + monster() { reset(); refs = 1; split_tick = -1; split_owner = -1; @@ -106,6 +100,14 @@ struct monster { }; #endif +void monster::reset() { + nextshot = 0; + stunoff = 0; blowoff = 0; fragoff = 0; footphase = 0; + inertia = Hypc; ori = Id; vel = 0; + swordangle = 0; + if(cgip && cgi.emb && cgi.emb->is_euc_in_product()) ori = cgi.emb->intermediate_to_logical_scaled; + } + using namespace multi; eItem targetRangedOrbKey(enum orbAction a); @@ -186,12 +188,12 @@ cell *monster::findbase(const shiftmatrix& T, int maxsteps) { /** fix the matrix, including the appropriate fixes for nonisotropic, embedded_plane, and elliptic space */ void full_fix(transmatrix& T) { if(embedded_plane) { - if(geom3::sph_in_low()) { + if(cgi.emb->is_sph_in_low()) { for(int i=0; i<4; i++) T[i][3] = 0, T[3][i] = 0; T[3][3] = 1; fixmatrix(T); } - else if(geom3::same_in_same()) { + else if(cgi.emb->is_same_in_same()) { for(int i=0; i<4; i++) T[i][2] = 0, T[2][i] = 0; T[2][2] = 1; fixmatrix(T); @@ -201,14 +203,14 @@ void full_fix(transmatrix& T) { } else { hyperpoint h = T * tile_center(); - transmatrix rot = iso_inverse(map_relative_push(h)) * T; - if(geom3::euc_in_sph()) rot = rot * lzpush(1); + transmatrix rot = iso_inverse(cgi.emb->map_relative_push(h)) * T; + if(cgi.emb->is_euc_in_sph()) rot = rot * lzpush(1); fix_rotation(rot); - if(geom3::hyp_in_solnih()) h[0] = 0; - else if(geom3::euc_in_nil()) h[1] = 0; + if(cgi.emb->is_hyp_in_solnih()) h[0] = 0; + else if(cgi.emb->is_euc_in_nil()) h[1] = 0; - T = map_relative_push(h) * rot; - if(geom3::euc_in_sph()) T = T * lzpush(-1); + T = cgi.emb->map_relative_push(h) * rot; + if(cgi.emb->is_euc_in_sph()) T = T * lzpush(-1); fixmatrix(T); } } @@ -940,7 +942,7 @@ void movePlayer(monster *m, int delta) { if(playerturn[cpid] && canmove && !blown && WDIM == 2) { m->swordangle -= playerturn[cpid]; - if(geom3::euc_in_product()) + if(cgi.emb->is_euc_in_product()) rotate_object(nat.T, m->ori, cspin(0, 1, playerturn[cpid])); else rotate_object(nat.T, m->ori, spin(playerturn[cpid])); diff --git a/sky.cpp b/sky.cpp index 83a96b7c..73314494 100644 --- a/sky.cpp +++ b/sky.cpp @@ -43,7 +43,7 @@ EX struct dqi_sky *sky; EX void prepare_sky() { sky = NULL; - if(euclid && !geom3::sph_in_euc() && !geom3::euc_cylinder()) { + if(euclid && !cgi.emb->is_sph_in_low() && !cgi.emb->is_cylinder()) { if(WDIM == 3 || GDIM == 2) return; if(no_wall_rendering) return; if(!draw_sky) return; @@ -69,14 +69,14 @@ EX void delete_sky() { void compute_skyvertices(const vector& sky) { skyvertices.clear(); if(!draw_sky) return; - if(vid.wall_height < 0 && geom3::euc_in_hyp()) return; /* just looks bad, hollow horospheres should not have sky */ + if(vid.wall_height < 0 && cgi.emb->is_euc_in_hyp()) return; /* just looks bad, hollow horospheres should not have sky */ if(vid.wall_height < 0 && meuclid && geom3::ggclass() == gcNIH) return; /* same */ if(among(geom3::ggclass(), gcSol, gcSolN)) return; /* errors */ if(among(geom3::ggclass(), gcNil)) return; /* errors sometimes too */ - if(geom3::hyp_in_solnih()) return; - if(geom3::euc_in_product()) return; - if(geom3::euc_in_sl2()) return; - if(geom3::euc_cylinder()) return; + if(cgi.emb->is_hyp_in_solnih()) return; + if(cgi.emb->is_euc_in_product()) return; + if(cgi.emb->is_euc_in_sl2()) return; + if(cgi.emb->is_cylinder()) return; int sk = get_skybrightness(); @@ -231,16 +231,16 @@ void compute_skyvertices(const vector& sky) { for(int i=0; inormalize_flat(p); for(auto& p: vertices) ctr = ctr + p; - ctr = normalize_flat(ctr); + ctr = cgi.emb->normalize_flat(ctr); for(int j=0; jnormalize_flat(h); color_t co = gradient(ccolor, gradient(vcolors[j], vcolors[j1], 0, y, x+y), 0, x+y, prec); // co = (hrand(0x1000000) << 8) | 0xFF; // co = minecolors[(x+2*y) % 7] << 8 | 0xFF; @@ -311,10 +311,12 @@ EX void be_euclidean_infinity(transmatrix& V) { for(int i=0; i<3; i++) V[i][3] = void draw_star(const shiftmatrix& V, const hpcshape& sh, color_t col, ld rev = false) { ld star_val = 2; - bool have_stars = geom3::same_in_same() || geom3::sph_in_euc() || geom3::sph_in_hyp() || geom3::euc_in_hyp(); - if(geom3::sph_in_euc()) { if(cgi.SKY < 0) have_stars = false; star_val = 1.8; } - if(geom3::sph_in_hyp() && cgi.SKY < 0) have_stars = false; - if(geom3::euc_in_hyp() && (rev ? cgi.SKY > 0 : cgi.SKY < 0)) have_stars = false; + bool have_stars = cgi.emb->is_same_in_same() || cgi.emb->is_sph_in_low() || cgi.emb->is_euc_in_hyp(); + if(cgi.emb->is_sph_in_low()) { + if(cgi.SKY < 0) have_stars = false; + if(euclid) star_val = 1.8; + } + if(cgi.emb->is_euc_in_hyp() && (rev ? cgi.SKY > 0 : cgi.SKY < 0)) have_stars = false; if(!have_stars) return; ld val = cgi.SKY+star_val; if(rev) val = -val; @@ -339,7 +341,7 @@ void celldrawer::draw_ceiling() { switch(ceiling_category(c)) { /* ceilingless levels */ case 1: { - if(euclid && !geom3::sph_in_euc()) return; + if(euclid && !cgi.emb->is_sph_in_low()) return; if(fieldpattern::fieldval_uniq(c) % 3 == 0) draw_star(V, cgi.shNightStar, 0xFFFFFFFF); add_to_sky(0x00000F, 0x00000F); @@ -354,7 +356,7 @@ void celldrawer::draw_ceiling() { } case 2: { - if(euclid && !geom3::sph_in_euc()) return; + if(euclid && !cgi.emb->is_sph_in_low()) return; color_t col; color_t skycol; @@ -583,6 +585,8 @@ EX void make_air() { pconf.stretch = 1; pmodel = mdDisk; + auto cgi1 = &cgi; + vid.always3 = false; geom3::apply_always3(); check_cgi(); @@ -603,7 +607,7 @@ EX void make_air() { S = g.T.T; S = current_display->radar_transform * S; geometry = orig; - swapmatrix(S); + S = cgi1.emb->actual_to_base(S); } auto& h = cgi.shFullFloor.b[shvid(g.c)];