rewritten the embeddings more nicely

This commit is contained in:
Zeno Rogue 2023-01-27 00:27:10 +01:00
parent 8744420504
commit 85dffdbeff
28 changed files with 1148 additions and 1090 deletions

View File

@ -34,9 +34,8 @@ vector<hyperpoint> geometry_information::get_shape(hpcshape sh) {
hyperpoint get_center(const vector<hyperpoint>& 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<hyperpoint> scaleshape(const vector<hyperpoint>& vh, ld s) {
vector<hyperpoint> 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<hyperpoint, 3> 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<hyperpoint, 3> 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; i<n; i++) if(!stillin[i] && !stillin[lastid[i]]) lastid[i] = lastid[lastid[i]];
for(int i=0; i<n; i++) {
if(!stillin[i]) gbody[i] = normalize_flat(gbody[lastid[i]] * (i - lastid[i]) + gbody[nextid[i]] * (nextid[i] - i));
if(!stillin[i]) gbody[i] = cgi.emb->normalize_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<int> 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<eye.e; i++) if(q == 1 || hpc[i][1] > 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<eye.e; i++) if(q == 1 || hpc[i][1] > 0) rad += hdist(center, hpc[i]);
@ -761,7 +763,7 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye
vector<hyperpoint> pss;
for(int i=head.s; i<head.e; i++) pss.push_back(psmin(lzpush(shift_head - (moved_center() ? 1 : 0)) * hpc[i]));
for(int i=head.s; i<head.e; i++) pss.push_back(psmin(lzpush(shift_head - cgi.emb->center_z()) * hpc[i]));
ld zmid = 0;
for(hyperpoint& h: pss) zmid += h[2];

View File

@ -2136,7 +2136,7 @@ EX void swap_vertices() {
for(auto& p: {&current, &slided})
for(auto& s: p->shapes)
for(auto& v: s.vertices)
swapmatrix(v);
swappoint(v);
}
#if MAXMDIM >= 4

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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();
}

View File

@ -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

955
embeddings.cpp Normal file
View File

@ -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<pair<string, string>> 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<geometryinfo> 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<class T> auto in_flipped(const T& f) -> decltype(f()) {
light_flip(true);
finalizer ff([] { light_flip(false); });
return f();
}
template<class T> 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<MDIM; i++) for(int j=0; j<MDIM; j++) if(isnan(T[i][j])) return Id;
return T;
}
hyperpoint base_to_actual(hyperpoint h) override {
h[3] = h[2]; h[2] = 0;
return h;
}
hyperpoint actual_to_base(hyperpoint h) override {
h[2] = h[3]; h[3] = 0;
return h;
}
transmatrix map_relative_push(hyperpoint h) override {
ld z = -asin_auto(h[2]);
ld u = 1 / cos_auto(z);
auto h1 = hpxy3(h[0] * u, h[1] * u, 0);
return rgpushxto0(h1) * zpush(-z);
}
};
/** embed in the product geometry */
struct emb_product_embedding : auaua {
virtual bool is_product_embedding() { return true; }
transmatrix intermediate_to_actual_translation(hyperpoint i) { return rgpushxto0(i); }
hyperpoint actual_to_intermediate(hyperpoint a) { return a; }
hyperpoint flatten(hyperpoint h) { h /= exp(zlevel(h)); return h; }
hyperpoint orthogonal_move(const hyperpoint& h, ld z) { return h * exp(z); }
transmatrix base_to_actual(const transmatrix &T) override { return T; }
transmatrix actual_to_base(const transmatrix &T0) override {
auto T = T0; fixmatrix(T);
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++) if(isnan(T[i][j])) return Id;
return T;
}
hyperpoint base_to_actual(hyperpoint h) override { return h; }
hyperpoint actual_to_base(hyperpoint h) override { return flatten(h); }
transmatrix map_relative_push(hyperpoint h) override { return rgpushxto0(h); }
};
/** embed Euclidean plane as horosphere */
struct emb_euc_in_hyp : embedding_method {
bool is_euc_in_hyp() override { return true; }
hyperpoint actual_to_intermediate(hyperpoint a) override { return deparabolic13(a); }
transmatrix intermediate_to_actual_translation(hyperpoint i) override { return parabolic13_at(i); }
transmatrix base_to_actual(const transmatrix &T) override {
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;
return parabolic13(mov[0], mov[1]) * U;
}
hyperpoint base_to_actual(hyperpoint h) override {
h[3] = h[2]; h[2] = 0; return parabolic13(h[0], h[1]) * C0;
}
hyperpoint actual_to_base(hyperpoint h) override { return deparabolic13(h); }
transmatrix actual_to_base(const transmatrix& T) override { hyperpoint h = deparabolic13(T * C0); return eupush(h[0], h[1]); }
};
/** sphere into a isotropic space of higher curvature */
struct emb_sphere_in_low : embedding_method {
bool is_sph_in_low() override { return true; }
bool is_depth_limited() override { return true; }
transmatrix intermediate_to_actual_translation(hyperpoint i) override { throw hr_exception("illegal function"); }
hyperpoint actual_to_intermediate(hyperpoint a) override { throw hr_exception("illegal function"); }
ld center_z() { return 1; }
transmatrix map_relative_push(hyperpoint a) {
ld z = hdist0(a);
geom3::light_flip(true);
auto h1 = normalize(a);
transmatrix T = rgpushxto0(h1);
geom3::light_flip(false);
return T * zpush(z);
}
transmatrix base_to_actual(const transmatrix &T0) override {
auto T = T0;
for(int i=0; i<4; i++) T[i][3] = T[3][i] = i == 3;
return T;
}
hyperpoint base_to_actual(hyperpoint h) override {
if(euclid) h[3] = 1;
else h *= sinh(1), h[3] = cosh(1);
return h;
}
hyperpoint actual_to_base(hyperpoint h) override { return h; }
transmatrix actual_to_base(const transmatrix& T) override { return T; }
ld get_logical_z(hyperpoint a) override { return hdist0(a) - 1; }
hyperpoint flatten(hyperpoint a) override {
ld d = hdist0(a);
if(d == 0) return a;
a *= sin_auto(1) / sin_auto(d);
a[3] = cos_auto(1);
return a;
}
hyperpoint orthogonal_move(const hyperpoint& h, ld z) override {
ld z0 = hdist0(h);
ld f = sin_auto(z0 + z) / sin_auto(z0);
hyperpoint hf = h * f;
hf[3] = cos_auto(z0 + z);
return hf;
}
};
/** abstract class for embeddings of Euclidean plane; these embeddings are not isotropic */
struct emb_euclid_noniso : embedding_method {
bool is_euc_in_noniso() override { return true; }
bool is_in_noniso() override { return true; }
transmatrix base_to_actual(const transmatrix &T) override {
auto T0 = T;
hyperpoint h = get_column(T0, 2);
h[2] = 0; h[3] = 1;
return intermediate_to_actual_translation( logical_to_intermediate * h);
}
hyperpoint base_to_actual(hyperpoint h) override {
h[2] = 0; h[3] = 1;
return intermediate_to_actual_translation( logical_to_intermediate * h ) * tile_center();
}
hyperpoint actual_to_base(hyperpoint h) override {
hyperpoint h1 = intermediate_to_logical * actual_to_intermediate(h);
h1[2] = 1; h1[3] = 0;
return h1;
}
transmatrix actual_to_base(const transmatrix& T) override { hyperpoint h = actual_to_base(T * tile_center()); return eupush(h[0], h[1]); }
transmatrix get_lti() override {
transmatrix lti = Id;
lti[0][0] *= geom3::euclid_embed_scale;
lti[1][1] *= geom3::euclid_embed_scale * geom3::euclid_embed_scale_y;
return logical_scaled_to_intermediate * cspin(0, 1, geom3::euclid_embed_rotate * degree) * lti;
}
};
struct emb_euc_in_product : emb_euclid_noniso {
bool is_euc_in_product() override { return true; }
bool no_spin() override { return true; }
hyperpoint actual_to_intermediate(hyperpoint a) override {
ld bz = zlevel(a);
auto h1 = a / exp(bz);
ld by = asin_auto(h1[1]);
ld bx = atan_auto(h1[0] / h1[2]);
return hyperpoint(bx, by, bz, 1);
}
transmatrix get_lsti() override { return cspin90(2, 1); }
transmatrix intermediate_to_actual_translation(hyperpoint i) {
return zpush(i[2]) * xpush(i[0]) * ypush(i[1]);
}
};
struct emb_euc_in_sl2 : emb_euclid_noniso {
/** 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);
}
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<embedding_method> 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<embedding_method> 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<ld>(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();
}
}

View File

@ -137,14 +137,10 @@ EX namespace euc {
map<gp::loc, struct cdata> 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; i<S7; i++)
tmatrix[i] = eumove(shifttable[i]);
if(b) geom3::light_flip(true);
for(int i=0; i<S7; i++) tmatrix[i] = eumove(shifttable[i]);
}
void on_dim_change() override {
@ -1212,7 +1208,7 @@ EX transmatrix eumove(coord co) {
Mat[0][2] += (co[0] + co[1] * .5) * cgi.tessf;
Mat[1][2] += co[1] * q3 /2 * cgi.tessf;
}
if(embedded_plane) swapmatrix(Mat);
if(embedded_plane) Mat = cgi.emb->base_to_actual(Mat);
return Mat;
}

View File

@ -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; i<c->type; 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; t<e-s; t++) {
hyperpoint fctr = tile_center();
hyperpoint fctr = may_kleinize(tile_center());
hyperpoint v1 = may_kleinize(hpc[s+t]) - fctr;
hyperpoint v2 = may_kleinize(hpc[s+t+1]) - fctr;
texture_order([&] (ld x, ld y) {
hyperpoint a = fctr + v1 * x + v2 * y;
hyperpoint b = normalize_flat(a);
hyperpoint b = cgi.emb->normalize_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))); });
}
}

View File

@ -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)";

View File

@ -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<transmatrix> 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<embedding_method> 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<pair<string, string>> 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<geometryinfo> 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<class T> auto in_flipped(const T& f) -> decltype(f()) {
light_flip(true);
finalizer ff([] { light_flip(false); });
return f();
}
template<class T> 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<ld>(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;

View File

@ -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);

View File

@ -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) {

View File

@ -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<hyperpoint>& 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;

View File

@ -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"

View File

@ -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<MXDIM; i++)
for(int j=0; j<MXDIM; j++)
@ -867,108 +726,6 @@ EX bool eqmatrix(transmatrix A, transmatrix B, ld eps IS(.01)) {
return true;
}
#if MAXMDIM >= 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; i<MDIM; i++) for(int j=0; j<MDIM; j++) if(isnan(T[i][j])) T = Id;
}
/** Just like swapmatrix but for hyperpoints. */
EX void swapmatrix(hyperpoint& h) {
if(geom3::euc_in_product()) {
h = cgi.logical_to_intermediate * h;
h = xpush(h[0]) * zpush(h[2]) * C0;
return;
}
if(geom3::in_product()) return;
if(geom3::sph_in_euc()) { h[3] = 1; return; }
if(geom3::sph_in_hyp()) { h[0] *= sinh(1); h[1] *= sinh(1); h[2] *= sinh(1); h[3] = cosh(1); return; }
if(geom3::euc_cylinder()) {
hyperpoint h1 = cgi.logical_to_intermediate * h;
h[0] = h1[0];
h[1] = sin(h1[1]);
h[2] = cos(h1[1]);
h[3] = 1;
return;
}
if(geom3::euc_in_nil()) { h = cgi.logical_to_intermediate * h; h[3] = 1; h[1] = 0; return; }
if(geom3::euc_in_sl2()) {
hyperpoint h1 = cgi.logical_to_intermediate * h; h1[1] = 0;
h = esl2_ita0(h1);
return;
}
if(geom3::euc_in_sph()) {
h = cgi.logical_to_intermediate * h;
h = cspin(0, 2, h[0]) * cspin(1, 3, h[1]) * lzpush(1) * C0;
return;
}
if(geom3::euc_in_solnih()) { h = cgi.logical_to_intermediate * h; h[3] = 1; h[2] = 0; return; }
if(geom3::hyp_in_solnih()) {
// 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;
h = point31(0, -hy, hx);
return;
}
swap(h[2], h[3]);
if(GDIM == 3) h[2] = 0;
if(geom3::euc_in_hyp()) h = parabolic13(h[0], h[1]) * C0;
}
#endif
EX transmatrix parabolic1(ld u) {
if(euclid)
return ypush(u);
else if(geom3::hyp_in_solnih() && !geom3::flipped) {
else if(cgi.emb->is_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;

View File

@ -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<pair<heptagon*, shiftmatrix>> 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);

View File

@ -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;

View File

@ -1058,12 +1058,12 @@ EX array<heptagon*, 3> 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);
}
}

View File

@ -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);
}

View File

@ -1370,7 +1370,7 @@ EX namespace hybrid {
template<class T> 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<eGeometryClass> dgc(cginf.g.kind, cginf.g.sig[2] < 0 ? gcHyperbolic : gcSphere);
return f();
}

View File

@ -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<hyperpoint> vertices, vector
ld w = 0;
for(int i=0; i<n; i++) center += vertices[i] * weights[i], w += weights[i];
if(mproduct && !bt::in()) center = normalize_flat(center);
if(mproduct && !bt::in()) center = cgi.emb->normalize_flat(center);
else center /= w;
ld center_altitude = 0;
@ -963,7 +963,7 @@ void geometry_information::make_wall(int id, vector<hyperpoint> 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<hyperpoint> 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)

View File

@ -28,7 +28,7 @@ pair<bool, hyperpoint> 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<bool, hyperpoint> makeradar(shiftpoint h) {
for(int a=0; a<LDIM; a++) h1[a] = h1[a] / (1 + h1[LDIM]);
}
else if(msphere) {
if(geom3::same_in_same()) h1[2] = h1[LDIM];
if(geom3::sph_in_hyp()) h1 /= sinh(1);
if(cgi.emb->is_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<bool, hyperpoint> 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<bool, hyperpoint> 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);

View File

@ -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);

View File

@ -450,7 +450,7 @@ shared_ptr<glhr::GLprogram> 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<glhr::GLprogram> selected;
if(matched_programs.count(id)) selected = matched_programs[id];

View File

@ -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]));

36
sky.cpp
View File

@ -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_item>& 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_item>& sky) {
for(int i=0; i<k; i++) ccolor = gradient(ccolor, vcolors[i], 0, 1, i+1);
hyperpoint ctr = Hypc;
for(auto& p: vertices) p = normalize_flat(p);
for(auto& p: vertices) p = cgi.emb->normalize_flat(p);
for(auto& p: vertices) ctr = ctr + p;
ctr = normalize_flat(ctr);
ctr = cgi.emb->normalize_flat(ctr);
for(int j=0; j<k; j++) {
int j1 = (j+1) % k;
glhr::colored_vertex cv[prec+1][prec+1];
for(int x=0; x<=prec; x++) for(int y=0; y<=prec; y++) if(x+y <= prec) {
hyperpoint h = ctr * (prec-x-y) + vertices[j] * x + vertices[j1] * y;
h = normalize_flat(h);
h = cgi.emb->normalize_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)];