1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-24 01:00:25 +00:00

Big change: spatial_embedding option

This commit is contained in:
Zeno Rogue 2022-12-08 19:38:06 +01:00
parent 90dd9e9866
commit 3e733ae6e9
45 changed files with 981 additions and 527 deletions

View File

@ -17,7 +17,7 @@ ld eyepos;
#define S (cgi.scalefactor / 0.805578)
#define SH (cgi.scalefactor / 0.805578 * vid.height_width / 1.5)
#define revZ ((WDIM == 2 || prod) ? -1 : 1)
#define revZ ((WDIM == 2 || gproduct) ? -1 : 1)
hyperpoint shcenter;
@ -46,9 +46,9 @@ EX ld zc(ld z) {
void geometry_information::add_cone(ld z0, const vector<hyperpoint>& vh, ld z1) {
last->flags |= POLY_TRIANGLES;
for(int i=0; i<isize(vh); i++) {
hpcpush(zpush(z0) * vh[i]);
hpcpush(zpush(z0) * vh[(i+1) % isize(vh)]);
hpcpush(zpush(z1) * shcenter);
hpcpush(lzpush(z0) * vh[i]);
hpcpush(lzpush(z0) * vh[(i+1) % isize(vh)]);
hpcpush(lzpush(z1) * shcenter);
}
}
@ -56,12 +56,12 @@ void geometry_information::add_prism_sync(ld z0, vector<hyperpoint> vh0, ld z1,
last->flags |= POLY_TRIANGLES;
for(int i=0; i<isize(vh0); i++) {
int i1 = (i+1) % isize(vh0);
hpcpush(zpush(z0) * vh0[i]);
hpcpush(zpush(z1) * vh1[i]);
hpcpush(zpush(z0) * vh0[i1]);
hpcpush(zpush(z1) * vh1[i]);
hpcpush(zpush(z0) * vh0[i1]);
hpcpush(zpush(z1) * vh1[i1]);
hpcpush(lzpush(z0) * vh0[i]);
hpcpush(lzpush(z1) * vh1[i]);
hpcpush(lzpush(z0) * vh0[i1]);
hpcpush(lzpush(z1) * vh1[i]);
hpcpush(lzpush(z0) * vh0[i1]);
hpcpush(lzpush(z1) * vh1[i1]);
}
}
@ -88,9 +88,9 @@ void geometry_information::add_prism(ld z0, vector<hyperpoint> vh0, ld z1, vecto
for(auto pp: pairs) {
int id = pp.owner;
hpcpush(zpush(z0) * lasts[0]);
hpcpush(zpush(z1) * lasts[1]);
hpcpush(zpush(id == 0 ? z0 : z1) * pp.h);
hpcpush(lzpush(z0) * lasts[0]);
hpcpush(lzpush(z1) * lasts[1]);
hpcpush(lzpush(id == 0 ? z0 : z1) * pp.h);
lasts[id] = pp.h;
}
}
@ -117,7 +117,7 @@ void geometry_information::add_texture(hpcshape& sh) {
sh.texture_offset = isize(utt.tvertices);
for(int i=sh.s; i<isize(hpc); i++) {
hyperpoint h = hpc[i];
if(prod) h = product::inverse_exp(h);
if(gproduct) h = product::inverse_exp(h);
ld rad = hypot_d(3, h);
ld factor = 0.50 + (0.17 * h[2] + 0.13 * h[1] + 0.15 * h[0]) / rad;
utt.tvertices.push_back(glhr::makevertex(0, factor, 0));
@ -132,13 +132,13 @@ vector<hyperpoint> scaleshape(const vector<hyperpoint>& vh, ld s) {
}
ld get_zlevel(hyperpoint h) {
if(prod) return zlevel(h);
if(gproduct) return zlevel(h);
if(sl2) return atan2(h[2], h[3]);
return asin_auto(h[2]);
}
void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
shcenter = C0;
shcenter = tile_center();
auto groin = get_shape(shHumanGroin);
auto body = get_shape(shPBodyOnly);
@ -207,12 +207,12 @@ void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
for(int i=arm0; i<arm1; i++) {
hyperpoint h = hpc[i];
ld zl = get_zlevel(h);
h = zpush(-zl) * h;
h = lzpush(-zl) * h;
ld rad = hdist0(h);
rad = (rad - 0.1124*S) / (0.2804*S - 0.1124*S);
rad = 1 - rad;
rad *= zc(0.7) - BODY;
hpc[i] = zpush(rad) * hpc[i];
hpc[i] = lzpush(rad) * hpc[i];
}
}
// 0.2804 - keep
@ -268,7 +268,7 @@ void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
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);
if(!prod || kind != 1) ht[s] = zpush(zz) * h;
if(!gproduct || kind != 1) ht[s] = lzpush(zz) * h;
else ht[s] = h;
if(hsh[s] < 0.1*S) shi[s] = 0.5;
else if(hsh[s] < 0.12*S) shi[s] = 0.1 + 0.4 * (hsh[s]/S - 0.1) / (0.12 - 0.1);
@ -285,14 +285,14 @@ void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
htx[2][i][1] *= 1.7;
htx[4][i][0] = htx[4][i][0] * 0.4 + scalefactor * 0.1;
htx[5][i][0] = htx[5][i][0] * 0.3 + scalefactor * 0.1;
if(!prod)
if(!gproduct)
for(int a=0; a<6; a++) htx[a][i] = hpxy3(htx[a][i][0], htx[a][i][1], htx[a][i][2]);
else
for(int a=0; a<6; a++) htx[a][i] = zpush(zzes[i]) * hpxy(htx[a][i][0], htx[a][i][1]);
for(int a=0; a<6; a++) htx[a][i] = lzpush(zzes[i]) * hpxy(htx[a][i][0], htx[a][i][1]);
}
ld levels[6] = {0, 0.125, 0.125, 0.250, 0.375, 0.5};
for(int a=0; a<6; a++) for(int i=0; i<3; i++)
htx[a][i] = zpush(-min(shi[i], levels[a]) * human_height * revZ) * htx[a][i];
htx[a][i] = lzpush(-min(shi[i], levels[a]) * human_height * revZ) * htx[a][i];
hpcpush(htx[0][0]);
hpcpush(htx[0][1]);
@ -320,7 +320,7 @@ void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
if(hdist0(h) <= 0.0501*S) {
zz += revZ * sqrt(0.0026 - pow(hdist0(h)/S, 2)) * SH;
}
hpcpush(zpush(zz) * h);
hpcpush(lzpush(zz) * h);
}
}
}
@ -382,7 +382,7 @@ void geometry_information::make_foot_3d(hpcshape& sh) {
void geometry_information::make_head_only() {
auto addpt = [this] (int d, int u) {
hpcpush(zpush(zc(eyepos) + 0.06 * SH * sin(u * degree)) * xspinpush0(d * degree, 0.05 * S * cos(u * degree)));
hpcpush(lzpush(zc(eyepos) + 0.06 * SH * sin(u * degree)) * xspinpush0(d * degree, 0.05 * S * cos(u * degree)));
};
bshape(shPHeadOnly, shPHeadOnly.prio);
@ -415,7 +415,7 @@ void geometry_information::make_head_3d(hpcshape& sh) {
array<ld, 2> zero = make_array<ld>(0,0);
pts[1].emplace_back(zero);
head.push_back(C0);
head.push_back(tile_center());
bshape(sh, sh.prio);
@ -491,7 +491,7 @@ void geometry_information::make_skeletal(hpcshape& sh, ld push) {
}
hyperpoint yzspin(ld alpha, hyperpoint h) {
if(prod) return product::direct_exp(cspin(1, 2, alpha) * product::inverse_exp(h));
if(gproduct) return product::direct_exp(cspin(1, 2, alpha) * product::inverse_exp(h));
else return cspin(1, 2, alpha) * h;
}
@ -625,7 +625,7 @@ void geometry_information::slimetriangle(hyperpoint a, hyperpoint b, hyperpoint
dynamicval<int> d(vid.texture_step, 8);
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) * (hybri ? .5 : 1);
ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8) * (mhybrid ? .5 : 1);
hyperpoint h = direct_exp(tangent_length(a*x+b*y+c*z, r));
hpcpush(h);
});
@ -709,16 +709,16 @@ void geometry_information::make_euclidean_sky() {
for(int x=-20; x<20; x++)
for(int y=-20; y<20; y++)
hpcsquare(
zpush(cgi.WALL) * hpxy(x, y),
zpush(cgi.WALL) * hpxy(x, y+1),
zpush(cgi.WALL) * hpxy(x+1, y),
zpush(cgi.WALL) * hpxy(x+1, y+1)
lzpush(cgi.WALL) * hpxy(x, y),
lzpush(cgi.WALL) * hpxy(x, y+1),
lzpush(cgi.WALL) * hpxy(x+1, y),
lzpush(cgi.WALL) * hpxy(x+1, y+1)
);
}
/** res[0] and res[1] place H on the plane, while res[2] is the altitude */
hyperpoint psmin(hyperpoint H) {
if(prod) {
if(gproduct) {
auto d = product_decompose(H);
d.second[2] = d.first;
return d.second;
@ -748,14 +748,14 @@ 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(zpush(shift_head) * hpc[i]));
for(int i=head.s; i<head.e; i++) pss.push_back(psmin(lzpush(shift_head) * hpc[i]));
ld zmid = 0;
for(hyperpoint& h: pss) zmid += h[2];
zmid /= isize(pss);
ld mindist = 1e9;
for(int i=0; i<isize(pss); i+=3) if(pss[i][2] < zmid || (WDIM == 3 && !prod)) {
for(int i=0; i<isize(pss); i+=3) if(pss[i][2] < zmid || (WDIM == 3 && !gproduct)) {
ld d = sqhypot_d(2, pss[i]-pscenter) + sqhypot_d(2, pss[i+1]-pscenter) + sqhypot_d(2, pss[i+2]-pscenter);
if(d < mindist) mindist = d, pos = min(min(pss[i][2], pss[i+1][2]), pss[i+2][2]), qty++;
qtyall++;
@ -766,11 +766,11 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye
if(&eye == &shFamiliarEye) cgi.eyelevel_familiar = pos;
make_ball(eye, rad, 0);
transmatrix T = zpush(-shift_eye) * rgpushxto0(center) * zpush(pos);
transmatrix T = lzpush(-shift_eye) * rgpushxto0(center) * lzpush(pos);
for(int i=eye.s; i<isize(hpc); i++) hpc[i] = T * hpc[i];
int s = isize(hpc);
if(&eye == &shSkullEyes)
for(int i=eye.s; i<s; i++) hpc[i] = xpush(0.07 * scalefactor) * hpc[i];
for(int i=eye.s; i<s; i++) hpc[i] = lxpush(0.07 * scalefactor) * hpc[i];
if(q == 2)
for(int i=eye.s; i<s; i++) {
hpcpush(MirrorY * hpc[i]);
@ -784,7 +784,7 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye
}
void geometry_information::shift_last_straight(ld z) {
for(int i=last->s; i<isize(hpc); i++) hpc[i] = zpush(z) * hpc[i];
for(int i=last->s; i<isize(hpc); i++) hpc[i] = lzpush(z) * hpc[i];
}
EX void queueball(const shiftmatrix& V, ld rad, color_t col, eItem what) {
@ -837,7 +837,7 @@ void geometry_information::make_3d_models() {
if(GDIM == 2 || noGUI) return;
eyepos = WDIM == 2 ? 0.875 : 0.925;
DEBBI(DF_POLY, ("make_3d_models"));
shcenter = C0;
shcenter = tile_center();
#if CAP_GL
if(floor_textures) {
@ -928,9 +928,9 @@ void geometry_information::make_3d_models() {
for(int i=shDogRearPaw.s; i<shDogRearPaw.e; i++) rear_leg += hpc[i];
front_leg = normalize(front_leg);
rear_leg = normalize(rear_leg);
front_leg_move = zpush(zc(0.4)) * rgpushxto0(front_leg);
front_leg_move = lzpush(zc(0.4)) * rgpushxto0(front_leg);
front_leg_move_inverse = inverse(front_leg_move);
rear_leg_move = zpush(zc(0.4)) * rgpushxto0(rear_leg);
rear_leg_move = lzpush(zc(0.4)) * rgpushxto0(rear_leg);
rear_leg_move_inverse = inverse(rear_leg_move);
leg_length = zc(0.4) - zc(0);
@ -1221,9 +1221,9 @@ void geometry_information::make_3d_models() {
texture_order([&] (ld x, ld y) {
ld z = 1-x-y;
ld rad = 2.1 - i * 0.2;
hyperpoint hx = ddi(t*12, -zhexf*rad) * C0;
hyperpoint hy = ddi(t*12+12, -zhexf*rad) * C0;
hyperpoint hz = C0;
hyperpoint hx = ddi(t*12, -zhexf*rad) * tile_center();
hyperpoint hy = ddi(t*12+12, -zhexf*rad) * tile_center();
hyperpoint hz = tile_center();
hyperpoint h = hx * x + hy * y + hz * z;
h = mid(h, h);
h = orthogonal_move(h, FLOOR - human_height * (i+2.5) / 100 * (x+y+1)/2);

View File

@ -196,7 +196,7 @@ struct hr_polygon_error : hr_exception {
string hr_polygon_error::generate_error() {
cld dist = (hdist0(tC0(end)) / params["distunit"]);
bool angle = abs(dist) < 1e-9;
if(angle) dist = (atan2(end * xpush0(1)) / params["angleunit"]);
if(angle) dist = (atan2(end * lxpush0(1)) / params["angleunit"]);
return
XLAT("Polygon number %1 did not close correctly (%2 %3). Here is the picture to help you understand the issue.\n\n", its(id),
angle ? "angle" : "distance",
@ -259,7 +259,7 @@ void shape::build_from_angles_edges(bool is_comb) {
matrices.push_back(at);
if(debugflags & DF_GEOM) println(hlog, "at = ", at);
ctr += tC0(at);
at = at * xpush(in_edges[i]) * spin(in_angles[i]+M_PI);
at = at * lxpush(in_edges[i]) * spin(in_angles[i]+M_PI);
}
matrices.push_back(at);
if(is_comb) return;
@ -271,8 +271,8 @@ void shape::build_from_angles_edges(bool is_comb) {
// try to move towards the center
if(debugflags & DF_GEOM) println(hlog, "special case encountered");
for(int i=0; i<n; i++) {
ctr += at * xpush(in_edges[i]) * spin((in_angles[i]+M_PI)/2) * xpush0(.01);
at = at * xpush(in_edges[i]) * spin(in_angles[i]);
ctr += at * lxpush(in_edges[i]) * spin((in_angles[i]+M_PI)/2) * lxpush0(.01);
at = at * lxpush(in_edges[i]) * spin(in_angles[i]);
}
if(debugflags & DF_GEOM) println(hlog, "ctr = ", ctr);
}
@ -1473,7 +1473,7 @@ struct hrmap_arbi : hrmap {
heptagon *alt = NULL;
if(hyperbolic) {
if(mhyperbolic) {
dynamicval<eGeometry> g(geometry, gNormal);
alt = init_heptagon(S7);
alt->s = hsOrigin;
@ -1481,7 +1481,7 @@ struct hrmap_arbi : hrmap {
current_altmap = newAltMap(alt);
}
transmatrix T = xpush(.01241) * spin(1.4117) * xpush(0.1241) * Id;
transmatrix T = lxpush(.01241) * spin(1.4117) * lxpush(0.1241) * Id;
arbi_matrix[origin] = make_pair(alt, T);
altmap[alt].emplace_back(origin, T);
@ -1559,7 +1559,7 @@ struct hrmap_arbi : hrmap {
transmatrix T = p.second * adj(h, d);
if(hyperbolic) {
if(mhyperbolic) {
dynamicval<eGeometry> g(geometry, gNormal);
dynamicval<hrmap*> cm(currentmap, current_altmap);
// transmatrix U = T;
@ -1567,8 +1567,8 @@ struct hrmap_arbi : hrmap {
// U = U * inverse(T);
}
fixmatrix(T);
if(euclid) {
if(meuclid) {
/* hash the rough coordinates as heptagon* alt */
size_t s = size_t(T[0][LDIM]+.261) * 124101 + size_t(T[1][LDIM]+.261) * 82143;
alt = (heptagon*) s;

View File

@ -168,7 +168,7 @@ EX ld compute_edgelength(vector<pair<ld, ld>> facemul, ld halftotal IS(M_PI)) {
else {
ld gamma = M_PI / fm.first;
auto c = asin_auto(sin_auto(edgelength/2) / sin(gamma));
hyperpoint h = xpush(c) * spin(M_PI - 2*gamma) * xpush0(c);
hyperpoint h = lxpush(c) * spin(M_PI - 2*gamma) * lxpush0(c);
ld a = atan2(h);
cyclefix(a, 0);
if(a < 0) a = -a;
@ -418,11 +418,20 @@ geometryinfo1& archimedean_tiling::get_geometry(ld mul) {
}
void archimedean_tiling::compute_geometry() {
if(embedded_plane) return IPF(compute_geometry());
ginf[gArchimedean].g = get_geometry();
set_flag(ginf[gArchimedean].flags, qCLOSED, get_class() == gcSphere);
if(geom3::ginf_backup.size()) {
geom3::ginf_backup[gArchimedean].g = geom3::ginf_backup[gSphere].g;
if(geom3::flipped) swap(geom3::ginf_backup[gArchimedean].g, ginf[gArchimedean].g);
set_flag(ginf[gArchimedean].flags, qCLOSED, get_class() == gcSphere);
}
DEBB(DF_GEOM, (format("euclidean_angle_sum = %f\n", float(euclidean_angle_sum))));
bool infake = fake::in();
dynamicval<eGeometry> dv(geometry, gArchimedean);
@ -478,9 +487,9 @@ void archimedean_tiling::compute_geometry() {
auto& c = circumradius[i];
c = asin_auto(sin_auto(edgelength/2) / sin(gamma));
inradius[i] = hdist0(mid(xpush0(circumradius[i]), xspinpush0(2*gamma, circumradius[i])));
inradius[i] = hdist0(mid(lxpush0(circumradius[i]), xspinpush0(2*gamma, circumradius[i])));
hyperpoint h = xpush(c) * spin(M_PI - 2*gamma) * xpush0(c);
hyperpoint h = lxpush(c) * spin(M_PI - 2*gamma) * lxpush0(c);
ld a = atan2(h);
cyclefix(a, 0);
if(a < 0) a = -a;
@ -592,7 +601,7 @@ struct hrmap_archimedean : hrmap {
current_altmap = newAltMap(alt);
}
transmatrix T = xpush(.01241) * spin(1.4117) * xpush(0.1241) * Id;
transmatrix T = lxpush(.01241) * spin(1.4117) * lxpush(0.1241) * Id;
archimedean_gmatrix[origin] = make_pair(alt, T);
altmap[alt].emplace_back(origin, T);
@ -653,13 +662,13 @@ struct hrmap_archimedean : hrmap {
auto& t1 = current.get_triangle(hi);
// * spin(-tri[id][pi+i].first) * xpush(t.second) * pispin * spin(tri[id'][p'+d'].first)
// * spin(-tri[id][pi+i].first) * lxpush(t.second) * pispin * spin(tri[id'][p'+d'].first)
auto& p1 = archimedean_gmatrix[h];
heptagon *alt = p1.first;
transmatrix T = p1.second * spin(-t1.first) * xpush(t1.second);
transmatrix T = p1.second * spin(-t1.first) * lxpush(t1.second);
transmatrix U = Id;
if(hyperbolic) {
@ -680,22 +689,22 @@ struct hrmap_archimedean : hrmap {
DEBB(DF_GEOM, ("look for: ", alt, " / ", kz(T * C0)));
for(auto& p2: altmap[alt]) if(same_point_may_warn(p2.second * C0, T * C0)) {
for(auto& p2: altmap[alt]) if(same_point_may_warn(p2.second * tile_center(), T * tile_center())) {
DEBB(DF_GEOM, ("cell found: ", p2.first));
for(int d2=0; d2<p2.first->degree(); d2++) {
heptspin hs(p2.first, d2);
auto& t2 = current.get_triangle(p2.first, d2);
transmatrix T1 = T * spin(M_PI + t2.first);
DEBB(DF_GEOM, ("compare: ", kz(T1 * xpush0(1)), ":: ", kz(p2.second * xpush0(1))));
if(same_point_may_warn(T1 * xpush0(1), p2.second * xpush0(1))) {
DEBB(DF_GEOM, ("compare: ", kz(T1 * lxpush0(1)), ":: ", kz(p2.second * lxpush0(1))));
if(same_point_may_warn(T1 * lxpush0(1), p2.second * lxpush0(1))) {
// T1 = p2.second
// T * spin(pi+t2.first) == p2.second
// p1.second * spinm(-t1.first) * xpush(t1.second) * spin(pi+t2.first) == p2.second
// p1.second * spinm(-t1.first) * lxpush(t1.second) * spin(pi+t2.first) == p2.second
// bring p1 and p2 closer, to prevent floating point errors
if(hyperbolic) {
fixup_matrix(p1.second, U * p2.second * spin(-M_PI - t2.first) * xpush(-t1.second) * spin(t1.first), 0.25);
fixup_matrix(p1.second, U * p2.second * spin(-M_PI - t2.first) * lxpush(-t1.second) * spin(t1.first), 0.25);
fixup_matrix(p2.second, T1, 0.25);
}
@ -837,7 +846,7 @@ struct hrmap_archimedean : hrmap {
auto& t1 = ac.get_triangle(c->master, cid);
hyperpoint h0 = xspinpush0(-t0.first, t0.second * 3 / cf * (ac.real_faces == 0 ? 0.999 : 1));
hyperpoint h1 = xspinpush0(-t1.first, t1.second * 3 / cf * (ac.real_faces == 0 ? 0.999 : 1));
return mid3(C0, h0, h1);
return mid3(tile_center(), h0, h1);
}
if(DUAL) {
auto& t0 = ac.get_triangle(c->master, 2*cid-1);
@ -965,7 +974,7 @@ transmatrix archimedean_tiling::adjcell_matrix(heptagon *h, int d) {
int d2 = h->c.spin(d);
auto& t2 = get_triangle(h2, d2);
return spin(-t1.first) * xpush(t1.second) * spin(M_PI + t2.first);
return spin(-t1.first) * lxpush(t1.second) * spin(M_PI + t2.first);
}
EX int fix(heptagon *h, int spin) {

View File

@ -38,7 +38,7 @@ EX bool hasbardir(cell *c) {
}
EX void preventbarriers(cell *c) {
if(hybri) c = hybrid::get_where(c).first;
if(mhybrid) c = hybrid::get_where(c).first;
if(c && c->bardir == NODIR) c->bardir = NOBARRIERS;
}

View File

@ -1496,7 +1496,7 @@ EX void initialize_all() {
#if CAP_ARCM
arcm::current.parse();
#endif
if(hybri) geometry = hybrid::underlying;
if(mhybrid) geometry = hybrid::underlying;
#if CAP_COMMANDLINE
arg::read(2);

View File

@ -184,7 +184,7 @@ map<heptagon*, short> altmap::quotient_relspins;
auto qclear = addHook(hooks_clearmemory, 200, [] { altmap::quotient_relspins.clear(); });
void hrmap::extend_altmap(heptagon *h, int levs, bool link_cdata) {
if(hybri) { PIU ( extend_altmap(h, levs, link_cdata) ); }
if(mhybrid) { PIU ( extend_altmap(h, levs, link_cdata) ); }
if(!h->alt) return;
preventbarriers(h->c7);
if(h->c7) forCellEx(c2, h->c7) preventbarriers(c2);
@ -230,7 +230,7 @@ EX int hrandom_adjacent(cellwalker cw) {
EX heptagon *create_altmap(cell *c, int rad, hstate firststate, int special IS(0)) {
if(hybri) {
if(mhybrid) {
if(hybrid::under_class() == gcSphere) return NULL;
c = hybrid::get_where(c).first;
return PIU ( create_altmap(c, rad, firststate, special) );
@ -296,7 +296,7 @@ EX heptagon *create_altmap(cell *c, int rad, hstate firststate, int special IS(0
if(!currentmap->link_alt(h, alt, firststate, p.last.spin)) {
return nullptr;
}
if(hybri) hybrid::altmap_heights[alt] = hybrid::get_where(centerover).second;
if(mhybrid) hybrid::altmap_heights[alt] = hybrid::get_where(centerover).second;
alt->alt = alt;
h->alt = alt;
alt->cdata = (cdata*) h;
@ -814,10 +814,10 @@ EX void buildEquidistant(cell *c) {
ls::nice_walls() ? true :
false;
if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !hybri && hrand(10) < 5 && chance)
if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !mhybrid && hrand(10) < 5 && chance)
buildAnotherEquidistant(c);
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !hybri && hrand(100) < (PURE?25:5) && items[itBone] >= U10 && chance)
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !mhybrid && hrand(100) < (PURE?25:5) && items[itBone] >= U10 && chance)
buildAnotherEquidistant(c);
}
@ -959,7 +959,7 @@ EX void clear_euland(eLand first) {
}
bool valid_wall_at(int c) {
if(nonisotropic || hybri) return true;
if(nonisotropic || mhybrid) return true;
return short(c) % 3 == 0;
}
@ -972,7 +972,7 @@ EX eLand switchable(eLand nearland, eLand farland, int c) {
else if(ls::no_walls()) {
if((dual::state && nearland == laCrossroads4) || hrand(15) == 0)
return getNewLand(nearland);
if(nearland == laCrossroads4 && (nonisotropic || hybri))
if(nearland == laCrossroads4 && (nonisotropic || mhybrid))
return getNewLand(nearland);
return nearland;
}
@ -1372,7 +1372,7 @@ EX bool horo_ok() {
if(INVERSE) return false;
if(currentmap->strict_tree_rules()) return true;
if(reg3::in_hrmap_h3() && !PURE) return false;
return hyperbolic && !bt::in() && !arcm::in() && !kite::in() && !experimental && !hybri && !arb::in() && !quotient;
return hyperbolic && !bt::in() && !arcm::in() && !kite::in() && !experimental && !mhybrid && !arb::in() && !quotient;
}
/** \brief should we either generate the horocycles in the current geometry, or have them exist via eubinary? */
@ -1496,7 +1496,7 @@ EX bool old_nice_walls() {
}
EX bool nice_walls_available() {
if(hybri) return PIU(nice_walls_available());
if(mhybrid) return PIU(nice_walls_available());
if(fake::in()) return FPIU(nice_walls_available());
return WDIM == 2;
}
@ -1520,7 +1520,7 @@ EX void build_walls(cell *c, cell *from) {
// buildgreatwalls
if(hybri) return; /* Great Walls generated via the underlying geometry */
if(mhybrid) return; /* Great Walls generated via the underlying geometry */
if(walls_not_implemented()) return; // walls not implemented here
@ -1920,7 +1920,7 @@ EX void gen_temple(cell *c) {
auto d = hybrid::get_where(c);
if(!PIU(pseudohept(d.first))) c->wall = waColumn;
}
else if(hybri) {
else if(mhybrid) {
auto d = hybrid::get_where(c);
if(d.first->wall == waColumn || (d.second&1)) c->wall = waColumn;
}

View File

@ -604,7 +604,7 @@ EX namespace bt {
/** \brief by what factor do the lengths expand after moving one level in hr::bt::expansion_coordinate() */
EX ld expansion() {
if(WDIM == 2) return area_expansion_rate();
else if(prod) return PIU( area_expansion_rate() );
else if(mproduct) return PIU( area_expansion_rate() );
else return sqrt(area_expansion_rate());
}

View File

@ -187,7 +187,7 @@ transmatrix hrmap::adj(heptagon *h, int i) { return relative_matrix(h->cmove(i),
vector<cell*>& hrmap::allcells() {
static vector<cell*> default_allcells;
if(disksize) return all_disk_cells;
if(closed_manifold && !(cgflags & qHUGE_BOUNDED) && !(hybri && hybrid::csteps == 0)) {
if(closed_manifold && !(cgflags & qHUGE_BOUNDED) && !(mhybrid && hybrid::csteps == 0)) {
celllister cl(gamestart(), 1000000, 1000000, NULL);
default_allcells = cl.lst;
return default_allcells;
@ -403,13 +403,15 @@ EX bool is_in_disk(cell *c) {
/** create a map in the current geometry */
EX void initcells() {
DEBB(DF_INIT, ("initcells"));
if(embedded_plane) return IPF( initcells() );
hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap);
if(res) currentmap = res;
#if CAP_SOLV
else if(asonov::in()) currentmap = asonov::new_map();
#endif
else if(nonisotropic || hybri) currentmap = nisot::new_map();
else if(nonisotropic || mhybrid) currentmap = nisot::new_map();
else if(INVERSE) currentmap = gp::new_inverse();
else if(fake::in()) currentmap = fake::new_map();
#if CAP_CRYSTAL
@ -586,7 +588,7 @@ EX int compdist(int dx[]) {
EX int celldist(cell *c) {
if(experimental) return 0;
if(hybri)
if(mhybrid)
return hybrid::celldistance(c, currentmap->gamestart());
if(nil && !quotient) return DISTANCE_UNKNOWN;
if(euc::in()) return celldistance(currentmap->gamestart(), c);
@ -617,7 +619,7 @@ static const int ALTDIST_ERROR = 90000;
EX int celldistAlt(cell *c) {
if(experimental) return 0;
if(hybri) {
if(mhybrid) {
if(in_s2xe()) return hybrid::get_where(c).second;
auto w = hybrid::get_where(c);
int d = c->master->alt && c->master->alt->alt ? hybrid::altmap_heights[c->master->alt->alt] : 0;
@ -831,7 +833,8 @@ EX bool randpatternMajority(cell *c, int ival, int iterations) {
cdata orig_cdata;
EX bool geometry_supports_cdata() {
if(hybri) return PIU(geometry_supports_cdata());
if(mhybrid) return PIU(geometry_supports_cdata());
if(embedded_plane) return IPF( geometry_supports_cdata() );
return among(geometry, gEuclid, gEuclidSquare, gNormal, gOctagon, g45, g46, g47, gBinaryTiling) || (arcm::in() && !sphere) || (currentmap && currentmap->strict_tree_rules());
}
@ -925,7 +928,8 @@ cdata *getHeptagonCdata_legacy(heptagon *h) {
cdata *getHeptagonCdata(heptagon *h) {
if(hybri) return PIU ( getHeptagonCdata(h) );
if(mhybrid) return PIU ( getHeptagonCdata(h) );
if(embedded_plane) return IPF( getHeptagonCdata(h) );
if(geometry == gNormal && BITRUNCATED) return getHeptagonCdata_legacy(h);
if(h->cdata) return h->cdata;
@ -1090,8 +1094,9 @@ EX cdata *arcmCdata(cell *c) {
EX int getCdata(cell *c, int j) {
if(fake::in()) return FPIU(getCdata(c, j));
if(embedded_plane) return IPF(getCdata(c, j));
if(experimental) return 0;
if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
if(mhybrid) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
else if(INVERSE) {
cell *c1 = gp::get_mapped(c);
return UIU(getCdata(c1, j));
@ -1116,8 +1121,9 @@ EX int getCdata(cell *c, int j) {
EX int getBits(cell *c) {
if(fake::in()) return FPIU(getBits(c));
if(embedded_plane) return IPF(getBits(c));
if(experimental) return 0;
if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
if(mhybrid) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
else if(INVERSE) {
cell *c1 = gp::get_mapped(c);
return UIU(getBits(c1));
@ -1265,7 +1271,7 @@ EX int celldistance(cell *c1, cell *c2) {
if(fake::in()) return FPIU(celldistance(c1, c2));
if(hybri) return hybrid::celldistance(c1, c2);
if(mhybrid) return hybrid::celldistance(c1, c2);
#if CAP_FIELD
if(geometry == gFieldQuotient && (PURE || BITRUNCATED)) {
@ -1533,7 +1539,7 @@ EX vector<int> reverse_directions(heptagon *c, int dir) {
}
EX bool standard_tiling() {
return !arcm::in() && !kite::in() && !bt::in() && !arb::in() && !nonisotropic && !hybri;
return !arcm::in() && !kite::in() && !bt::in() && !arb::in() && !nonisotropic && !mhybrid;
}
EX int valence() {

View File

@ -1764,7 +1764,7 @@ void celldrawer::draw_features_and_walls_3d() {
/* always render */
if(wrl::in && wrl::print) ; else
#endif
if(pmodel == mdPerspective && !sphere && !quotient && !kite::in() && !nonisotropic && !hybri && !experimental && !nih) {
if(pmodel == mdPerspective && !sphere && !quotient && !kite::in() && !nonisotropic && !mhybrid && !experimental && !nih) {
if(a < 4 && among(geometry, gHoroTris, gBinary3) && celldistAlt(c) >= celldistAlt(centerover)) continue;
else if(a < 2 && among(geometry, gHoroRec) && celldistAlt(c) >= celldistAlt(centerover)) continue;
// this optimization is not correct, need to fix
@ -1782,7 +1782,7 @@ void celldrawer::draw_features_and_walls_3d() {
case 6: case 7: if (pmodel == mdPerspective && V[2][LDIM] <= -l) continue; break;
}
}
else if(prod) {
else if(mproduct) {
if(a < c->type-2 && !in_s2xe()) {
ld d = in_e2xe() ? sqhypot_d(2, unshift(tC0(V))) : V[2][2];
hyperpoint h = (unshift(V) * cgi.walltester[ofs + a]);
@ -1838,7 +1838,7 @@ void celldrawer::draw_features_and_walls_3d() {
else if(c->wall == waMineOpen) {
if(pmodel == mdGeodesic && hdist0(tC0(V)) < 1e-3) {
}
else if(prod && hdist0(tC0(V)) < 1e-3) {
else if(mproduct && hdist0(tC0(V)) < 1e-3) {
}
else {
int mines = countMinesAround(c);
@ -1903,7 +1903,7 @@ void celldrawer::check_rotations() {
if(a <= b) {
ds.best = c;
ds.speed = spd;
if(prod) {
if(mproduct) {
auto pd = product_decompose(unshift(tC0(V)));
ds.total += pd.second;
ds.depth += pd.first;
@ -1912,7 +1912,7 @@ void celldrawer::check_rotations() {
ds.total += unshift(tC0(V));
ds.qty++;
ds.point = normalize_flat(ds.total);
if(prod) ds.point = orthogonal_move(ds.point, ds.depth / ds.qty);
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

@ -2796,7 +2796,7 @@ EX namespace sword {
};
/** dimensions available to the Sword */
#define SWORDDIM (hybri ? 2 : WDIM)
#define SWORDDIM (mhybrid ? 2 : WDIM)
#endif
@ -2829,7 +2829,7 @@ EX namespace sword {
EX cell *pos2(cell *c, int s) {
int t = c->type;
if(hybri) t -= 2;
if(mhybrid) t -= 2;
s *= 2;
s += sword_angles/t;
s %= (2 * sword_angles);
@ -2887,7 +2887,7 @@ EX namespace sword {
neighborId(c2, c1);
if(s1 < 0 || s2 < 0) return d;
if(SWORDDIM == 2) {
int sub = (hybri) ? 2 : 0;
int sub = (mhybrid) ? 2 : 0;
int t2 = c2->type - sub;
int t1 = c1->type - sub;
if(t1 == 0 || t2 == 0) return d;
@ -3590,7 +3590,7 @@ EX namespace windmap {
// cw.spin = 0;
neighbors.emplace_back();
auto &v = neighbors.back();
if(NONSTDVAR && !sphere && !arcm::in() && !hybri && !INVERSE)
if(NONSTDVAR && !sphere && !arcm::in() && !mhybrid && !INVERSE)
for(int l=0; l<S7; l++) {
v.push_back(getId(cw + cth + l + wstep + cth));
}
@ -3607,7 +3607,7 @@ EX namespace windmap {
if(N == 18920) precomp = windcodes18920;
if(N == 5676) precomp = windcodes5676;
if(precomp && (hyperbolic || hybri) && isize(currfp.matrices)) {
if(precomp && (hyperbolic || mhybrid) && isize(currfp.matrices)) {
int randval = hrand(isize(currfp.matrices));
for(int i=0; i<N; i++)
windcodes[i] = precomp[getid[fieldpattern::fieldval_uniq_rand(samples[i].at, randval)]-1];

View File

@ -832,6 +832,9 @@ EX void initConfig() {
addsaver(vid.highlightmode, "highlightmode");
addsaver(vid.always3, "3D always", false);
param_enum(geom3::spatial_embedding, "spatial_embedding", "spatial embedding", geom3::seDefault)
->editable(geom3::spatial_embedding_options, "spatial embedding", 'E');
param_b(memory_saving_mode, "memory_saving_mode", (ISMOBILE || ISPANDORA || ISWEB) ? 1 : 0);
param_i(reserve_limit, "memory_reserve", 128);
@ -2203,6 +2206,8 @@ EX void show3D() {
dialog::add_action(geom3::switch_fpp);
}
#endif
add_edit(geom3::spatial_embedding);
dialog::addBreak(50);
#if MAXMDIM >= 4
@ -2278,7 +2283,7 @@ EX void show3D() {
});
}
if((WDIM == 2 && GDIM == 3) || prod)
if(mproduct || embedded_plane)
dialog::addBoolItem_action(XLAT("fixed Y/Z rotation"), vid.fixed_yz, 'Z');
if(WDIM == 2 && GDIM == 3) {

View File

@ -83,7 +83,7 @@ EX bool mouseout2() {
EX movedir vectodir(hyperpoint P) {
transmatrix U = unshift(ggmatrix(cwt.at));
if(GDIM == 3 && WDIM == 2) U = current_display->radar_transform * U;
if(embedded_plane && geom3::same_in_same()) U = current_display->radar_transform * U;
P = direct_exp(lp_iapply(P));
@ -94,10 +94,12 @@ EX movedir vectodir(hyperpoint P) {
vector<ld> dirdist(cwt.at->type);
auto TC0 = tile_center();
for(int i=0; i<cwt.at->type; i++) {
transmatrix T = currentmap->adj(cwt.at, (cwt + i).spin);
ld d1 = geo_dist(U * T * C0, Centered * P);
ld d2 = geo_dist(U * T * C0, Centered * C0);
ld d1 = geo_dist(U * T * TC0, Centered * P);
ld d2 = geo_dist(U * T * TC0, Centered * TC0);
dirdist[i] = d1 - d2;
}

View File

@ -1559,7 +1559,7 @@ EX namespace ods {
for(int j=0; j<3; j++) {
hyperpoint o = p->V * glhr::gltopoint((*p->tab)[p->offset+i+j]);
if(nonisotropic || prod) {
if(nonisotropic || gproduct) {
o = lp_apply(inverse_exp(o, iTable, false));
o[3] = 1;
dynamicval<eGeometry> g(geometry, gEuclid);
@ -2456,7 +2456,7 @@ EX void drawqueue() {
#endif
#if MAXMDIM >= 4 && CAP_GL
if(WDIM == 2 && GDIM == 3 && hyperbolic && !vrhr::rendering()) make_air();
if(embedded_plane && (hyperbolic || geom3::sph_in_euc()) && !vrhr::rendering()) make_air();
#endif
#if CAP_VR

View File

@ -137,10 +137,14 @@ 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);
}
void on_dim_change() override {
@ -1200,13 +1204,14 @@ EX transmatrix eumove(coord co) {
}
transmatrix Mat = Id;
if(a4) {
Mat[0][LDIM] += co[0] * cgi.tessf;
Mat[1][LDIM] += co[1] * cgi.tessf;
Mat[0][2] += co[0] * cgi.tessf;
Mat[1][2] += co[1] * cgi.tessf;
}
else {
Mat[0][LDIM] += (co[0] + co[1] * .5) * cgi.tessf;
Mat[1][LDIM] += co[1] * q3 /2 * cgi.tessf;
Mat[0][2] += (co[0] + co[1] * .5) * cgi.tessf;
Mat[1][2] += co[1] * q3 /2 * cgi.tessf;
}
if(embedded_plane) swapmatrix(Mat);
return Mat;
}

View File

@ -43,7 +43,7 @@ EX bool isprime(int n) {
}
#if HDR
#define MWDIM (prod ? 3 : WDIM+1)
#define MWDIM (mproduct ? 3 : WDIM+1)
struct matrix : array<array<int, MAXMDIM>, MAXMDIM> {
bool operator == (const matrix& B) const {
@ -1409,7 +1409,7 @@ EX struct fpattern& getcurrfp() {
return fp;
}
if(!hyperbolic) return fp_invalid;
if(WDIM == 3 && !quotient && !hybri && !bt::in()) {
if(WDIM == 3 && !quotient && !mhybrid && !bt::in()) {
static fpattern fp(0);
if(fp.Prime) return fp;
for(int p=2; p<20; p++) { fp.Prime = p; if(!fp.solve()) break; }

View File

@ -693,14 +693,14 @@ 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 v1 = may_kleinize(hpc[s+t]) - C0;
hyperpoint v2 = may_kleinize(hpc[s+t+1]) - C0;
hyperpoint fctr = 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) {
hpcpush(
orthogonal_move(
normalize(C0 + v1 * x + v2 * y)
, dfloor_table[k])
);
hyperpoint a = fctr + v1 * x + v2 * y;
hyperpoint b = normalize_flat(a);
hyperpoint c = orthogonal_move(b, dfloor_table[k]);
cgi.hpcpush(c);
});
}
}
@ -1396,7 +1396,9 @@ EX void make_floor_textures() {
dynamicval<eModel> gm(pmodel, mdDisk);
dynamicval<eVariation> va(variation, eVariation::pure);
dynamicval<geometryinfo1> gie(ginf[geometry].g, giEuclid2);
dynamicval<flagtype> gief(ginf[geometry].flags, qOPTQ);
dynamicval<geometryinfo1> gih(ginf[gNormal].g, giHyperb2);
dynamicval<flagtype> gihf(ginf[gNormal].flags, 0);
dynamicval<bool> a3(vid.always3, false);
dynamicval<bool> hq(inHighQual, true);
dynamicval<int> hd(darken, 0);

View File

@ -258,13 +258,13 @@ bool forced_quotient() { return quotient && !(cgflags & qOPTQ); }
EX geometry_filter gf_hyperbolic = {"hyperbolic", 'h', [] { return (arcm::in() || arb::in() || hyperbolic) && !forced_quotient(); }};
EX geometry_filter gf_spherical = {"spherical", 's', [] { return (arcm::in() || arb::in() || sphere) && !forced_quotient(); }};
EX geometry_filter gf_euclidean = {"Euclidean", 'e', [] { return (arcm::in() || arb::in() || euclid) && !forced_quotient(); }};
EX geometry_filter gf_other = {"non-isotropic", 'n', [] { return prod || nonisotropic; }};
EX geometry_filter gf_other = {"non-isotropic", 'n', [] { return mproduct || nonisotropic; }};
EX geometry_filter gf_regular_2d = {"regular 2D tesselations", 'r', [] {
return standard_tiling() && WDIM == 2 && !forced_quotient();
}};
EX geometry_filter gf_regular_3d = {"regular 3D honeycombs", '3', [] {
if(euclid) return geometry == gCubeTiling;
return !bt::in() && !kite::in() && WDIM == 3 && !forced_quotient() && !nonisotropic && !prod;
return !bt::in() && !kite::in() && WDIM == 3 && !forced_quotient() && !nonisotropic && !mproduct;
}};
EX geometry_filter gf_quotient = {"interesting quotient spaces", 'q', [] {
return forced_quotient() && !elliptic;
@ -610,7 +610,7 @@ EX void select_quotient() {
pushScreen(asonov::show_config);
}
#endif
else if(prod)
else if(mproduct)
pushScreen(product::show_config);
else if(rotspace)
hybrid::configure_period();
@ -634,7 +634,7 @@ EX void select_quotient() {
EX string full_geometry_name() {
string qstring = ginf[geometry].quotient_name;
bool variable =
!(prod || hybri || bt::in() || (WDIM == 3 && !reg3::in()) || kite::in() || arb::in());
!(mproduct || mhybrid || bt::in() || (WDIM == 3 && !reg3::in()) || kite::in() || arb::in());
string fgname = XLAT(ginf[geometry].tiling_name);
if(qstring != "none") fgname += " " + XLAT(qstring);
@ -806,7 +806,7 @@ EX geometry_data compute_geometry_data() {
gd.nom *= gd.euler;
gd.denom *= 2;
if(hybri) gd.nom *= hybrid::csteps, gd.denom *= cgi.single_step;
if(mhybrid) gd.nom *= hybrid::csteps, gd.denom *= cgi.single_step;
int g = gcd(gd.nom, gd.denom);
if(g) {
@ -1000,14 +1000,14 @@ EX void showEuclideanMenu() {
}
#endif
if(prod) {
if(mproduct) {
dialog::addSelItem(XLAT("Z-level height factor"), fts(vid.plevel_factor), 'Z');
dialog::add_action([] {
dialog::editNumber(vid.plevel_factor, 0, 2, 0.1, 0.7, XLAT("Z-level height factor"), "");
dialog::reaction = ray::reset_raycaster;
});
}
else if(hybri) {
else if(mhybrid) {
dialog::addSelItem(XLAT("number of levels"), its(hybrid::csteps / cgi.single_step), 'L');
dialog::add_action(hybrid::configure_period);
}
@ -1037,7 +1037,7 @@ EX void showEuclideanMenu() {
}
#if MAXMDIM >= 4
if(hybri) {
if(mhybrid) {
auto r = rots::underlying_scale;
dialog::addSelItem(XLAT("view the underlying geometry"), r > 0 ? fts(r)+"x" : ONOFF(false), '6');
dialog::add_action([] {

View File

@ -593,7 +593,7 @@ void geometry_information::prepare_basics() {
xp_order = 0;
if(arcm::in() && !prod)
if(arcm::in() && !mproduct)
ginf[gArchimedean].cclass = gcHyperbolic;
dynamicval<eVariation> gv(variation, variation);
@ -603,9 +603,9 @@ void geometry_information::prepare_basics() {
println(hlog, "bitruncated = ", BITRUNCATED);
}
if(hybri) {
if(mhybrid) {
auto t = this;
ld d = prod ? 1 : 2;
ld d = mproduct ? 1 : 2;
hybrid::in_underlying_geometry([&] {
t->rhexf = cgi.rhexf / d;
t->hexf = cgi.hexf / d;
@ -619,6 +619,8 @@ void geometry_information::prepare_basics() {
goto hybrid_finish;
}
if(embedded_plane) geom3::light_flip(true);
if((sphere || hyperbolic) && WDIM == 3 && !bt::in()) {
rhexf = hexf = 0.378077;
crossf = hcrossf = 0.620672;
@ -675,18 +677,6 @@ void geometry_information::prepare_basics() {
finish:
heptmove.resize(S7);
hexmove.resize(S7);
invhexmove.resize(S7);
for(int d=0; d<S7; d++)
heptmove[d] = spin(-d * ALPHA) * xpush(tessf) * spin(M_PI);
for(int d=0; d<S7; d++)
hexmove[d] = spin(hexshift-d * ALPHA) * xpush(-crossf)* spin(M_PI);
for(int d=0; d<S7; d++) invhexmove[d] = iso_inverse(hexmove[d]);
hexvdist = hdist(xpush0(hexf), xspinpush0(ALPHA/2, hcrossf));
hexhexdist = fake::in() ?
@ -777,6 +767,13 @@ void geometry_information::prepare_basics() {
}
#endif
if(geom3::euc_in_hyp()) {
scalefactor *= exp(-vid.depth);
}
if(geom3::sph_in_euc()) scalefactor *= (1 + vid.depth);
if(geom3::sph_in_hyp()) scalefactor *= sinh(1 + vid.depth);
if(scale_used()) {
scalefactor *= vid.creature_scale;
orbsize *= vid.creature_scale;
@ -799,7 +796,7 @@ void geometry_information::prepare_basics() {
plevel = vid.plevel_factor * scalefactor;
single_step = 1;
if(hybri && !prod) {
if(mhybrid && !mproduct) {
#if CAP_ARCM
if(hybrid::underlying == gArchimedean)
arcm::current.get_step_values(psl_steps, single_step);
@ -819,10 +816,26 @@ void geometry_information::prepare_basics() {
set_sibling_limit();
geom3::light_flip(false);
prepare_compute3();
if(hyperbolic && &currfp != &fieldpattern::fp_invalid)
currfp.analyze();
heptmove.resize(S7);
hexmove.resize(S7);
invhexmove.resize(S7);
for(int d=0; d<S7; d++)
heptmove[d] = spin(-d * ALPHA) * lxpush(tessf) * spin(M_PI);
for(int d=0; d<S7; d++)
hexmove[d] = spin(hexshift-d * ALPHA) * lxpush(-crossf)* spin(M_PI);
for(int d=0; d<S7; d++) invhexmove[d] = iso_inverse(hexmove[d]);
gp::prepare_matrices(inv);
#if CAP_SOLV
if(asonov::in()) {
asonov::prepare();
@ -832,7 +845,14 @@ void geometry_information::prepare_basics() {
}
EX transmatrix xspinpush(ld dir, ld dist) {
if(euclid)
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);
@ -873,13 +893,13 @@ EX namespace geom3 {
}
EX ld lev_to_factor(ld lev) {
if(prod) return -lev;
if(mproduct) return -lev;
if(WDIM == 3) return lev;
if(GDIM == 3) return vid.depth - lev;
return projection_to_factor(lev_to_projection(lev));
}
EX ld factor_to_lev(ld fac) {
if(prod) return -fac;
if(mproduct) return -fac;
if(GDIM == 3) return fac;
return vid.depth - projection_to_abslev(factor_to_projection(fac));
}
@ -904,7 +924,7 @@ EX namespace geom3 {
EX string invalid;
EX ld actual_wall_height() {
if(hybri) return cgi.plevel;
if(mhybrid) return cgi.plevel;
#if CAP_GP
if(GOLDBERG && vid.gp_autoscale_heights)
return vid.wall_height * min<ld>(4 / hypot_d(2, gp::next), 1);
@ -919,7 +939,7 @@ EX namespace geom3 {
// tanh(depth) / tanh(camera) == pconf.alpha
invalid = "";
if(GDIM == 3) ;
if(GDIM == 3 || flipped) ;
else if(vid.tc_alpha < vid.tc_depth && vid.tc_alpha < vid.tc_camera)
pconf.alpha = tan_auto(vid.depth) / tan_auto(vid.camera);
else if(vid.tc_depth < vid.tc_alpha && vid.tc_depth < vid.tc_camera) {
@ -976,7 +996,7 @@ EX namespace geom3 {
human_height = vid.human_wall_ratio * wh;
if(WDIM == 3) human_height = scalefactor * vid.height_width / 2;
if(hybri) human_height = min(human_height, cgi.plevel * .9);
if(mhybrid) human_height = min(human_height, cgi.plevel * .9);
ld reduce = (WDIM == 3 ? human_height / 2 : 0);
@ -1020,26 +1040,134 @@ EX namespace geom3 {
LOWSKY = lev_to_factor(2 * wh);
HIGH = LOWSKY;
HIGH2 = lev_to_factor(3 * wh);
SKY = LOWSKY - 5;
SKY = LOWSKY - (vid.wall_height > 0 ? 5 : -5);
if(geom3::mgclass() == gcSphere && geom3::ggclass() != gcSphere) {
ld max_high = lerp(-FLOOR, -1, 0.8);
ld max_high2 = lerp(-FLOOR, -1, 0.9);
if(HIGH < max_high) HIGH = max_high;
if(HIGH2 < max_high2) HIGH2 = max_high2;
if(LOWSKY < max_high) LOWSKY = max_high;
if(SKY < max_high) SKY = max_high;
if(vid.wall_height < 0) {
SKY = -3 * vid.wall_height;
LOWSKY = 1.75 * SKY;
}
}
}
}
EX namespace geom3 {
#if HDR
enum eSpatialEmbedding {
seDefault,
seFlat,
seInverted,
seLowerCurvature,
seLowerCurvatureInverted,
seMuchLowerCurvature,
seMuchLowerCurvatureInverted,
seProduct
};
#endif
EX vector<pair<string, string>> spatial_embedding_options = {
{"default", "Embed as a equidistant surface in the 3D version of the same geometry. This is the model used by HyperRogue in its 2D graphics."},
{"flat", "Embed as a flat surface in the 3D version of the same geometry."},
{"inverted", "Embed as a equidistant surface, but this time it is inverted."},
{"lower curvature", "Embed as a convex surface in a space of lower curvature."},
{"lower curvature inverted", "Embed as a concave surface in a space of lower curvature."},
{"much lower curvature", "Embed sphere as a convex sphere in hyperbolic space."},
{"much lower curvature inverted", "Embed sphere as a concave sphere in hyperbolic space."},
{"product", "Add one extra dimension in the Euclidean way."}
};
EX eSpatialEmbedding spatial_embedding;
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 sph_in_euc() {
return ggclass() == gcEuclid && mgclass() == gcSphere;
}
EX bool sph_in_hyp() {
return ggclass() == gcHyperbolic && mgclass() == gcSphere;
}
EX bool in_product() {
return ggclass() == gcProduct;
}
EX bool same_in_same() {
return mgclass() == ggclass();
}
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;
}
}
EX void apply_always3() {
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(!vid.always3 && g.gameplay_dimension == 2 && g.graphical_dimension == 3) {
g.graphical_dimension--;
g.homogeneous_dimension--;
g.sig[1] = g.sig[2];
g.sig[2] = g.sig[3];
#if HDR
template<class T> auto in_flipped(const T& f) -> decltype(f()) {
light_flip(true);
finalizer ff([] { light_flip(false); });
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(spatial_embedding == seProduct && g.kind != gcEuclid) {
g.kind = gcProduct;
g.homogeneous_dimension--;
g.sig[2] = g.sig[3];
gi.flags |= qHYBRID;
}
if(among(spatial_embedding, seLowerCurvature, seLowerCurvatureInverted)) {
if(g.kind == gcEuclid) g = ginf[gSpace534].g;
if(g.kind == gcSphere) g = ginf[gCubeTiling].g;
g.gameplay_dimension = 2;
}
if(among(spatial_embedding, seMuchLowerCurvature, seMuchLowerCurvatureInverted)) {
g = ginf[gSpace534].g;
g.gameplay_dimension = 2;
}
}
}
}
}
@ -1090,17 +1218,44 @@ EX void switch_always3() {
vid.always3 = true;
apply_always3();
ld ms = min<ld>(cgi.scalefactor, 1);
vid.depth = ms;
vid.wall_height = 1.5 * ms;
if(sphere) {
if(sphere && same_in_same()) {
vid.depth = 30 * degree;
vid.wall_height = 60 * degree;
}
vid.human_wall_ratio = 0.8;
if(euclid && allowIncreasedSight() && vid.use_smart_range == 0) {
if(mgclass() == gcEuclid && allowIncreasedSight() && vid.use_smart_range == 0) {
genrange_bonus = gamerange_bonus = sightrange_bonus = cgi.base_distlimit * 3/2;
}
vid.camera = 0;
vid.depth = ms;
vid.eye = 0;
if(sph_in_euc() || sph_in_hyp()) {
vid.depth = 0;
vid.wall_height = -1;
vid.eye = 0.5;
if(among(spatial_embedding, seLowerCurvatureInverted, seMuchLowerCurvatureInverted)) {
vid.wall_height = 1.4;
vid.eye = -0.2;
vid.depth = 0.5;
}
}
if(spatial_embedding == seFlat) {
vid.eye -= vid.depth / 2;
vid.depth = 0;
}
if(spatial_embedding == seInverted) {
vid.eye -= vid.depth * 1.5;
vid.depth *= -1;
}
if(euc_in_hyp() && spatial_embedding == seLowerCurvatureInverted) {
vid.wall_height *= -1;
vid.eye = 2 * vid.depth;
}
if(euc_in_hyp() && spatial_embedding == seMuchLowerCurvatureInverted) {
vid.wall_height *= -1;
vid.eye = 2 * vid.depth;
}
if(pmodel == mdDisk) pmodel = mdPerspective;
swapmatrix(View);
swapmatrix(current_display->which_copy);
@ -1111,6 +1266,8 @@ EX void switch_always3() {
#if CAP_RACING
racing::player_relative = true;
#endif
check_cgi();
cgi.prepare_basics();
}
else {
vid.always3 = false;
@ -1188,12 +1345,11 @@ EX string cgi_string() {
if(bt::in() || GDIM == 3) V("WQ", its(vid.texture_step));
if(hybri) {
if(mhybrid) {
V("U", PIU(cgi_string()));
// its(int(hybrid::underlying)));
}
if(prod) V("PL", fts(vid.plevel_factor));
if(mproduct) V("PL", fts(vid.plevel_factor));
if(geometry == gFieldQuotient) { V("S3=", its(S3)); V("S7=", its(S7)); }
if(nil) V("NIL", its(S7));
@ -1242,7 +1398,7 @@ EX void check_cgi() {
cgip = &cgis[s];
cgi.timestamp = ++ntimestamp;
if(hybri) hybrid::underlying_cgip->timestamp = ntimestamp;
if(mhybrid) hybrid::underlying_cgip->timestamp = ntimestamp;
if(fake::in()) fake::underlying_cgip->timestamp = ntimestamp;
#if CAP_ARCM
if(arcm::alt_cgip) arcm::alt_cgip->timestamp = ntimestamp;

View File

@ -100,7 +100,7 @@ transmatrix hrmap_standard::adj(heptagon *h, int d) {
int t0 = h->type;
int t1 = h->cmove(d)->type;
int sp = h->c.spin(d);
return spin(-d * TAU / t0) * xpush(spacedist(h->c7, d)) * spin(M_PI + TAU * sp / t1);
return spin(-d * TAU / t0) * lxpush(spacedist(h->c7, d)) * spin(M_PI + TAU * sp / t1);
}
transmatrix T = cgi.heptmove[d];
if(h->c.mirror(d)) T = T * Mirror;
@ -235,10 +235,10 @@ void horo_distance::become(hyperpoint h1) {
a = abs(bt::horo_level(h1));
}
#endif
else if(hybri)
else if(mhybrid)
a = 0, b = hdist(h1, C0);
else
a = 0, b = intval(h1, C0);
a = 0, b = intval(h1, tile_center());
}
horo_distance::horo_distance(shiftpoint h1, const shiftmatrix& T) {
@ -246,7 +246,7 @@ horo_distance::horo_distance(shiftpoint h1, const shiftmatrix& T) {
if(bt::in()) become(inverse_shift(T, h1));
else
#endif
if(sn::in() || hybri || nil) become(inverse_shift(T, h1));
if(sn::in() || mhybrid || nil) become(inverse_shift(T, h1));
else
a = 0, b = intval(h1.h, unshift(tC0(T), h1.shift));
}
@ -368,7 +368,7 @@ void virtualRebase(cell*& base, T& at, const U& check) {
}
/* todo variants of sol */
if(prod) {
if(mproduct) {
auto d = product_decompose(check(at)).first;
while(d > cgi.plevel / 2) {
at = currentmap->iadj(base, base->type-1) * at;
@ -530,7 +530,7 @@ transmatrix hrmap_standard::adj(cell *c, int i) {
return calc_relative_matrix(c->cmove(i), c, C0);
}
double d = cellgfxdist(c, i);
transmatrix T = ddspin(c, i) * xpush(d);
transmatrix T = ddspin(c, i) * lxpush(d);
if(c->c.mirror(i)) T = T * Mirror;
cell *c1 = c->cmove(i);
T = T * iddspin(c1, c->c.spin(i), M_PI);
@ -574,15 +574,15 @@ hyperpoint hrmap_standard::get_corner(cell *c, int cid, ld cf) {
}
#endif
if(PURE) {
return ddspin(c,cid,M_PI/S7) * xpush0(cgi.hcrossf * 3 / cf);
return ddspin(c,cid,M_PI/S7) * lxpush0(cgi.hcrossf * 3 / cf);
}
if(BITRUNCATED) {
if(!ishept(c))
return ddspin(c,cid,M_PI/S6) * xpush0(cgi.hexvdist * 3 / cf);
return ddspin(c,cid,M_PI/S6) * lxpush0(cgi.hexvdist * 3 / cf);
else
return ddspin(c,cid,M_PI/S7) * xpush0(cgi.rhexf * 3 / cf);
return ddspin(c,cid,M_PI/S7) * lxpush0(cgi.rhexf * 3 / cf);
}
return C0;
return tile_center();
}
EX bool approx_nearcorner = false;
@ -679,7 +679,7 @@ EX hyperpoint nearcorner(cell *c, int i) {
}
#endif
double d = cellgfxdist(c, i);
return ddspin(c, i) * xpush0(d);
return ddspin(c, i) * lxpush0(d);
}
/** /brief get the coordinates of the another vertex of c->move(i)
@ -728,7 +728,7 @@ EX hyperpoint farcorner(cell *c, int i, int which) {
int id = arcm::id_of(c->master);
auto id1 = ac.get_adj(ac.get_adj(c->master, i-1), -2).first;
int n1 = isize(ac.adjacent[id1]);
return spin(-t.first - M_PI / c->type) * xpush(ac.inradius[id/2] + ac.inradius[id1/2]) * xspinpush0(M_PI + M_PI/n1*(which?3:-3), ac.circumradius[id1/2]);
return spin(-t.first - M_PI / c->type) * lxpush(ac.inradius[id/2] + ac.inradius[id1/2]) * xspinpush0(M_PI + M_PI/n1*(which?3:-3), ac.circumradius[id1/2]);
}
if(BITRUNCATED || DUAL) {
int mul = DUALMUL;
@ -742,7 +742,7 @@ EX hyperpoint farcorner(cell *c, int i, int which) {
auto& t2 = arcm::current.get_triangle(adj);
return spin(-t1.first) * xpush(t1.second) * spin(M_PI + t2.first) * get_corner_position(&cx, which ? -mul : 2*mul);
return spin(-t1.first) * lxpush(t1.second) * spin(M_PI + t2.first) * get_corner_position(&cx, which ? -mul : 2*mul);
}
}
#endif
@ -768,7 +768,7 @@ EX hyperpoint get_warp_corner(cell *c, int cid) {
#if CAP_IRR || CAP_ARCM
if(IRREGULAR || arcm::in()) return midcorner(c, cid, .5);
#endif
return ddspin(c,cid,M_PI/S7) * xpush0(cgi.tessf/2);
return ddspin(c,cid,M_PI/S7) * lxpush0(cgi.tessf/2);
}
EX map<cell*, map<cell*, vector<transmatrix>>> brm_structure;
@ -899,7 +899,7 @@ EX pathgen generate_random_path(cellwalker start, int length, bool for_yendor, b
p.last = p.path.back();
}
else if(hybri) {
else if(mhybrid) {
/* I am lazy */
for(int i=1; i<=length; i++) p.path[i] = p.path[i-1]->cmove(p.path[i-1]->type-1);
p.last = p.path.back();

View File

@ -646,7 +646,7 @@ EX namespace gp {
}
if(sp>SG3) sp -= SG6;
return normalize(spin(TAU*sp/S7) * cornmul(T, corner));
return normalize_flat(spin(TAU*sp/S7) * cornmul(T, corner));
}
transmatrix dir_matrix(int i) {
@ -654,14 +654,15 @@ EX namespace gp {
return spin(M_PI - d * TAU / S7 - cgi.hexshift);
};
return spin(-cgi.gpdata->alpha) * build_matrix(
C0,
ddspin(i) * xpush0(cgi.tessf),
ddspin(i+1) * xpush0(cgi.tessf),
tile_center(),
ddspin(i) * lxpush0(cgi.tessf),
ddspin(i+1) * lxpush0(cgi.tessf),
C03
);
}
void prepare_matrices() {
EX void prepare_matrices(bool inv) {
if(!(GOLDBERG_INV || inv)) return;
cgi.gpdata->corners = inverse(build_matrix(
loctoh_ort(loc(0,0)),
loctoh_ort(param),
@ -669,6 +670,10 @@ EX namespace gp {
C03
));
cgi.gpdata->Tf.resize(S7);
/* should work directly without flipping but it does not... flipping for now */
if(embedded_plane) geom3::light_flip(true);
for(int i=0; i<S7; i++) {
transmatrix T = dir_matrix(i);
for(int x=-GOLDBERG_LIMIT_HALF; x<GOLDBERG_LIMIT_HALF; x++)
@ -679,8 +684,19 @@ EX namespace gp {
hyperpoint h = atz(T, cgi.gpdata->corners, at, 6);
hyperpoint hl = atz(T, cgi.gpdata->corners, at + eudir(d), 6);
cgi.gpdata->Tf[i][x&GOLDBERG_MASK][y&GOLDBERG_MASK][d] = rgpushxto0(h) * rspintox(gpushxto0(h) * hl) * spin180();
// cgi.gpdata->Tf[i][x&GOLDBERG_MASK][y&GOLDBERG_MASK][d] = Id; // map_relative_push(h) * lrspintox(inverse(map_relative_push(h)) * hl) * spin180();
}
}
if(geom3::flipped) {
geom3::light_flip(false);
for(int i=0; i<S7; i++) {
for(int x=-GOLDBERG_LIMIT_HALF; x<GOLDBERG_LIMIT_HALF; x++)
for(int y=-GOLDBERG_LIMIT_HALF; y<GOLDBERG_LIMIT_HALF; y++)
for(int d=0; d<(S3==3?6:4); d++) {
swapmatrix( cgi.gpdata->Tf[i][x&GOLDBERG_MASK][y&GOLDBERG_MASK][d] );
}
} }
}
EX hyperpoint get_corner_position(const local_info& li, int cid, ld cf IS(3)) {
@ -729,7 +745,6 @@ EX namespace gp {
cgi.base_distlimit = 2 * param.first + 2 * param.second + 1;
if(cgi.base_distlimit > SEE_ALL)
cgi.base_distlimit = SEE_ALL;
prepare_matrices();
DEBB(DF_GEOM | DF_POLY, ("scale = ", scale));
}
}

View File

@ -393,7 +393,7 @@ EX void drawPlayerEffects(const shiftmatrix& V, const shiftmatrix& Vparam, cell
int adj = 1 - ((sword_angles/cwt.at->type)&1);
#if CAP_QUEUE
if(!euclid && !hybri) for(int a=0; a<sword_angles; a++) {
if(!euclid && !mhybrid) for(int a=0; a<sword_angles; a++) {
if(a == ang && items[itOrbSword]) continue;
if((a+sword_angles/2)%sword_angles == ang && items[itOrbSword2]) continue;
bool longer = sword::pos2(cwt.at, a-1) != sword::pos2(cwt.at, a+1);
@ -629,7 +629,7 @@ EX void ShadowV(const shiftmatrix& V, const hpcshape& bp, PPR prio IS(PPR::MONST
#if CAP_SHAPES
transmatrix otherbodyparts(const shiftmatrix& V, color_t col, eMonster who, double footphase) {
#define VFOOT ((GDIM == 2 || hybri) ? V : at_smart_lof(V, cgi.LEG0))
#define VFOOT ((GDIM == 2 || mhybrid) ? V : at_smart_lof(V, cgi.LEG0))
#define VLEG at_smart_lof(V, cgi.LEG)
#define VGROIN at_smart_lof(V, cgi.GROIN)
#define VBODY at_smart_lof(V, cgi.BODY)
@ -681,7 +681,7 @@ transmatrix otherbodyparts(const shiftmatrix& V, color_t col, eMonster who, doub
shiftmatrix Tright, Tleft;
if(GDIM == 2 || hybri) {
if(GDIM == 2 || mhybrid) {
Tright = VFOOT * xpush(rightfoot);
Tleft = VFOOT * Mirror * xpush(-rightfoot);
}
@ -758,15 +758,15 @@ EX color_t kind_outline(eItem it) {
EX shiftmatrix face_the_player(const shiftmatrix V) {
if(GDIM == 2) return V;
if(prod) return orthogonal_move(V, cos(ptick(750)) * cgi.plevel / 16);
if(hybri) return V * zpush(cos(ptick(750)) * cgi.plevel / 16);
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(nonisotropic) return shiftless(spin_towards(unshift(V), dummy, C0, 2, 0));
#if CAP_VR
if(vrhr::enabled) {
shiftpoint h = tC0(V);
hyperpoint uh = unshift(h);
return shiftless(cspin90(1, 2) * rspintox(cspin90(2, 1) * uh) * xpush(hdist0(uh)) * cspin90(0, 2) * spin270());
return shiftless(cspin90(1, 2) * lrspintox(cspin90(2, 1) * uh) * xpush(hdist0(uh)) * cspin90(0, 2) * spin270());
}
#endif
return rgpushxto0(tC0(V));
@ -894,7 +894,7 @@ EX bool drawItemType(eItem it, cell *c, const shiftmatrix& V, color_t icol, int
shiftmatrix Vit = V;
if(GDIM == 3 && WDIM == 2 && c && it != itBabyTortoise) Vit = orthogonal_move_fol(V, cgi.STUFF);
if(c && prod)
if(c && mproduct)
Vit = orthogonal_move(Vit, sin(ptick(750)) * cgi.plevel / 4);
else if(c && sl2)
Vit = Vit * zpush(sin(ptick(750)) * cgi.plevel / 4);
@ -955,7 +955,7 @@ EX bool drawItemType(eItem it, cell *c, const shiftmatrix& V, color_t icol, int
addauraspecial(P1, 0xFF0000, 0);
}
V2 = V * rspintox(inverse_shift(V, P1));
V2 = V * lrspintox(inverse_shift(V, P1));
}
else V2 = V;
}
@ -1557,7 +1557,7 @@ EX bool drawMonsterType(eMonster m, cell *where, const shiftmatrix& V1, color_t
char xch = minf[m].glyph;
shiftmatrix V = V1;
if(WDIM == 3 && (classflag(m) & CF_FACE_UP) && where && !hybri) V = V1 * cspin90(0, 2);
if(WDIM == 3 && (classflag(m) & CF_FACE_UP) && where && !mhybrid) V = V1 * cspin90(0, 2);
#if CAP_SHAPES
if(among(m, moTortoise, moWorldTurtle) && where && where->stuntime >= 3)
@ -2641,7 +2641,7 @@ EX bool applyAnimation(cell *c, shiftmatrix& V, double& footphase, int layer) {
else
wnow = tC0(z_inverse(a.wherenow));
if(prod) {
if(gproduct) {
auto d = product_decompose(wnow);
ld dist = d.first / R * aspd;
if(abs(dist) > abs(d.first)) dist = -d.first;
@ -2856,8 +2856,8 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col
else {
if(c->monst == moTentacleGhost) {
hyperpoint V0 = history::on ? unshift(tC0(Vs)) : inverse_shift(cwtV, tC0(Vs));
hyperpoint V1 = spintox(V0) * V0;
Vs = cwtV * rspintox(V0) * rpushxto0(V1) * pispin;
hyperpoint V1 = lspintox(V0) * V0;
Vs = cwtV * lrspintox(V0) * rpushxto0(V1) * pispin;
drawMonsterType(moGhost, c, Vs, col, footphase, asciicol);
col = minf[moTentacletail].color;
}
@ -2904,7 +2904,7 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col
if(mmmon) {
if(isAnyIvy(c)) {
if(hybri) {
if(mhybrid) {
queuepoly(Vb, cgi.shILeaf[ctof(c)], darkena(col, 0, 0xFF));
for(int a=0; a<c->type-2; a++)
queuepoly(Vb * spin(a * TAU / (c->type-2)), cgi.shILeaf[2], darkena(col, 0, 0xFF));
@ -3092,7 +3092,7 @@ EX bool drawMonster(const shiftmatrix& Vparam, int ct, cell *c, color_t col, col
}
else if(NONSTDVAR) {
transmatrix T = currentmap->adj(c, c->mondir);
Vb = Vb * T * rspintox(tC0(iso_inverse(T))) * xpush(cgi.tentacle_length);
Vb = Vb * T * lrspintox(tC0(iso_inverse(T))) * xpush(cgi.tentacle_length);
}
else {
Vb = Vb * ddspin180(c, c->mondir);
@ -3129,27 +3129,27 @@ 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(WDIM == 2 || prod) {
hyperpoint V0 = inverse_shift(Vs, tC0(where));
if(WDIM == 2 || mproduct) {
hyperpoint V0 = inverse_shift(Vs, where * tile_center());
ld z = 0;
if(prod) {
if(gproduct) {
auto d = product_decompose(V0);
z = d.first;
V0 = d.second;
}
if(hypot_d(2, tC0(unshift(Vs))) > 1e-3) {
Vs = Vs * rspintox(V0);
if(prod) Vs = orthogonal_move(Vs, z);
Vs = Vs * lrspintox(V0);
if(gproduct) Vs = orthogonal_move(Vs, z);
}
}
else if(!sl2) {
hyperpoint V0 = inverse_shift(Vs, tC0(where));
Vs = Vs * rspintox(V0);
Vs = Vs * lrspintox(V0);
// cwtV * rgpushxto0(inverse(cwtV) * tC0(Vs));
}
if(c->monst == moHunterChanging)
Vs = Vs * (hybri ? spin180() : cspin180(WDIM-2, WDIM-1));
Vs = Vs * (mhybrid ? spin180() : cspin180(WDIM-2, WDIM-1));
}
if(c->monmirror) Vs = Vs * Mirror;
@ -3518,7 +3518,7 @@ void draw_movement_arrows(cell *c, const transmatrix& V, int df) {
transmatrix Centered = rgpushxto0(unshift(tC0(cwtV)));
int sd = md.subdir;
transmatrix T = iso_inverse(Centered) * rgpushxto0(Centered * tC0(V)) * rspintox(Centered*tC0(V)) * spin(-sd * M_PI/S7) * xpush(0.2);
transmatrix T = iso_inverse(Centered) * rgpushxto0(Centered * tC0(V)) * lrspintox(Centered*tC0(V)) * spin(-sd * M_PI/S7) * xpush(0.2);
if(vid.axes >= 5)
queuestr(shiftless(T), keysize, s0 + key, col >> 8, 1);
@ -3994,7 +3994,7 @@ EX color_t transcolor(cell *c, cell *c2, color_t wcol) {
// how much should be the d-th wall darkened in 3D
EX int get_darkval(cell *c, int d) {
if(hybri) {
if(mhybrid) {
return d >= c->type - 2 ? 4 : 0;
}
const int darkval_hbt[9] = {0,2,2,0,6,6,8,8,0};
@ -4054,7 +4054,7 @@ EX bool clip_checked = false;
void make_clipping_planes() {
#if MAXMDIM >= 4
clip_checked = false;
if(!frustum_culling || PIU(sphere) || experimental || vid.stereo_mode == sODS || panini_alpha || stereo_alpha || prod) return;
if(!frustum_culling || PIU(sphere) || experimental || vid.stereo_mode == sODS || panini_alpha || stereo_alpha || gproduct || embedded_plane) return;
if(WDIM == 3 && pmodel == mdPerspective && !nonisotropic && !in_s2xe())
threshold = sin_auto(cgi.corner_bonus), xyz_threshold = 0, clip_checked = true;
@ -4221,26 +4221,26 @@ EX subcellshape& generate_subcellshape_if_needed(cell *c, int id) {
auto& ss = cgi.subshapes[id];
if(!ss.faces.empty()) return ss;
cell *c1 = hybri ? hybrid::get_where(c).first : c;
cell *c1 = mhybrid ? hybrid::get_where(c).first : c;
if(hybri || WDIM == 2) for(int i=0; i<c1->type; i++) {
if(mhybrid || WDIM == 2) for(int i=0; i<c1->type; i++) {
hyperpoint w;
auto f = [&] {
/* mirror image of C0 in the axis h1-h2 */
hyperpoint h1 = get_corner_position(c1, i);
hyperpoint h2 = get_corner_position(c1, i+1);
transmatrix T = gpushxto0(h1);
T = spintox(T * h2) * T;
T = lspintox(T * h2) * T;
w = T * C0;
w[1] = -w[1];
w = iso_inverse(T) * w;
};
if(prod) PIU(f());
if(mproduct) PIU(f());
else f();
ss.walltester.push_back(w);
}
if(hybri || WDIM == 2) {
if(mhybrid || WDIM == 2) {
ss.walltester.push_back(C0);
ss.walltester.push_back(C0);
}
@ -4253,7 +4253,7 @@ EX subcellshape& generate_subcellshape_if_needed(cell *c, int id) {
int z = a ? 1 : -1;
hyperpoint ctr = zpush0(z * cgi.plevel/2);
for(int i=0; i<c1->type; i++)
if(prod || WDIM == 2)
if(mproduct || WDIM == 2)
l.push_back(hybrid::get_corner(c1, i, 0, z));
else {
l.push_back(ctr);
@ -4274,7 +4274,7 @@ EX subcellshape& generate_subcellshape_if_needed(cell *c, int id) {
int hrmap::wall_offset(cell *c) {
int id = currentmap->full_shvid(c);
if(WDIM == 3 && !hybri && !reg3::in()) return 0;
if(WDIM == 3 && !mhybrid && !reg3::in()) return 0;
if(isize(cgi.walloffsets) <= id) cgi.walloffsets.resize(id+1, {-1, nullptr});
auto &wop = cgi.walloffsets[id];
@ -4791,7 +4791,7 @@ EX void drawMarkers() {
#endif
if(hybri && !shmup::on) {
if(mhybrid && !shmup::on) {
using namespace sword;
int& ang = sword::dir[multi::cpid].angle;
@ -4854,7 +4854,7 @@ EX void drawMarkers() {
auto& c2 = mib.t;
shiftmatrix T1 = ggmatrix(c1);
shiftmatrix T2 = ggmatrix(c2);
shiftmatrix T = T1 * rspintox(inverse_shift(T1,T2*C0)) * xpush(hdist(T1*C0, T2*C0) * fractick(50, 0));
shiftmatrix T = T1 * lrspintox(inverse_shift(T1,T2*C0)) * xpush(hdist(T1*C0, T2*C0) * fractick(50, 0));
color_t aircol = (orbToTarget == itOrbAir ? 0x8080FF40 : 0x8080FF20);
queuepoly(T, cgi.shDisk, aircol);
c1 = c2;
@ -5017,7 +5017,7 @@ EX transmatrix actual_view_transform;
EX ld wall_radar(cell *c, transmatrix T, transmatrix LPe, ld max) {
if(!in_perspective() || !vid.use_wall_radar) return max;
transmatrix ori;
if(prod) ori = ortho_inverse(LPe);
if(gproduct) ori = ortho_inverse(LPe);
ld step = max / 20;
ld fixed_yshift = 0;
for(int i=0; i<20; i++) {
@ -5052,6 +5052,7 @@ EX void make_actual_view() {
actual_view_transform = get_shift_view_of(ztangent(d), actual_view_transform * View) * view_inverse(View);
}
camera_level = asin_auto(tC0(view_inverse(actual_view_transform * View))[2]);
camera_sign = cgi.FLOOR > cgi.WALL;
}
if(nonisotropic && !nonisotropic_weird_transforms) {
transmatrix T = actual_view_transform * View;
@ -5099,7 +5100,7 @@ EX void precise_mouseover() {
if(WDIM == 3 && (cmode & (sm::EDIT_INSIDE_WALLS | sm::EDIT_BEFORE_WALLS))) {
transmatrix T = view_inverse(View);
transmatrix ori = Id;
if(prod) ori = ortho_inverse(NLP);
if(gproduct) ori = ortho_inverse(NLP);
ld step = 0.2;
cell *c = centerover;
for(int i=0; i<100; i++) {
@ -5175,7 +5176,7 @@ EX void center_multiplayer_map(const vector<hyperpoint>& hs) {
hyperpoint h = Hypc;
for(auto h1: hs) h += h1;
h /= isize(hs);
h = normalize(h);
h = normalize_flat(h);
cwtV = shiftless(rgpushxto0(h));
if(isize(hs) == 2) {
set_multi = true;
@ -5307,7 +5308,7 @@ EX void drawthemap() {
else {
vector<hyperpoint> pts;
for(int p=0; p<multi::players; p++) if(multi::playerActive(p))
pts.push_back(unshift(tC0(multi::whereis[p])));
pts.push_back(unshift(multi::whereis[p] * tile_center()));
center_multiplayer_map(pts);
}
}
@ -5322,7 +5323,7 @@ EX void drawthemap() {
else {
vector<hyperpoint> pts;
for(int p=0; p<multi::players; p++)
pts.push_back(unshift(tC0(shmup::pc[p]->pat)));
pts.push_back(unshift(shmup::pc[p]->pat * tile_center()));
center_multiplayer_map(pts);
}
}
@ -5361,7 +5362,7 @@ EX void drawmovestar(double dx, double dy) {
if(rug::rugged && multi::players == 1 && !multi::alwaysuse) return;
#endif
shiftpoint H = tC0(cwtV);
shiftpoint H = cwtV * tile_center();
ld R = sqrt(H[0] * H[0] + H[1] * H[1]);
shiftmatrix Centered;
@ -5886,7 +5887,7 @@ EX void restartGraph() {
if(!autocheat) linepatterns::clearAll();
if(currentmap) {
resetview();
if(sphere) View = spin(-90._deg);
View = inverse(View);
}
}
@ -6001,7 +6002,7 @@ EX void animateAttackOrHug(const movei& m, int layer, int phase, ld ratio, ld de
animation& a = animations[layer][m.s];
a.attacking = phase;
if(phase == 3) println(hlog, "distance = ", hdist0(T * C0));
a.attackat = rspintox(tC0(iso_inverse(T))) * xpush(hdist0(T*C0) * ratio + delta);
a.attackat = lrspintox(tC0(iso_inverse(T))) * lxpush(hdist0(T*C0) * ratio + delta);
if(newanim) a.wherenow = Id, a.ltick = ticks, a.footphase = 0;
}

View File

@ -25,6 +25,7 @@ cell *newCell(int type, heptagon *master);
*/
EX hstate transition(hstate s, int dir) {
if(embedded_plane) return IPF(transition(s, dir));
if(sphere) {
if(S7 == 4) {
if(s == hsOrigin) return dir == 0 ? hsB0 : hsB1;

View File

@ -372,7 +372,7 @@ EX namespace history {
v[ph+1]->at * C0;
View = xpush(-(phase-ph) * hdist(now, next)) * View;
if(WDIM == 2 || prod) {
if(WDIM == 2 || mproduct) {
View = models::rotmatrix() * View;
}
else {

15
hyper.h
View File

@ -148,8 +148,6 @@ void addMessage(string s, char spamtype = 0);
#define nih (cgflags & qNIH)
#define nil (cgclass == gcNil)
#define sl2 (cgclass == gcSL2)
#define prod (cgclass == gcProduct)
#define hybri (cgflags & qHYBRID)
#define rotspace (geometry == gRotSpace)
#define hyperbolic (cgclass == gcHyperbolic)
#define nonisotropic (among(cgclass, gcSolNIH, gcNil, gcSL2))
@ -160,6 +158,19 @@ void addMessage(string s, char spamtype = 0);
#define smallbounded ((cgflags & qSMALL) || disksize)
#define closed_manifold (cgflags & qCLOSED)
#define closed_or_bounded (closed_manifold || disksize)
/** the actual map has hybrid geometry, not just the graphics */
#define mhybrid (cgflags & qHYBRID)
/** graphics based on a product geometry -- either embedded or actual hybrid product */
#define gproduct (cgclass == gcProduct)
/** 2D geometry embedded in 3D */
#define embedded_plane (WDIM == 2 && GDIM == 3)
/** the actual map is product, not just the graphics */
#define mproduct (gproduct && !embedded_plane)
/** the actual map is product, not just the graphics */
#define meuclid (geom3::mgclass() == gcEuclid)
#define msphere (geom3::mgclass() == gcSphere)
#define mhyperbolic (geom3::mgclass() == gcHyperbolic)
// Dry Forest burning, heat transfer, etc. are performed on the whole universe
#define doall (closed_or_bounded)

View File

@ -389,6 +389,13 @@ EX ld edge_of_triangle_with_angles(ld alpha, ld beta, ld gamma) {
EX hyperpoint hpxy(ld x, ld y) {
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));
if(embedded_plane) {
geom3::light_flip(true);
hyperpoint h = hpxy(x, y);
geom3::light_flip(false);
swapmatrix(h);
return h;
}
return PIU(hpxyz(x,y, translatable ? 1 : sphere ? sqrt(1-x*x-y*y) : sqrt(1+x*x+y*y)));
}
@ -427,7 +434,7 @@ EX ld intval(const hyperpoint &h1, const hyperpoint &h2) {
}
EX ld quickdist(const hyperpoint &h1, const hyperpoint &h2) {
if(prod) return hdist(h1, h2);
if(gproduct) return hdist(h1, h2);
return intval(h1, h2);
}
@ -515,7 +522,7 @@ EX ld zlevel(const hyperpoint &h) {
else if(translatable) return h[LDIM];
else if(sphere) return sqrt(intval(h, Hypc));
else if(in_e2xe()) return log(h[2]);
else if(prod) return log(sqrt(abs(intval(h, Hypc)))); /* abs works with both underlying spherical and hyperbolic */
else if(gproduct) return log(sqrt(abs(intval(h, Hypc)))); /* abs works with both underlying spherical and hyperbolic */
else return (h[LDIM] < 0 ? -1 : 1) * sqrt(-intval(h, Hypc));
}
@ -534,7 +541,7 @@ EX ld hypot_auto(ld x, ld y) {
/** normalize the homogeneous coordinates */
EX hyperpoint normalize(hyperpoint H) {
if(prod) return H;
if(gproduct) return H;
ld Z = zlevel(H);
for(int c=0; c<MXDIM; c++) H[c] /= Z;
return H;
@ -550,17 +557,38 @@ EX hyperpoint ultra_normalize(hyperpoint H) {
/** normalize, and in product geometry, also flatten */
EX hyperpoint normalize_flat(hyperpoint h) {
if(prod) return product_decompose(h).second;
if(gproduct) return product_decompose(h).second;
if(sl2) h = slr::translate(h) * zpush0(-atan2(h[2], h[3]));
if(geom3::euc_in_hyp()) {
h = normalize(h);
auto h1 = deparabolic13(h);
h1[2] = 0;
return parabolic13(h1);
}
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(prod) {
if(gproduct) {
auto d1 = product_decompose(H1);
auto d2 = product_decompose(H2);
return orthogonal_move(PIU( mid(d1.second, d2.second) ), (d1.first + d2.first) / 2);
hyperpoint res1 = PIU( mid(d1.second, d2.second) );
hyperpoint res = orthogonal_move(res1, (d1.first + d2.first) / 2);
return res;
}
return normalize(H1 + H2);
}
@ -571,7 +599,7 @@ EX shiftpoint mid(const shiftpoint& H1, const shiftpoint& H2) {
/** like mid, but take 3D into account */
EX hyperpoint midz(const hyperpoint& H1, const hyperpoint& H2) {
if(prod) return mid(H1, H2);
if(gproduct) return mid(H1, H2);
hyperpoint H3 = H1 + H2;
ld Z = 2;
@ -691,7 +719,7 @@ EX transmatrix euaffine(hyperpoint h) {
}
EX transmatrix cpush(int cid, ld alpha) {
if(prod && cid == 2)
if(gproduct && cid == 2)
return scale_matrix(Id, exp(alpha));
transmatrix T = Id;
if(nonisotropic)
@ -703,6 +731,7 @@ EX transmatrix cpush(int cid, ld alpha) {
}
EX transmatrix lzpush(ld z) {
if(geom3::euc_in_hyp() && !destandarize_eih) return cpush(0, z);
return cpush(2, z);
}
@ -715,6 +744,17 @@ 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(WDIM == 2 && GDIM == 3) {
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++)
@ -726,8 +766,29 @@ EX bool eqmatrix(transmatrix A, transmatrix B, ld eps IS(.01)) {
#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::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::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(GDIM == 2) return scale_point(h, geom3::scale_at_lev(z));
if(prod) return scale_point(h, exp(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);
@ -764,19 +825,44 @@ EX transmatrix matrix4(ld a, ld b, ld c, ld d, ld e, ld f, ld g, ld h, ld i, ld
}
#if MAXMDIM >= 4
/** Transform a matrix between the 'embedded_plane' and underlying representation. Switches to the current variant. */
EX void swapmatrix(transmatrix& T) {
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;
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::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::in_product()) {
/* just do nothing */
}
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<4; i++) for(int j=0; j<4; j++) if(isnan(T[i][j])) T = Id;
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::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; }
swap(h[2], h[3]);
if(GDIM == 3) h[2] = 0;
if(geom3::euc_in_hyp()) h = parabolic13(h[0], h[1]) * C0;
}
#endif
@ -793,9 +879,20 @@ EX transmatrix parabolic1(ld u) {
}
}
EX bool destandarize_eih = true;
EX transmatrix parabolic13(ld u, ld v) {
if(euclid)
return eupush3(0, u, v);
else if(geom3::euc_in_hyp() && destandarize_eih) {
ld diag = (u*u+v*v)/2;
return matrix4(
1, 0, -u, u,
0, 1, -v, v,
u, v, -diag+1, diag,
u, v, -diag, diag+1
);
}
else {
ld diag = (u*u+v*v)/2;
return matrix4(
@ -809,6 +906,13 @@ EX transmatrix parabolic13(ld u, ld v) {
EX hyperpoint deparabolic13(hyperpoint h) {
if(euclid) return h;
if(geom3::euc_in_hyp() && destandarize_eih) {
h /= (1 + h[LDIM]);
h[2] -= 1;
h /= sqhypot_d(LDIM, h);
h[2] += .5;
return point3(h[0] * 2, h[1] * 2, log(2) + log(-h[2]));
}
h /= (1 + h[LDIM]);
h[0] -= 1;
h /= sqhypot_d(LDIM, h);
@ -818,12 +922,26 @@ EX hyperpoint deparabolic13(hyperpoint h) {
EX hyperpoint parabolic13(hyperpoint h) {
if(euclid) return h;
else if(geom3::euc_in_hyp() && destandarize_eih) {
return parabolic13(h[0], h[1]) * cpush0(2, h[2]);
}
else if(LDIM == 3)
return parabolic13(h[1], h[2]) * xpush0(h[0]);
else
return parabolic1(h[1]) * xpush0(h[0]);
}
EX transmatrix parabolic13_at(hyperpoint h) {
if(euclid) return rgpushxto0(h);
else if(geom3::euc_in_hyp() && destandarize_eih) {
return parabolic13(h[0], h[1]) * cpush(2, h[2]);
}
else if(LDIM == 3)
return parabolic13(h[1], h[2]) * xpush(h[0]);
else
return parabolic1(h[1]) * xpush(h[0]);
}
EX transmatrix spintoc(const hyperpoint& H, int t, int f) {
transmatrix T = Id;
ld R = hypot(H[f], H[t]);
@ -852,7 +970,7 @@ EX transmatrix rspintoc(const hyperpoint& H, int t, int f) {
* \see rspintox
*/
EX transmatrix spintox(const hyperpoint& H) {
if(GDIM == 2 || prod) return spintoc(H, 0, 1);
if(GDIM == 2 || gproduct) return spintoc(H, 0, 1);
transmatrix T1 = spintoc(H, 0, 1);
return spintoc(T1*H, 0, 2) * T1;
}
@ -860,7 +978,19 @@ EX transmatrix spintox(const hyperpoint& H) {
/** inverse of hr::spintox
*/
EX transmatrix rspintox(const hyperpoint& H) {
if(GDIM == 2 || prod) return rspintoc(H, 0, 1);
if(GDIM == 2 || gproduct) return rspintoc(H, 0, 1);
transmatrix T1 = spintoc(H, 0, 1);
return rspintoc(H, 0, 1) * rspintoc(T1*H, 0, 2);
}
EX transmatrix lspintox(const hyperpoint& H) {
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(WDIM == 2 || gproduct) return rspintoc(H, 0, 1);
transmatrix T1 = spintoc(H, 0, 1);
return rspintoc(H, 0, 1) * rspintoc(T1*H, 0, 2);
}
@ -915,7 +1045,7 @@ EX transmatrix rpushxto0(const hyperpoint& H) {
EX transmatrix ggpushxto0(const hyperpoint& H, ld co) {
if(translatable)
return eupush(H, co);
if(prod) {
if(gproduct) {
auto d = product_decompose(H);
return scale_matrix(PIU(ggpushxto0(d.second, co)), exp(d.first * co));
}
@ -958,7 +1088,7 @@ EX shiftmatrix rgpushxto0(const shiftpoint& H) {
EX void fixmatrix(transmatrix& T) {
if(nonisotropic) ; // T may be inverse... do not do that
else if(cgflags & qAFFINE) ; // affine
else if(prod) {
else if(gproduct) {
auto z = zlevel(tC0(T));
T = scale_matrix(T, exp(-z));
PIU(fixmatrix(T));
@ -1157,14 +1287,14 @@ EX transmatrix z_inverse(const transmatrix& T) {
/** \brief T inverse a matrix T = O*P, where O is orthogonal and P is an isometry (todo optimize) */
EX transmatrix view_inverse(transmatrix T) {
if(nonisotropic) return inverse(T);
if(prod) return z_inverse(T);
if(gproduct) return z_inverse(T);
return iso_inverse(T);
}
/** \brief T inverse a matrix T = P*O, where O is orthogonal and P is an isometry (todo optimize) */
EX transmatrix iview_inverse(transmatrix T) {
if(nonisotropic) return inverse(T);
if(prod) return z_inverse(T);
if(gproduct) return z_inverse(T);
return iso_inverse(T);
}
@ -1298,9 +1428,16 @@ EX hyperpoint scale_point(const hyperpoint& h, ld scale_factor) {
return res;
}
/** 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::sph_in_hyp()) return zpush0(1);
return C0;
}
EX transmatrix orthogonal_move(const transmatrix& t, double level) {
if(prod) return scale_matrix(t, exp(level));
if(GDIM == 3) return t * cpush(2, level);
if(gproduct) return scale_matrix(t, exp(level));
if(GDIM == 3) return t * lzpush(level);
return scale_matrix(t, geom3::lev_to_factor(level));
}
@ -1396,7 +1533,7 @@ EX ld xcross(ld x1, ld y1, ld x2, ld y2) { return x1 + (x2 - x1) * y1 / (y1 - y2
EX transmatrix parallel_transport(const transmatrix Position, const transmatrix& ori, const hyperpoint direction) {
if(nonisotropic) return nisot::parallel_transport(Position, direction);
else if(prod) {
else if(gproduct) {
hyperpoint h = product::direct_exp(ori * direction);
return Position * rgpushxto0(h);
}
@ -1408,7 +1545,7 @@ EX void apply_parallel_transport(transmatrix& Position, const transmatrix orient
}
EX void rotate_object(transmatrix& Position, transmatrix& orientation, transmatrix R) {
if(prod) orientation = orientation * R;
if(gproduct) orientation = orientation * R;
else Position = Position * R;
}
@ -1419,7 +1556,7 @@ EX transmatrix spin_towards(const transmatrix Position, transmatrix& ori, const
T = nisot::spin_towards(Position, goal);
else {
hyperpoint U = inverse(Position) * goal;
if(prod) {
if(gproduct) {
hyperpoint h = product::inverse_exp(U);
alpha = asin_clamp(h[2] / hypot_d(3, h));
U = product_decompose(U).second;
@ -1427,7 +1564,7 @@ EX transmatrix spin_towards(const transmatrix Position, transmatrix& ori, const
T = rspintox(U);
}
if(back < 0) T = T * spin180(), alpha = -alpha;
if(prod) {
if(gproduct) {
if(dir == 0) ori = cspin(2, 0, alpha);
if(dir == 2) ori = cspin(2, 0, alpha - 90._deg), dir = 0;
}
@ -1463,6 +1600,15 @@ EX transmatrix transpose(transmatrix T) {
return result;
}
EX hyperpoint lspinpush0(ld alpha, ld x) {
geom3::light_flip(true);
hyperpoint h = xspinpush0(alpha, x);
geom3::light_flip(false);
swapmatrix(h);
return h;
// return spin(alpha) * lxpush(x) * C0;
}
#if HDR
namespace slr {
hyperpoint xyz_point(ld x, ld y, ld z);
@ -1472,7 +1618,7 @@ namespace slr {
inline hyperpoint cpush0(int c, ld x) {
hyperpoint h = Hypc;
if(sl2) return slr::xyz_point(c==0?x:0, c==1?x:0, c==2?x:0);
if(c == 2 && prod) {
if(c == 2 && gproduct) {
h[2] = exp(x);
return h;
}
@ -1483,6 +1629,7 @@ inline hyperpoint cpush0(int c, ld x) {
inline hyperpoint xspinpush0(ld alpha, ld x) {
if(sl2) return slr::polar(x, -alpha, 0);
if(embedded_plane) return lspinpush0(alpha, x);
hyperpoint h = Hypc;
h[LDIM] = cos_auto(x);
h[0] = sin_auto(x) * cos(alpha);
@ -1491,6 +1638,7 @@ inline hyperpoint xspinpush0(ld alpha, 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); }
@ -1514,9 +1662,12 @@ EX hyperpoint ctangent(int c, ld x) { return point3(c==0?x:0, c==1?x:0, c==2?x:0
/** tangent vector in direction X */
EX hyperpoint xtangent(ld x) { return ctangent(0, x); }
/** tangent vector in direction Y */
/** 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) { 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);
@ -1533,7 +1684,7 @@ EX hyperpoint direct_exp(hyperpoint v) {
if(nil) return nilv::formula_exp(v);
if(sl2 || stretch::in()) return stretch::mstretch ? nisot::numerical_exp(v) : rots::formula_exp(v);
#endif
if(prod) return product::direct_exp(v);
if(gproduct) return product::direct_exp(v);
ld d = hypot_d(GDIM, v);
if(d > 0) for(int i=0; i<GDIM; i++) v[i] = v[i] * sin_auto(d) / d;
v[LDIM] = cos_auto(d);
@ -1564,7 +1715,7 @@ EX hyperpoint inverse_exp(const shiftpoint h, flagtype prec IS(pNORMAL)) {
#endif
if(nil) return nilv::get_inverse_exp(h.h, prec);
if(sl2) return slr::get_inverse_exp(h);
if(prod) return product::inverse_exp(h.h);
if(gproduct) return product::inverse_exp(h.h);
ld d = acos_auto_clamp(h[GDIM]);
hyperpoint v = Hypc;
if(d && sin_auto(d)) for(int i=0; i<GDIM; i++) v[i] = h[i] * d / sin_auto(d);
@ -1596,7 +1747,7 @@ EX hyperpoint lp_apply(const hyperpoint h) {
return nisot::local_perspective_used() ? NLP * h : h;
}
EX hyperpoint smalltangent() { return xtangent(.1); }
EX hyperpoint smalltangent() { if(embedded_plane && msphere) return lxpush0(0.1); else return xtangent(.1); }
EX void cyclefix(ld& a, ld b) {
while(a > b + M_PI) a -= TAU;
@ -1617,7 +1768,7 @@ EX unsigned bucketer(ld x) {
EX unsigned bucketer(hyperpoint h) {
unsigned dx = 0;
if(prod) {
if(gproduct) {
auto d = product_decompose(h);
h = d.second;
dx += bucketer(d.first) * 50;

View File

@ -13,7 +13,7 @@ shiftpoint ghpm = shiftless(C02);
EX ld flip_limit = 1.1;
EX bool flip_sphere() { return sphere && pconf.alpha > flip_limit; }
EX bool flip_sphere() { return GDIM == 2 && sphere && pconf.alpha > flip_limit; }
EX bool sphere_flipped;
@ -516,7 +516,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
switch(md) {
case mdPerspective: {
if(prod) H = product::inverse_exp(H);
if(gproduct) H = product::inverse_exp(H);
apply_nil_rotation(H);
H = lp_apply(H);
apply_perspective(H, ret);
@ -888,7 +888,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
ret = lp_apply(H);
break;
}
if(prod) {
if(gproduct) {
ret = H;
break;
}
@ -1259,7 +1259,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
return;
}
if(nonisotropic || prod) {
if(nonisotropic || gproduct) {
ret = lp_apply(inverse_exp(H_orig));
ret[3] = 1;
break;
@ -1557,7 +1557,7 @@ EX bool confusingGeometry() {
}
EX ld master_to_c7_angle() {
if(hybri) return hybrid::in_underlying_geometry(master_to_c7_angle);
if(mhybrid) return hybrid::in_underlying_geometry(master_to_c7_angle);
if(WDIM == 3) return 0;
ld alpha = 0;
#if CAP_GP
@ -1567,7 +1567,7 @@ EX ld master_to_c7_angle() {
}
EX transmatrix actualV(const heptspin& hs, const transmatrix& V) {
if(prod) return PIU(actualV(hs, V));
if(gproduct) return PIU(actualV(hs, V));
if(WDIM == 3) return V;
#if CAP_IRR
if(IRREGULAR)
@ -1592,7 +1592,7 @@ EX bool point_behind(const shiftpoint h) {
if(!in_perspective()) return false;
hyperpoint h1;
if(pmodel == mdGeodesic) h1 = inverse_exp(h, pQUICK);
if(pmodel == mdPerspective && prod) h1 = product::inverse_exp(h.h);
if(pmodel == mdPerspective && gproduct) h1 = product::inverse_exp(h.h);
h1 = lp_apply(h1);
return h1[2] < 1e-8;
}
@ -1605,7 +1605,7 @@ EX bool invalid_matrix(const transmatrix T) {
for(int i=0; i<GDIM; i++) for(int j=0; j<GDIM; j++)
if(std::isnan(T[i][j]) || T[i][j] > 1e8 || T[i][j] < -1e8 || std::isinf(T[i][j]))
return true;
if(prod || (cgflags & qAFFINE)) {
if(gproduct || (cgflags & qAFFINE)) {
for(int i=0; i<GDIM; i++) for(int j=0; j<GDIM; j++) if(abs(T[i][j]) > 1e-60) return false;
}
else
@ -1632,13 +1632,17 @@ 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;
if(x > current_display->xtop + current_display->xsize * 2) return false;
if(x < current_display->xtop - current_display->xsize * 1) return false;
if(y > current_display->ytop + current_display->ysize * 2) return false;
if(y < current_display->ytop - current_display->ysize * 1) return false;
if(GDIM == 3) {
if(-h1[2] < pconf.clip_min * 2 - pconf.clip_max) return false;
if(-h1[2] > pconf.clip_max * 2 - pconf.clip_min) return false;
bool culling = !geom3::euc_in_hyp();
if(culling) {
if(x > current_display->xtop + current_display->xsize * 2) return false;
if(x < current_display->xtop - current_display->xsize * 1) return false;
if(y > current_display->ytop + current_display->ysize * 2) return false;
if(y < current_display->ytop - current_display->ysize * 1) return false;
if(GDIM == 3) {
if(-h1[2] < pconf.clip_min * 2 - pconf.clip_max) return false;
if(-h1[2] > pconf.clip_max * 2 - pconf.clip_min) return false;
}
}
ld epsilon = 0.01;
@ -1675,6 +1679,8 @@ EX bool in_smart_range(const shiftmatrix& T) {
ld scale = sqrt(dh[0] * dh[1]) * cgi.scalefactor * hcrossf7;
if(scale <= vid.smart_range_detail) return false;
}
if(!culling) return true;
return
x - 2 * dx < current_display->xtop + current_display->xsize &&
@ -1889,16 +1895,25 @@ void hrmap_standard::draw_at(cell *at, const shiftmatrix& where) {
}
EX bool keep_vertical() {
if((WDIM == 2 || prod) && GDIM == 3 && vid.fixed_yz) return !CAP_ORIENTATION;
if((WDIM == 2 || gproduct) && GDIM == 3 && vid.fixed_yz) return !CAP_ORIENTATION;
if(downseek.qty) return true;
return false;
}
EX hyperpoint vertical_vector() {
auto& ds = downseek;
if((WDIM == 2 || prod) && GDIM == 3 && vid.fixed_yz)
return get_view_orientation() * ztangent(1);
else if(ds.qty && prod)
if(msphere && !sphere && vid.fixed_yz) {
hyperpoint h = get_view_orientation() * C0;
if(vid.wall_height > 0) h = -h;
return h;
}
if(meuclid && hyperbolic && vid.fixed_yz) {
hyperpoint h = iso_inverse(View) * C0;
return View * (orthogonal_move(h, vid.wall_height) - h);
}
if((WDIM == 2 || gproduct) && GDIM == 3 && vid.fixed_yz)
return get_view_orientation() * lztangent(1);
else if(ds.qty && gproduct)
return get_view_orientation() * product::inverse_exp(ds.point);
else if(ds.qty)
return ds.point;
@ -1918,7 +1933,7 @@ EX void spinEdge(ld aspd) {
transmatrix V = T * get_view_orientation();
hyperpoint h = inverse(V) * C0;
if(!prod) {
if(!gproduct) {
V = V * rgpushxto0(h);
}
@ -1943,7 +1958,7 @@ EX void spinEdge(ld aspd) {
V = cspin90(dir, 2) * V;
V = inverse(T) * V;
if(!prod) V = V * gpushxto0(h);
if(!gproduct) V = V * gpushxto0(h);
get_view_orientation() = V;
return;
}
@ -2009,6 +2024,16 @@ void fix_whichcopy_if_near() {
current_display->which_copy = T;
}
EX void adjust_eye(transmatrix& T, cell *c) {
if(!embedded_plane) return;
geom3::do_auto_eye();
int sl = snakelevel(c);
if(isWorm(c->monst) && sl < 3) sl++;
int i = (msphere && !sphere) ? 1 : 0;
if(sl || vid.eye || i)
T = T * lzpush(cgi.SLEV[sl] - cgi.FLOOR + vid.eye + i);
}
EX void centerpc(ld aspd) {
if(subscreens::split([=] () {centerpc(aspd);})) return;
@ -2029,14 +2054,13 @@ EX void centerpc(ld aspd) {
auto& pc = shmup::pc[id];
centerover = pc->base;
transmatrix T = pc->at;
int sl = snakelevel(cwt.at);
if((sl || vid.eye) && WDIM == 2) T = T * zpush(cgi.SLEV[sl] - cgi.FLOOR + vid.eye);
adjust_eye(T, cwt.at);
/* in nonisotropic geometries, T is isometry * rotation, so iso_inverse does not work */
if(nonisotropic)
View = inverse(T);
else
View = iso_inverse(T);
if(prod) NLP = ortho_inverse(pc->ori);
if(gproduct) NLP = ortho_inverse(pc->ori);
if(WDIM == 2) rotate_view( cspin180(0, 1) * cspin(2, 1, 90._deg + shmup::playerturny[id]) * spin270() );
return;
}
@ -2061,22 +2085,17 @@ EX void centerpc(ld aspd) {
if(invalid_matrix(T)) return;
#if MAXMDIM >= 4
if(GDIM == 3 && WDIM == 2) {
geom3::do_auto_eye();
int sl = snakelevel(cwt.at);
if(isWorm(cwt.at->monst) && sl < 3) sl++;
if(sl || vid.eye) T = T * zpush(cgi.SLEV[sl] - cgi.FLOOR + vid.eye);
}
#endif
adjust_eye(T, cwt.at);
hyperpoint H = tC0(T);
ld R = (zero_d(GDIM, H) && !prod) ? 0 : hdist0(H);
ld R = (zero_d(GDIM, H) && !gproduct) ? 0 : hdist0(H);
if(R < 1e-9) {
// either already centered or direction unknown
/* if(playerfoundL && playerfoundR) {
} */
spinEdge(aspd);
fixmatrix(View);
fix_whichcopy(cwt.at);
@ -2182,6 +2201,7 @@ EX void resetview() {
if(cwt.at) {
centerover = cwt.at;
View = iddspin(cwt.at, cwt.spin);
adjust_eye(View, cwt.at);
if(!flipplayer) View = pispin * View;
if(cwt.mirrored) View = Mirror * View;
@ -2197,21 +2217,22 @@ EX void resetview() {
}
if(GDIM == 2) View = spin(M_PI + vid.fixed_facing_dir * degree) * View;
if(GDIM == 3 && !prod) View = cspin90(0, 2) * View;
if(prod) NLP = cspin90(0, 2);
if(GDIM == 3 && !gproduct) View = cspin90(0, 2) * View;
if(gproduct) NLP = cspin90(0, 2);
if(cheater && eqmatrix(View, lView) && !centering) {
View = Id;
View = Id; adjust_eye(View, cwt.at);
static ld cyc = 0;
cyc += 90._deg;
View = spin(cyc) * View;
if(GDIM == 2) View = spin(M_PI + vid.fixed_facing_dir * degree) * View;
if(GDIM == 3 && !prod) View = cspin90(0, 2) * View;
if(GDIM == 3 && !gproduct) View = cspin90(0, 2) * View;
}
}
else if(currentmap) {
centerover = currentmap->gamestart();
View = Id;
View = Id; adjust_eye(View, cwt.at);
}
cwtV = shiftless(View);
current_display->which_copy =
nonisotropic ? gpushxto0(tC0(view_inverse(View))) :
@ -2237,7 +2258,7 @@ EX void fullcenter() {
if(playerfound && false) centerpc(INF);
else {
bfs();
resetview();
resetview(); View = inverse(View);
drawthemap();
if(!centering) centerpc(INF);
centerover = cwt.at;
@ -2539,7 +2560,7 @@ void queuestraight(hyperpoint X, int style, color_t lc, color_t fc, PPR p) {
EX void draw_boundary(int w) {
if(w == 1) return;
if(nonisotropic || euclid || prod) return;
if(nonisotropic || euclid || gproduct) return;
#if CAP_VR
if(vrhr::active() && pmodel == mdHyperboloid) return;
#endif
@ -3039,7 +3060,7 @@ EX int cone_side(const shiftpoint H) {
/** get the current orientation of the view */
EX transmatrix& get_view_orientation() {
return prod ? NLP : View;
return gproduct ? NLP : View;
}
EX hookset<bool(const transmatrix&)> hooks_rotate_view;
@ -3050,7 +3071,7 @@ EX void rotate_view(transmatrix T) {
if(callhandlers(false, hooks_rotate_view, T)) return;
transmatrix& which = get_view_orientation();
which = T * which;
if(!prod && !rug::rugged) current_display->which_copy = T * current_display->which_copy;
if(!gproduct && !rug::rugged) current_display->which_copy = T * current_display->which_copy;
}
EX hyperpoint lie_exp(hyperpoint h) {
@ -3186,7 +3207,7 @@ EX transmatrix get_shift_view_of(const hyperpoint H, const transmatrix V) {
else if(!nisot::geodesic_movement) {
transmatrix IV = view_inverse(View);
transmatrix view_shift = eupush( tC0(IV) );
transmatrix rot = View * view_shift;
transmatrix rot = V * view_shift;
hyperpoint tH = lie_exp(inverse(rot) * H);
return rot * eupush(tH) * inverse(view_shift);
}
@ -3211,25 +3232,66 @@ EX void shift_view(hyperpoint H) {
wc = get_shift_view_of(H, wc);
}
void multiply_view(transmatrix T) {
/** works in embedded_plane and isotropic spaces */
void shift_view_isotropic(transmatrix T) {
if(embedded_plane) {
transmatrix IV = view_inverse(View);
transmatrix rot = View * map_relative_push(IV * C0);
View = T * View;
transmatrix IV1 = view_inverse(View);
transmatrix rot1 = View * map_relative_push(IV1 * C0);
View = rot * inverse(rot1) * View;
auto& wc = current_display->which_copy;
wc = rot * inverse(rot1) * T * wc;
return;
}
View = T * View;
auto& wc = current_display->which_copy;
wc = T * wc;
}
/* like rgpushxto0 but keeps the map orientation correct */
EX transmatrix map_relative_push(hyperpoint h) {
if(!embedded_plane) return rgpushxto0(h);
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);
}
return rgpushxto0(h);
}
EX void shift_view_to(shiftpoint H) {
if(!nonisotropic) multiply_view(gpushxto0(unshift(H)));
if(!nonisotropic)
shift_view_isotropic(gpushxto0(unshift(H)));
else shift_view(-inverse_exp(H));
}
EX void shift_view_towards(shiftpoint H, ld l) {
if(!nonisotropic && !prod)
multiply_view(rspintox(unshift(H)) * xpush(-l) * spintox(unshift(H)));
if(!nonisotropic && !gproduct)
shift_view_isotropic(rspintox(unshift(H)) * xpush(-l) * spintox(unshift(H)));
else if(nonisotropic && !nisot::geodesic_movement)
shift_view(tangent_length(unshift(H)-C0, -l));
else {
hyperpoint ie = inverse_exp(H, pNORMAL | pfNO_DISTANCE);
if(prod) ie = lp_apply(ie);
if(gproduct) ie = lp_apply(ie);
shift_view(tangent_length(ie, -l));
}
}
@ -3279,7 +3341,7 @@ EX void set_view(hyperpoint camera, hyperpoint forward, hyperpoint upward) {
if(det(rotator) < 0) rotator[0] = -rotator[0];
View = iso_inverse(rgpushxto0(camera));
if(prod)
if(gproduct)
NLP = rotator;
else
View = rotator * View;

View File

@ -49,7 +49,7 @@ struct portal_data {
#endif
hyperpoint portal_data::to_poco(hyperpoint h) const {
if(prod && kind == 1) {
if(mproduct && kind == 1) {
auto dec = product_decompose(h);
h = dec.second;
if(bt::in()) {
@ -67,7 +67,7 @@ hyperpoint portal_data::to_poco(hyperpoint h) const {
if(d<0) h[2] = -h[2], h[0] = -h[0];
return h;
}
else if(prod && kind == 0) {
else if(mproduct && kind == 0) {
h = T * h;
ld z = product_decompose(h).first;
h /= exp(z);
@ -105,7 +105,7 @@ hyperpoint portal_data::to_poco(hyperpoint h) const {
}
hyperpoint portal_data::from_poco(hyperpoint h) const {
if(prod && kind == 1) {
if(mproduct && kind == 1) {
ld xd = h[2];
if(d<0) xd = -xd, h[0] = -h[0];
#if CAP_BT
@ -118,7 +118,7 @@ hyperpoint portal_data::from_poco(hyperpoint h) const {
auto z = product_decompose(h).first;
return iT * h * exp(d+xd-z);
}
else if(prod && kind == 0) {
else if(mproduct && kind == 0) {
auto h0 = h;
h[0] = sin_auto(h0[2]);
h[1] = sin_auto(h0[0]) * cos_auto(h0[2]);
@ -156,7 +156,7 @@ EX portal_data make_portal(cellwalker cw, int spin) {
id.scale = 1;
id.T = Id;
auto gg = geometry;
if(prod && cw.spin >= cw.at->type - 2) {
if(mproduct && cw.spin >= cw.at->type - 2) {
id.kind = 1;
id.d = product_decompose(fac[0]).first;
id.v0 = C0 * exp(id.d);
@ -180,7 +180,7 @@ EX portal_data make_portal(cellwalker cw, int spin) {
id.T = gpushxto0(ctr);
}
}
else if(prod) {
else if(mproduct) {
id.kind = 0;
id.v0 = Hypc;
id.scale = cgi.plevel;
@ -518,7 +518,7 @@ EX void analyze_orthonormal(array<hyperpoint, 4> ds, ld sca) {
vector<ld> orths;
for(int i: {1,2,3}) {
ds[i] = T * ds[i];
if(prod) ds[i][2]--;
if(mproduct) ds[i][2]--;
}
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
@ -811,7 +811,7 @@ EX void show_portals() {
dialog::add_action_push(ray::configure);
}
if(prod && point_direction < mouseover2->type - 2) {
if(mproduct && point_direction < mouseover2->type - 2) {
ld r = get_ratio_edge(mouseover2, point_direction);
dialog::addSelItem(XLAT("height-to-width ratio"), fts(r), 'r');
dialog::add_action([] {
@ -1047,7 +1047,7 @@ EX void handle() {
z[2] = bt::minkowski_to_bt(fac.h0)[2];
return bt::bt_to_minkowski(z);
}
else if(prod && bt::in()) {
else if(mproduct && bt::in()) {
auto dec = product_decompose(at);
hyperpoint dep = PIU( deparabolic13(dec.second) );
hyperpoint h = product_decompose(fac.h0).second;

View File

@ -148,7 +148,7 @@ EX void createArrowTrapAt(cell *c, eLand land) {
EX eMonster emerald_monster() {
static eMonster emeraldmonsters[4] = { moHedge, moLancer, moFlailer, moMiner };
eMonster m = emeraldmonsters[hrand(4)];
if(m == moHedge && (S3 != 3 || (hybri && !prod)))
if(m == moHedge && (S3 != 3 || (mhybrid && !mproduct)))
m = moFlailer;
return m;
}
@ -399,7 +399,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(gs == 1)
c->wall = waPalace;
if(gs == 3) {
if(hybri) {
if(mhybrid) {
c->wall = pick(waClosedGate, waOpenGate);
if(c->wall == waClosedGate) toggleGates(c, waClosePlate, 1);
else toggleGates(c, waOpenPlate, 1);
@ -415,7 +415,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
c->wall = pick(waClosePlate, waOpenPlate);
if(gs == -6 && !reptilecheat)
c->wall = waTrapdoor;
if(hybri) {
if(mhybrid) {
int l = hybrid::get_where(c).second;
if(gs >= 3 && (l % 4) == 0) c->wall = waPalace;
if(gs < 3 && (l % 4) == 2) c->wall = waPalace;
@ -424,7 +424,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
else if(d == 8 && !sphere) {
if(prod && polarb50(c) && (hybrid::get_where(c).second & 3) == 2) {
if(mproduct && polarb50(c) && (hybrid::get_where(c).second & 3) == 2) {
c->wall = waPalace;
break;
}
@ -462,19 +462,19 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
if(GOLDBERG) ;
else {
int q = 0, s = 0;
if(!ishept(c)) for(int i=0; i<c->type - (hybri ? 2 : 0); i++)
if(!ishept(c)) for(int i=0; i<c->type - (mhybrid ? 2 : 0); i++)
if(cdist50(c->move(i)) == 3 && polarb50(c->move(i)) && !ishept(c->move(i)))
q++, s += i;
if(q == 1 && c->move(s)->land == laPalace) {
switch(princess::generating ? 0 : hrand(2)) {
case 0:
c->wall = waClosedGate;
if(hybri) toggleGates(c, waClosePlate, 1);
if(mhybrid) toggleGates(c, waClosePlate, 1);
c->move(s)->wall = waClosedGate;
break;
case 1:
c->wall = waOpenGate;
if(hybri) toggleGates(c, waOpenPlate, 1);
if(mhybrid) toggleGates(c, waOpenPlate, 1);
c->move(s)->wall = waOpenGate;
break;
}
@ -798,7 +798,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
else if(v == 25 || v == 59 || v == 27 || v == 57)
c->wall = waVineHalfB;
else c->wall = waNone;
if(hybri && cellHalfvine(c)) c->wall = waNone;
if(mhybrid && cellHalfvine(c)) c->wall = waNone;
if(NONSTDVAR && cellHalfvine(c)) {
c->wall = waNone;
forCellCM(c2, c) if(emeraldval(c2) == (v^1))
@ -1392,7 +1392,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
while(i) { if(i&1) b++; i>>=1; }
if(ctof(c) && (b&1) && hrand(100) < 20) c->wall = (z&2) ? waCharged : waGrounded;
}
else if(hybri) {
else if(mhybrid) {
cell *c1 = hybrid::get_where(c).first;
if(among(c1->wall, waCharged, waGrounded))
c->wall = c1->wall;
@ -2834,7 +2834,7 @@ EX void set_land_for_geometry(cell *c) {
#if MAXMDIM == 4
else if(euc::in(3)) euc::set_land(c);
#endif
else if(hybri) setLandHybrid(c);
else if(mhybrid) setLandHybrid(c);
else if(sphere || (euclid && closed_or_bounded)) setLandSphere(c);
else if(euclid) setLandEuclid(c);
else if(quotient) { setland(c, specialland); setLandQuotient(c); }
@ -2849,6 +2849,7 @@ EX void setdist(cell *c, int d, cell *from) {
if(c == &out_of_bounds) return;
if(fake::in()) return FPIU(setdist(c, d, from));
if(embedded_plane) return IPF(setdist(c, d, from));
if(d < -64) d = -64; /* otherwise it will underflow */
if(c->mpdist <= d) return;
@ -2870,7 +2871,7 @@ EX void setdist(cell *c, int d, cell *from) {
if(d <= 10 - getDistLimit()) lastexplore = shmup::on ? shmup::curtime : turncount;
if(hybri) {
if(mhybrid) {
auto wc = hybrid::get_where(c).first;
auto wf = from ? hybrid::get_where(from).first : NULL;
if(c->land && !wc->land) wc->land = c->land;
@ -2888,7 +2889,7 @@ EX void setdist(cell *c, int d, cell *from) {
if(d >= BARLEV) {
#if CAP_BT
if(bt::in() && WDIM == 3 && !c->land && !sn::in() && !hybri) {
if(bt::in() && WDIM == 3 && !c->land && !sn::in() && !mhybrid) {
ld z = vid.binary_width;
cell *cseek = c;
int step = 0;

View File

@ -757,7 +757,7 @@ EX land_validity_t& land_validity(eLand l) {
if(walls_not_implemented() && isCrossroads(l))
return no_walls;
if(hybri || hybrid::pmap) {
if(mhybrid || hybrid::pmap) {
if(among(l, laPrincessQuest, laPrairie, laMirrorOld, laMirror, laDual, laWarpCoast, laKraken, laBrownian, laWhirlpool, laWestWall, laHive, laClearing, laWhirlwind, laBlizzard, laBull, laTerracotta, laCrossroads5,
laEndorian, laDungeon, laMountain))
return lv::not_implemented;
@ -765,7 +765,7 @@ EX land_validity_t& land_validity(eLand l) {
return lv::bad_graphics;
if((hybrid::actual_geometry == gRotSpace || geometry == gRotSpace) && l == laDryForest)
return lv::hedgehogs;
if(hybri && hybrid::underlying && hybrid::underlying_cgip) {
if(mhybrid && hybrid::underlying && hybrid::underlying_cgip) {
return *PIU(&land_validity(l));
}
}

View File

@ -518,7 +518,7 @@ EX namespace mapstream {
f.write(asonov::period_z);
}
#endif
if(prod) {
if(mproduct) {
f.write(hybrid::csteps);
f.write(product::cspin);
f.write(product::cmirror);
@ -527,7 +527,7 @@ EX namespace mapstream {
if(rotspace) {
f.write(hybrid::csteps);
}
if(hybri) {
if(mhybrid) {
hybrid::in_underlying_geometry([&] { save_geometry(f); });
}
if(fake::in()) {
@ -661,7 +661,7 @@ EX namespace mapstream {
if(geometry == gRotSpace && vernum >= 0xA833) {
f.read(hybrid::csteps);
}
if(hybri && vernum >= 0xA80C) {
if(mhybrid && vernum >= 0xA80C) {
auto g = geometry;
load_geometry(f);
set_geometry(g);
@ -688,7 +688,7 @@ EX namespace mapstream {
EX hookset<void(hstream&, int)> hooks_loadmap;
EX cell *save_start() {
return (closed_manifold || euclid || prod || arcm::in() || sol || INVERSE) ? currentmap->gamestart() : cwt.at->master->c7;
return (closed_manifold || euclid || mproduct || arcm::in() || sol || INVERSE) ? currentmap->gamestart() : cwt.at->master->c7;
}
#if CAP_EDIT
@ -926,7 +926,7 @@ EX namespace mapstream {
for(int k=0; k<i; k++) f.read(kills[k]);
}
int sub = hybri ? 2 : 0;
int sub = mhybrid ? 2 : 0;
while(true) {
cell *c;
int rspin;
@ -947,7 +947,7 @@ EX namespace mapstream {
// spinval becomes xspinval
rspin = gmod(c2->c.spin(dir) - f.read_char(), c->type - sub);
if(GDIM == 3 && rspin && !hybri) {
if(GDIM == 3 && rspin && !mhybrid) {
println(hlog, "rspin in 3D");
throw hstream_exception();
}

View File

@ -135,7 +135,7 @@ EX namespace models {
#endif
EX transmatrix rotmatrix() {
if(GDIM == 2 || prod) return spin(rotation * degree);
if(GDIM == 2 || gproduct) return spin(rotation * degree);
return spin(rotation_xy2 * degree) * cspin(0, 2, -rotation_xz * degree) * spin(rotation * degree);
}
@ -190,7 +190,7 @@ EX namespace models {
EX bool model_available(eModel pm) {
if(mdinf[pm].flags & mf::technical) return false;
if(prod) {
if(gproduct) {
if(pm == mdPerspective) return true;
if(among(pm, mdBall, mdHemisphere)) return false;
return PIU(model_available(pm));
@ -205,7 +205,7 @@ EX namespace models {
if(pm == mdLiePerspective && sphere) return false;
if(pm == mdLieOrthogonal && sphere) return false;
if(GDIM == 2 && pm == mdEquivolume) return false;
if(pm == mdThreePoint && !(GDIM == 3 && !nonisotropic && !prod)) return false;
if(pm == mdThreePoint && !(GDIM == 3 && !nonisotropic && !gproduct)) return false;
if(GDIM == 3 && among(pm, mdBall, mdHyperboloid, mdFormula, mdPolygonal, mdRotatedHyperboles, mdSpiral, mdHemisphere)) return false;
if(pm == mdCentralInversion && !euclid) return false;
if(pm == mdPoorMan) return hyperbolic;
@ -247,7 +247,7 @@ EX namespace models {
}
EX bool product_model(eModel m) {
if(!prod) return false;
if(!gproduct) return false;
if(among(m, mdPerspective, mdHyperboloid, mdEquidistant, mdThreePoint)) return false;
return true;
}
@ -256,8 +256,8 @@ EX namespace models {
EX string get_model_name(eModel m) {
if(m == mdDisk && GDIM == 3 && (hyperbolic || nonisotropic)) return XLAT("ball model/Gans");
if(m == mdPerspective && prod) return XLAT("native perspective");
if(prod) return PIU(get_model_name(m));
if(m == mdPerspective && gproduct) return XLAT("native perspective");
if(gproduct) return PIU(get_model_name(m));
if(nonisotropic) {
if(m == mdHorocyclic && !sol) return XLAT("simple model: projection");
if(m == mdPerspective) return XLAT("simple model: perspective");

View File

@ -796,7 +796,7 @@ EX void generateSnake(cell *c, int i, int snakecolor) {
c2 = c3;
c2->monst = moHexSnakeTail; c2->hitpoints = snakecolor;
int t = c2->type;
if(hybri) t -= 2;
if(mhybrid) t -= 2;
i = (j + (t%4 == 0 ? t/2 : (len%2 ? 2 : t - 2))) % t;
createMov(c2, i);
if(!inpair(c2->move(i), cpair)) {

View File

@ -64,7 +64,7 @@ void gamedata_all(gamedata& gd) {
if(gd.mode != 0) cgip->use_count--;
gd.store(hybrid::underlying);
gd.store(hybrid::csteps);
if(hybri && hybrid::underlying_cgip) {
if(mhybrid && hybrid::underlying_cgip) {
if(gd.mode == 0) hybrid::underlying_cgip->use_count++;
if(gd.mode != 0) hybrid::underlying_cgip->use_count--;
}

View File

@ -11,7 +11,7 @@ namespace hr {
EX namespace nisot {
#if HDR
inline bool local_perspective_used() { return nonisotropic || prod; }
inline bool local_perspective_used() { return nonisotropic || gproduct; }
#endif
EX bool geodesic_movement = true;
@ -1049,16 +1049,19 @@ EX void create_faces() {
EX }
EX bool in_s2xe() { return prod && hybrid::under_class() == gcSphere; }
EX bool in_h2xe() { return prod && hybrid::under_class() == gcHyperbolic; }
EX bool in_e2xe() { return prod && hybrid::under_class() == gcEuclid; }
EX bool in_s2xe() { return gproduct && hybrid::under_class() == gcSphere; }
EX bool in_h2xe() { return gproduct && hybrid::under_class() == gcHyperbolic; }
EX bool in_e2xe() { return gproduct && hybrid::under_class() == gcEuclid; }
EX namespace hybrid {
EX eGeometry underlying;
EX geometry_information *underlying_cgip;
EX eGeometryClass under_class() { return ginf[hybrid::underlying].cclass; }
EX eGeometryClass under_class() {
if(embedded_plane) return geom3::ginf_backup[geometry].cclass;
return ginf[hybrid::underlying].cclass;
}
EX int csteps;
@ -1106,7 +1109,7 @@ EX namespace hybrid {
}
EX void reconfigure() {
if(!hybri) return;
if(!mhybrid) return;
stop_game();
auto g = geometry;
geometry = underlying;
@ -1364,7 +1367,13 @@ EX namespace hybrid {
#if HDR
template<class T> auto in_underlying_geometry(const T& f) -> decltype(f()) {
if(!hybri) return f();
if(!mhybrid && !gproduct) return f();
if(embedded_plane) {
geom3::light_flip(true);
finalizer ff([] { geom3::light_flip(false); });
return f();
}
if(geom3::flipped) throw hr_exception("called in_underlying_geometry in flipped");
pcgip = cgip;
dynamicval<eGeometry> gag(actual_geometry, geometry);
dynamicval<eGeometry> g(geometry, underlying);
@ -1381,7 +1390,8 @@ EX namespace hybrid {
/** like in_underlying_geometry but does not return */
EX void switch_to_underlying() {
if(!hybri) return;
if(!mhybrid && !gproduct) return;
if(embedded_plane) throw hr_exception("switch_to_underlying in embedded_plane");
auto m = hmap();
pmap = m;
actual_geometry = geometry;
@ -1410,7 +1420,7 @@ EX namespace hybrid {
hyperpoint h = orthogonal_move(get_corner_position(c, i+next), zz);
return h;
}
if(prod) {
if(gproduct) {
dynamicval<eGeometry> g(geometry, hybrid::underlying);
dynamicval<geometry_information*> gc(cgip, hybrid::underlying_cgip);
dynamicval<hrmap*> gm(currentmap, ((hrmap_hybrid*)currentmap)->underlying_map);
@ -1449,7 +1459,7 @@ EX namespace hybrid {
});
EX vector<pair<int, cell*>> gen_sample_list() {
if(!hybri && WDIM != 2 && PURE)
if(!mhybrid && WDIM != 2 && PURE)
return {make_pair(0, centerover), make_pair(centerover->type, nullptr)};
vector<pair<int, cell*>> result;
for(auto& v: cgi.walloffsets) if(v.first >= 0) result.push_back(v);
@ -1668,7 +1678,7 @@ EX namespace product {
}
EX bool validate_spin() {
if(prod) return hybrid::in_underlying_geometry(validate_spin);
if(mproduct) return hybrid::in_underlying_geometry(validate_spin);
if(kite::in()) return false;
if(!quotient && !arcm::in()) return true;
map<cell*, cellwalker> cws;
@ -2232,7 +2242,7 @@ EX namespace rots {
if(det(T) < 0) T = centralsym * T;
if(prod) d = 0;
if(mproduct) d = 0;
hyperpoint h = inverse(View * spin(master_to_c7_angle()) * T) * C0;
@ -2241,7 +2251,7 @@ EX namespace rots {
ld alpha = atan2(ortho_inverse(NLP) * point3(1, 0, 0));
bool inprod = prod;
bool inprod = mproduct;
transmatrix pView = View;
if(inprod) {
pView = spin(alpha) * View;
@ -2857,10 +2867,10 @@ EX namespace nisot {
#if CAP_SOLV
if(sn::in()) return new sn::hrmap_solnih;
#endif
if(prod) return new product::hrmap_product;
if(mproduct) return new product::hrmap_product;
#if MAXMDIM >= 4
if(nil) return new nilv::hrmap_nil;
if(hybri) return new rots::hrmap_rotation_space;
if(mhybrid) return new rots::hrmap_rotation_space;
#endif
return NULL;
}
@ -2963,7 +2973,7 @@ EX namespace nisot {
#endif
else if(argis("-prodperiod")) {
PHASEFROM(2);
if(prod) stop_game();
if(mproduct) stop_game();
shift(); hybrid::csteps = argi();
hybrid::reconfigure();
return 0;
@ -2999,7 +3009,7 @@ EX namespace nisot {
}
else if(argis("-prodturn")) {
PHASEFROM(2);
if(prod) stop_game();
if(mproduct) stop_game();
shift(); product::cspin = argi();
shift(); product::cmirror = argi();
return 0;

View File

@ -28,7 +28,7 @@ EX int ctof(cell *c) {
if(IRREGULAR) return irr::ctof(c);
#endif
if(PURE) return 1;
// if(euclid) return 0;
// if(meuclid) return 0;
if(!c) return 1;
if(bt::in()) return c->type == 7;
return ishept(c) ? 1 : 0;
@ -68,7 +68,7 @@ EX bool ishept(cell *c) {
if(cgflags & qPORTALSPACE) return 0;
// EUCLIDEAN
if(euc::in() && PURE) return eupattern(c) == 0;
else if(hybri) { cell *c1 = hybrid::get_where(c).first; return c1 == c1->master->c7; }
else if(mhybrid) { cell *c1 = hybrid::get_where(c).first; return c1 == c1->master->c7; }
else return c == c->master->c7;
}
@ -131,8 +131,8 @@ EX int chessvalue(cell *c) {
EX int emeraldval(heptagon *h) { return h->emeraldval >> 3; }
EX int emeraldval(cell *c) {
if(euclid) return eupattern(c);
if(sphere) return 0;
if(meuclid) return eupattern(c);
if(msphere) return 0;
if(ctof(c))
return emeraldval(c->master);
else {
@ -166,8 +166,8 @@ int eufifty(cell *c) {
}
int fiftyval(cell *c) {
if(euclid) return eufifty(c) * 32;
if(sphere || S7>7 || S6>6) return 0;
if(meuclid) return eufifty(c) * 32;
if(msphere || S7>7 || S6>6) return 0;
if(ctof(c))
return c->master->fiftyval;
else {
@ -180,13 +180,13 @@ int fiftyval(cell *c) {
}
EX int cdist50(cell *c) {
if(euclid && S3 == 4) {
if(meuclid && S3 == 4) {
auto co = euc2_coordinates(c);
int x = co.first, y = co.second;
return abs(szgmod(x, 5)) + abs(zgmod(y, 5));
}
if(sphere || S7>7 || S6>6) return 0;
if(euclid) {
if(msphere || S7>7 || S6>6) return 0;
if(meuclid) {
if(c->land == laWildWest)
return "0123333332112332223322233211233333322"[eufifty(c)] - '0';
else return "012333321112322232222321123"[eufifty(c)] - '0';
@ -201,7 +201,7 @@ EX int cdist50(cell *c) {
}
int land50(cell *c) {
if(sphere || euclid) return 0;
if(msphere || meuclid) return 0;
else if(ctof(c)) return land50(fiftyval(c));
else {
auto ar = gp::get_masters(c);
@ -212,7 +212,7 @@ int land50(cell *c) {
}
EX bool polara50(cell *c) {
if(sphere || euclid || S7>7 || S6>6) return false;
if(msphere || meuclid || S7>7 || S6>6) return false;
else if(NONSTDVAR) return polara50(fiftyval(c->master->c7));
else if(ctof(c)) return polara50(fiftyval(c));
else {
@ -224,8 +224,8 @@ EX bool polara50(cell *c) {
}
EX bool polarb50(cell *c) {
if(euclid) return true;
if(sphere || euclid || S7>7 || S6>6) return true;
if(meuclid) return true;
if(msphere || meuclid || S7>7 || S6>6) return true;
else if(NONSTDVAR) return polarb50(fiftyval(c->master->c7));
else if(ctof(c)) return polarb50(fiftyval(c));
else {
@ -257,9 +257,9 @@ EX int fiftyval049(heptagon *h) {
}
EX int fiftyval049(cell *c) {
if(euclid) return fiftyval(c) / 32;
if(meuclid) return fiftyval(c) / 32;
else if(ctof(c)) return fiftyval049(c->master);
else if(sphere) return 0;
else if(msphere) return 0;
else {
int a[3], qa=0;
bool pa = polara50(c);
@ -332,7 +332,7 @@ int dir_bitrunc457(cell *c) {
int val46(cell *c);
EX int zebra40(cell *c) {
if(euclid) return pattern_threecolor(c);
if(meuclid) return pattern_threecolor(c);
else if(IRREGULAR) return c->master->zebraval/10;
else if(INVERSE) {
cell *c1 = gp::get_mapped(c);
@ -367,7 +367,7 @@ EX int zebra40(cell *c) {
if(tot == 4+5+6+7) return 17+cod;
return 24;
}
else if(sphere) return 0;
else if(msphere) return 0;
else if(S3 == 4 && S7 == 6) {
return 8 + ((c->master->zebraval / 10 + c->c.spin(0))%2) * 2;
}
@ -394,9 +394,9 @@ EX int zebra40(cell *c) {
}
EX int zebra3(cell *c) {
if(euclid) return 0;
if(meuclid) return 0;
else if(ctof(c)) return (c->master->zebraval/10)/4;
else if(euclid || sphere || S7>7 || S6>6) return 0;
else if(meuclid || msphere || S7>7 || S6>6) return 0;
else {
int ii[3];
auto ar = gp::get_masters(c);
@ -424,11 +424,11 @@ EX int fieldval_uniq(cell *c) {
if(experimental) return 0;
if(reg3::in() && !PURE) return 0;
else if(arb::in()) return arb::id_of(c->master);
else if(hybri) {
else if(mhybrid) {
auto c1 = hybrid::get_where(c).first;
return PIU ( fieldval_uniq(c1) );
}
else if(sphere) {
else if(msphere) {
if(arcm::in()) return c->master->fiftyval;
#if CAP_IRR
else if(IRREGULAR) return irr::cellindex[c];
@ -463,11 +463,11 @@ EX int fieldval_uniq(cell *c) {
}
EX int fieldval_uniq_rand(cell *c, int randval) {
if(hybri) {
if(mhybrid) {
auto c1 = hybrid::get_where(c).first;
return PIU ( fieldval_uniq_rand(c1, randval) );
}
if(sphere || euclid || NONSTDVAR)
if(msphere || meuclid || NONSTDVAR)
// we do not care in these cases
return fieldval_uniq(c);
if(ctof(c)) return currfp.gmul(c->master->fieldval, randval)/7;
@ -539,9 +539,9 @@ EX int getHemisphere(heptagon *h, int which) {
}
EX int getHemisphere(cell *c, int which) {
if(euclid && quotient) return 0;
if(hybri) { auto d = hybrid::get_where(c); return PIU(getHemisphere(d.first, which)); }
if(WDIM == 3 && !hybri) {
if(meuclid && quotient) return 0;
if(mhybrid) { auto d = hybrid::get_where(c); return PIU(getHemisphere(d.first, which)); }
if(WDIM == 3 && !mhybrid) {
hyperpoint p = tC0(calc_relative_matrix(c, currentmap->gamestart(), C0));
return int(p[which] * 6 + 10.5) - 10;
}
@ -991,9 +991,9 @@ EX namespace patterns {
if(subpattern_flags & SPF_FULLSYM)
si.symmetries = 1;
}
if(sphere && BITRUNCATED && !(S7 == 3))
if(msphere && BITRUNCATED && !(S7 == 3))
si.symmetries = ctof(c) ? 1 : 2;
if(sphere && (sub & SPF_EXTRASYM)) {
if(msphere && (sub & SPF_EXTRASYM)) {
si.symmetries = ctof(c) ? 1 : 2;
}
if(a38)
@ -1154,7 +1154,7 @@ EX namespace patterns {
else if(pat == PAT_EMERALD && (stdhyperbolic || a38)) {
si.id = emeraldval(c); // 44 to 99
if(!euclid) {
if(!meuclid) {
int tcdir = 0, tbest = (si.id&3);
for(int i=0; i<c->type; i++) {
cell *c2 = c->move(i);
@ -1208,7 +1208,7 @@ EX namespace patterns {
si.id -= ((si.id/4-1) % 7) * 4;
}
else if(pat == PAT_PALACE && euclid) {
else if(pat == PAT_PALACE && meuclid) {
si.id = fiftyval049(c);
si.symmetries = 6;
}
@ -1225,7 +1225,7 @@ EX namespace patterns {
#if CAP_FIELD
else if(pat == PAT_FIELD) {
if(euclid)
if(meuclid)
// use the torus ID
si.id = fieldpattern::fieldval_uniq(c);
else if(PURE && standard_tiling())
@ -1238,7 +1238,7 @@ EX namespace patterns {
}
#endif
else if(sphere && pat == PAT_SIBLING) {
else if(msphere && pat == PAT_SIBLING) {
val_all(c, si, sub, pat);
}
@ -1252,7 +1252,7 @@ EX namespace patterns {
else val_threecolors(c, si, sub);
}
else if(pat == PAT_COLORING && (S7 == 4 || euclid || (a38 && gp_threecolor() == 1) || arcm::in())) {
else if(pat == PAT_COLORING && (S7 == 4 || meuclid || (a38 && gp_threecolor() == 1) || arcm::in())) {
val_threecolors(c, si, sub);
}
@ -1403,7 +1403,7 @@ EX int pattern_threecolor(cell *c) {
int i = si.id;
return i >> 2;
}
if(euclid) {
if(meuclid) {
if(a4 && PURE) return eupattern4(c);
if(euc::in(2,6) && !BITRUNCATED) return eupattern(c) % 3;
return c == c->master->c7 ? 0 : (c->c.spin(0)&1) ? 1 : 2;
@ -1471,7 +1471,7 @@ EX bool pseudohept(cell *c) {
#if CAP_IRR
if(IRREGULAR) return irr::pseudohept(c);
#endif
if(hybri) { auto d = hybrid::get_where(c); return ((!prod) || (d.second & 1)) && PIU(pseudohept(d.first)); }
if(mhybrid) { auto d = hybrid::get_where(c); return ((!mproduct) || (d.second & 1)) && PIU(pseudohept(d.first)); }
#if CAP_BT
if(nil) return c->master->zebraval & c->master->emeraldval & c->master->fieldval & 1;
if(sol) return (c->master->emeraldval % 3 == 2) && (c->master->zebraval % 3 == 2) && (c->master->distance % 2);
@ -1506,7 +1506,7 @@ EX bool pseudohept(cell *c) {
EX bool kraken_pseudohept(cell *c) {
if(0);
#if CAP_GP
else if(!euclid && S3 == 4 && GOLDBERG && (gp::param.first % 2 || gp::param.second % 2 || S7 % 2))
else if(!meuclid && S3 == 4 && GOLDBERG && (gp::param.first % 2 || gp::param.second % 2 || S7 % 2))
return ishept(c);
#endif
#if CAP_IRR
@ -1521,7 +1521,7 @@ EX bool kraken_pseudohept(cell *c) {
else if(arcm::in() && DUAL)
return false;
#endif
else if(!euclid && S3 == 3 && !(S7&1) && gp_threecolor() == 1)
else if(!meuclid && S3 == 3 && !(S7&1) && gp_threecolor() == 1)
return ishept(c);
else
return pseudohept(c);
@ -1600,7 +1600,7 @@ EX namespace patterns {
EX bool innerwalls;
int sevenval(cell *c) {
if(!euclid) return 0;
if(!meuclid) return 0;
auto p = euc2_coordinates(c);
return gmod(p.first - p.second * 2, 7);
}
@ -1706,7 +1706,7 @@ EX namespace patterns {
ep.extra_params["mz"] = c->master->zebraval;
}
if(sphere) {
if(msphere) {
ep.extra_params["h0"] = getHemisphere(c, 0);
ep.extra_params["h1"] = getHemisphere(c, 1);
ep.extra_params["h2"] = getHemisphere(c, 2);
@ -1739,7 +1739,7 @@ EX namespace patterns {
ep.extra_params["ny"] = szgmod(co[1], nilv::nilperiod[1]);
ep.extra_params["nz"] = szgmod(co[2], nilv::nilperiod[2]);
}
if(hybri)
if(mhybrid)
ep.extra_params["level"] = hybrid::get_where(c).second;
if(geometry_supports_cdata()) {
@ -2031,7 +2031,7 @@ EX namespace patterns {
dialog::addSelItem(XLAT("random black-and-white"), "current", 'w');
#if CAP_FIELD
if(!sphere) {
if(!msphere) {
dialog::addSelItem(XLAT("field pattern C"), "field", 'C');
dialog::addSelItem(XLAT("field pattern D"), "field", 'D');
dialog::addSelItem(XLAT("field pattern N"), "field", 'N');
@ -2218,7 +2218,7 @@ EX namespace patterns {
else if(a38)
dialog::addBoolItem(XLAT("broken Emerald Pattern"), (whichPattern == PAT_EMERALD), PAT_EMERALD);
if(stdhyperbolic || euclid)
if(stdhyperbolic || meuclid)
dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == PAT_PALACE), PAT_PALACE);
if(geosupport_chessboard())
@ -2230,9 +2230,9 @@ EX namespace patterns {
if(sphere_narcm)
dialog::addBoolItem(XLAT("siblings"), (whichPattern == PAT_SIBLING), PAT_SIBLING);
if(euclid)
if(meuclid)
dialog::addBoolItem(XLAT("torus"), (whichPattern == PAT_FIELD), PAT_FIELD);
else if(sphere)
else if(msphere)
dialog::addBoolItem(XLAT("single cells"), (whichPattern == PAT_FIELD), PAT_FIELD);
else
dialog::addBoolItem(XLAT("field pattern"), (whichPattern == PAT_FIELD), PAT_FIELD);
@ -2245,17 +2245,17 @@ EX namespace patterns {
(whichPattern == PAT_EMERALD && (stdhyperbolic || a38)) ||
(whichPattern == PAT_PALACE && stdhyperbolic) ||
(whichPattern == PAT_ZEBRA && stdhyperbolic) ||
(whichPattern == PAT_SIBLING && sphere) ||
(whichPattern == PAT_SIBLING && msphere) ||
(whichPattern == PAT_ZEBRA && a457)) {
dialog::addBoolItem(XLAT("rotational symmetry"), subpattern_flags & SPF_ROT, '0');
}
if((euclid && whichPattern == PAT_COLORING) ||
if((meuclid && whichPattern == PAT_COLORING) ||
(a38 && whichPattern == PAT_COLORING) ||
(a4 && !BITRUNCATED && whichPattern == PAT_COLORING && !a46))
dialog::addBoolItem(XLAT("edit all three colors"), subpattern_flags & SPF_ROT, '0');
if(euclid && whichPattern == PAT_COLORING)
if(meuclid && whichPattern == PAT_COLORING)
dialog::addBoolItem(XLAT("rotate the color groups"), subpattern_flags & SPF_CHANGEROT, '4');
if(a46 && whichPattern == PAT_COLORING)
@ -2275,7 +2275,7 @@ EX namespace patterns {
dialog::addBoolItem(XLAT("symmetry 0-2"), subpattern_flags & SPF_SYM02, '2');
dialog::addBoolItem(XLAT("symmetry 0-3"), subpattern_flags & SPF_SYM03, '3');
}
if(euclid && among(whichPattern, PAT_COLORING, PAT_TYPES) && !arcm::in())
if(meuclid && among(whichPattern, PAT_COLORING, PAT_TYPES) && !arcm::in())
dialog::addBoolItem(XLAT("extra symmetries"), subpattern_flags & SPF_EXTRASYM, '=');
#if CAP_ARCM
@ -2288,7 +2288,7 @@ EX namespace patterns {
dialog::addBoolItem(XLAT("extra symmetries"), subpattern_flags & SPF_EXTRASYM, '=');
}
if(euclid && among(whichPattern, PAT_COLORING, 0))
if(meuclid && among(whichPattern, PAT_COLORING, 0))
dialog::addBoolItem(XLAT("full symmetry"), subpattern_flags & SPF_FULLSYM, '!');
if(a38 && PURE && whichPattern == PAT_TYPES) {
@ -2517,8 +2517,8 @@ EX namespace patterns {
}
dialog::addBoolItem(s, geometry == g.geo && variation == g.var && whichPattern == g.whichPattern && subpattern_flags == g.subpattern_flags, 'a'+j);
}
bool have_goldberg = (S3 == 3 && among(cgroup, cpFootball, cpThree) && !euclid);
bool have_variations = (among(cgroup, cpSingle, cpSingleSym) && !euclid);
bool have_goldberg = (S3 == 3 && among(cgroup, cpFootball, cpThree) && !meuclid);
bool have_variations = (among(cgroup, cpSingle, cpSingleSym) && !meuclid);
if(!(S7&1) && BITRUNCATED) have_goldberg = false; // always start from pure
if(have_goldberg) {
dialog::addBoolItem(XLAT("Goldberg"), GOLDBERG, 'G');
@ -2715,7 +2715,7 @@ EX namespace linepatterns {
linepattern patBigTriangles("big triangular grid", 0x00606000, always_available,
ALLCELLS(
if(is_master(c) && !euclid) for(int i=0; i<S7; i++)
if(is_master(c) && !meuclid) for(int i=0; i<S7; i++)
if(c->master->move(i) && c->master->move(i) < c->master) {
gridlinef(V, C0, xspinpush0(-TAU*i/S7 - master_to_c7_angle(), cgi.tessf), col, 2 + vid.linequality);
}
@ -2724,7 +2724,7 @@ EX namespace linepatterns {
linepattern patBigRings("big triangles: rings", 0x00606000, [] { return standard_tiling() && S3 == 3 && mod_allowed(); },
ALLCELLS(
if(is_master(c) && !euclid) for(int i=0; i<S7; i++)
if(is_master(c) && !meuclid) for(int i=0; i<S7; i++)
if(c->master->move(i) && way(c->master, i) && c->master->move(i)->dm4 == c->master->dm4)
gridlinef(V, C0, xspinpush0(-TAU*i/S7 - master_to_c7_angle(), cgi.tessf), col, 2 + vid.linequality);
)
@ -2790,7 +2790,7 @@ EX namespace linepatterns {
if(fv2/4 == 4 || fv2/4 == 6 || fv2/4 == 5 || fv2/4 == 10) fv2 ^= 2;
if((fv1&1) == (fv2&1)) continue;
double x = cgi.hexhexdist / 2; // sphere?.3651:euclid?.2611:.2849;
double x = cgi.hexhexdist / 2; // msphere?.3651:meuclid?.2611:.2849;
gridlinef(V, ddspin(c,i,-M_PI/S3) * xpush0(x),
ddspin(c,i,M_PI/S3) * xpush0(x),

View File

@ -111,7 +111,7 @@ void geometry_information::chasmifyPoly(double fol, double fol2, int k) {
int zf = int(x);
if(zf == isize(points)-1) zf--;
x -= zf;
hpcpush(orthogonal_move(normalize(points[zf] + (points[zf+1] - points[zf]) * x), fol + (fol2-fol) * y));
hpcpush(orthogonal_move(normalize_flat(points[zf] + (points[zf+1] - points[zf]) * x), fol + (fol2-fol) * y));
};
texture_order([&] (ld x, ld y) { at((1-x+y)/2, (1-x-y)/2); });
texture_order([&] (ld x, ld y) { at((1-x-y)/2, (1+x-y)/2); });
@ -881,7 +881,7 @@ hyperpoint ray_kleinize(hyperpoint h, int id, ld pz) {
return deparabolic13(final_coords(h));
}
#endif
if(prod) {
if(gproduct) {
if(bt::in()) return point3(h[0], h[1], pz);
return point3(h[0]/h[2], h[1]/h[2], pz);
}
@ -912,7 +912,7 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
vector<ld> altitudes;
altitudes.resize(n);
if(prod) {
if(gproduct) {
for(int i=0; i<n; i++) {
auto d = product_decompose(vertices[i]);
altitudes[i] = d.first;
@ -926,11 +926,11 @@ 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(prod && !bt::in()) center = normalize_flat(center);
if(mproduct && !bt::in()) center = normalize_flat(center);
else center /= w;
ld center_altitude = 0;
if(prod) for(int i=0; i<n; i++) center_altitude += altitudes[i] * weights[i] / w;
if(mproduct) for(int i=0; i<n; i++) center_altitude += altitudes[i] * weights[i] / w;
auto ocenter = center;
@ -956,7 +956,7 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
hyperpoint h = center + v1 * x + v2 * y;
if(nil && (x || y))
h = nilv::on_geodesic(center, nilv::on_geodesic(v1+center, v2+center, y / (x+y)), x + y);
if(prod) {
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);
hpcpush(h); return;
@ -971,7 +971,7 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
for(int a=0; a<n; a++) for(int y=0; y<STEP; y++) {
if(triangles && (a%3 != 1)) continue;
hyperpoint h = (vertices[a] * (STEP-y) + vertices[(a+1)%n] * y)/STEP;
if(prod) {
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);
hpcpush(h);
@ -1011,9 +1011,9 @@ void geometry_information::reserve_wall3d(int i) {
void geometry_information::create_wall3d() {
if(WDIM == 2) return;
reserve_wall3d(kite::in() ? 22 : hybri ? 0 : S7);
reserve_wall3d(kite::in() ? 22 : mhybrid ? 0 : S7);
if(hybri) {
if(mhybrid) {
walloffsets.clear();
}
@ -1129,7 +1129,7 @@ void geometry_information::prepare_shapes() {
allshapes.clear();
DEBBI(DF_POLY, ("buildpolys"));
if(WDIM == 3 && !hybri) {
if(WDIM == 3 && !mhybrid) {
if(sphere) SD3 = 3, SD7 = 5;
else SD3 = SD7 = 4;
}

View File

@ -134,7 +134,7 @@ void fix_cave(cell *c) {
}
bool keep_to_crossroads() {
return specialland == laCrossroads && !(nonisotropic || hybri);
return specialland == laCrossroads && !(nonisotropic || mhybrid);
}
bool bad(cell *c2, cell *c) {
@ -414,7 +414,7 @@ EX void generate_track() {
}
try {
if(closed_or_bounded && !prod && !(cgflags & qHUGE_BOUNDED)) {
if(closed_or_bounded && !mproduct && !(cgflags & qHUGE_BOUNDED)) {
bounded_track = true;
make_bounded_track(s);
}
@ -701,7 +701,7 @@ bool inrec = false;
EX ld race_angle = 90;
EX bool force_standard_centering() {
return nonisotropic || hybri || quotient || closed_or_bounded;
return nonisotropic || mhybrid || quotient || closed_or_bounded;
}
EX bool use_standard_centering() {

View File

@ -15,7 +15,7 @@ pair<bool, hyperpoint> makeradar(shiftpoint h) {
if(r < 1) h1 = h1 * (atanh(r) / r);
else return {false, h1};
}
else if(prod) h1 = product::inverse_exp(unshift(h));
else if(mproduct) h1 = product::inverse_exp(unshift(h));
else if(sl2) h1 = slr::get_inverse_exp(h);
else h1 = unshift(h);
@ -84,7 +84,7 @@ EX void draw_radar(bool cornermode) {
bool d3 = WDIM == 3;
bool hyp = hyperbolic;
bool sph = sphere;
bool scompass = nonisotropic && !hybri;
bool scompass = nonisotropic && !mhybrid;
dynamicval<eGeometry> g(geometry, gEuclid);
dynamicval<eModel> pm(pmodel, mdDisk);

View File

@ -125,7 +125,7 @@ EX bool available() {
if(WDIM == 2 && (kite::in() || bt::in())) return false;
#ifdef GLES_ONLY
if(need_many_cell_types()) return false;
if(!euclid && !prod && !nil) return false;
if(!euclid && !gproduct && !nil) return false;
#endif
if(hyperbolic && pmodel == mdPerspective && !kite::in())
return true;
@ -137,7 +137,7 @@ EX bool available() {
return true;
if(euclid && pmodel == mdPerspective && !bt::in())
return true;
if(prod)
if(gproduct)
return true;
if(pmodel == mdPerspective && stretch::in())
return true;
@ -370,7 +370,7 @@ void raygen::compute_which_and_dist(int flat1, int flat2) {
else if(in_h2xe() && hybrid::underlying == gBinaryTiling)
fmain += "for(int i=0; i<=4; i++) if(i == 0 || i == 4) {";
else
fmain += "for(int i="+its(flat1)+"; i<"+(prod ? "sides-2" : ((WDIM == 2 || is_subcube_based(variation) || intra::in) && !bt::in()) ? "sides" : its(flat2))+"; i++) {\n";
fmain += "for(int i="+its(flat1)+"; i<"+(gproduct ? "sides-2" : ((WDIM == 2 || is_subcube_based(variation) || intra::in) && !bt::in()) ? "sides" : its(flat2))+"; i++) {\n";
fmain += " mediump mat4 m = " + getM("walloffset+i") + ";\n";
@ -454,14 +454,14 @@ void raygen::compute_which_and_dist(int flat1, int flat2) {
"mediump float v = -(Mp*u-1.) / Mt;\n"
"if(a < 1e-5) v = (1.-Mp*Mp) / (2. * Mt);\n"
"mediump float d = asinh(v);\n";
if(prod) fmain += "d /= xspeed;\n";
if(gproduct) fmain += "d /= xspeed;\n";
fmain +=
"if(d < 0. && abs(log(position."+w+"*position."+w+"-position.x*position.x)) < uBLevel) continue;\n"
"if(d < dist) { dist = d; which = i; }\n"
"}\n";
}
if(prod) fmain +=
if(gproduct) fmain +=
"if(zspeed > 0.) { mediump float d = (uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = sides-1; }}\n"
"if(zspeed < 0.) { mediump float d = (-uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = sides-2; }}\n";
@ -743,7 +743,7 @@ void raygen::move_forward() {
if(eyes) {
fmain +=
" mediump float t = go + dist;\n";
fmain += prod ?
fmain += gproduct ?
" mediump vec4 v = at1 * t;\n" :
" mediump vec4 v = at0 * t;\n";
fmain +=
@ -756,7 +756,7 @@ void raygen::move_forward() {
" mediump vec4 xp = vec4(2.*c*sin(w/2.) * cos(w/2.+alpha), 2.*c*sin(w/2.)*sin(w/2.+alpha), w*(1.+(c*c/2.)*((1.-sin(w)/w)+(1.-cos(w))/w * sin(w+2.*alpha))), 1.);\n"
" mediump vec4 orig_position = vw * vec4(0., 0., 0., 1.);\n"
" mediump vec4 nposition = translate(orig_position, xp);\n";
else if(prod) {
else if(gproduct) {
fmain +=
" mediump float alen_xy = length(azeq.xy);\n";
fmain += " mediump float nzpos = zpos + azeq.z;\n";
@ -808,10 +808,10 @@ void raygen::move_forward() {
" mediump vec4 nposition = v;\n";
}
bool reg = hyperbolic || sphere || euclid || sl2 || prod;
bool reg = hyperbolic || sphere || euclid || sl2 || gproduct;
if(reg) {
string s = (rotspace || prod) ? "-2" : "";
string s = (rotspace || gproduct) ? "-2" : "";
fmain +=
" mediump float best = "+f_len()+"(nposition);\n"
" for(int i=0; i<sides"+s+"; i++) {\n"
@ -826,7 +826,7 @@ void raygen::move_forward() {
" mediump float cand2 = len_rotspace(" + getM("walloffset+sides-1") + "*nposition);\n"
" if(cand2 < best) { best = cand2; which = sides-1; }\n"
" }\n";
if(prod) {
if(gproduct) {
fmain +=
"if(nzpos > uPLevel) which = sides-1;\n"
"if(nzpos <-uPLevel) which = sides-2;\n";
@ -944,7 +944,7 @@ void raygen::move_forward() {
}
void raygen::apply_reflect(int flat1, int flat2) {
if(prod) fmain += "if(reflect && which >= sides-2) { zspeed = -zspeed; continue; }\n";
if(gproduct) fmain += "if(reflect && which >= sides-2) { zspeed = -zspeed; continue; }\n";
if(horos()) {
fmain +=
"if(reflect && (which < "+its(flat1)+" || which >= "+its(flat2)+")) {\n";
@ -1014,7 +1014,7 @@ void raygen::emit_intra_portal(int gid1, int gid2) {
intra::switch_to(gid2);
}
if(prod) {
if(gproduct) {
fmain += "mediump vec4 nposition;\n";
fmain += "if(pconnection.x != .5) {\n"; // kind != 0
if(1) {
@ -1089,7 +1089,7 @@ void raygen::emit_intra_portal(int gid1, int gid2) {
intra::resetter ir;
intra::switch_to(gid2);
if(prod) {
if(gproduct) {
fmain += "if(pconnection.z != .5) {\n"; // kind != 0
if(1) {
string sgn = in_h2xe() ? "-" : "+";
@ -1182,11 +1182,11 @@ void raygen::emit_intra_portal(int gid1, int gid2) {
void raygen::emit_iterate(int gid1) {
using glhr::to_glsl;
if(intra::in && prod)
if(intra::in && gproduct)
fmain += " const mediump float uPLevel = " + to_glsl(cgi.plevel/2) + ";\n";
int flat1 = 0, flat2 = deg;
if(prod || rotspace) flat2 -= 2;
if(gproduct || rotspace) flat2 -= 2;
#if CAP_BT
if(horos()) {
@ -1292,8 +1292,8 @@ void raygen::emit_iterate(int gid1) {
fmain += "if(which == -1) continue;\n";
if(prod && eyes) fmain += "position.w = -nzpos;\n";
else if(prod) fmain += "position.w = -zpos;\n";
if(gproduct && eyes) fmain += "position.w = -nzpos;\n";
else if(gproduct) fmain += "position.w = -zpos;\n";
if(reg3::ultra_mirror_in()) fmain +=
"if(which >= " + its(S7) + ") {"
@ -1323,11 +1323,11 @@ void raygen::emit_iterate(int gid1) {
"pos.xyz = pos.zxy;\n";
else if(hyperbolic || sphere) fmain +=
"pos /= pos.w;\n";
else if(prod && bt::in()) fmain +=
else if(gproduct && bt::in()) fmain +=
"pos.xy = deparabolic12(pos).xy;\n"
"pos.z = -pos.w; pos.w = 0.;\n"
;
else if(prod) fmain +=
else if(gproduct) fmain +=
"pos = vec4(pos.x/pos.z, pos.y/pos.z, -pos.w, 0);\n";
fmain +=
" mediump vec2 inface = map_texture(pos, which+walloffset);\n"
@ -1438,7 +1438,7 @@ void raygen::emit_iterate(int gid1) {
" position = m * position;\n"
" tangent = m * tangent;\n";
if(prod) no_intra_portal =
if(gproduct) no_intra_portal =
" if(which == sides-2) { zpos += uPLevel+uPLevel; }\n"
" else if(which == sides-1) { zpos -= uPLevel+uPLevel; }\n"
" else {\n" + no_intra_portal + "}\n";
@ -1708,7 +1708,7 @@ void raygen::add_functions() {
}
void raygen::emit_raystarter() {
if(prod) {
if(gproduct) {
string sgn=in_h2xe() ? "-" : "+";
fmain +=
" position = vw * vec4(0., 0., 1., 0.);\n"
@ -1863,10 +1863,10 @@ void raygen::create() {
fsh += build_getter("mediump mat4", "uM", gms_limit);
#endif
if(prod || intra::in) fsh +=
if(gproduct || intra::in) fsh +=
"uniform mediump mat4 uLP;\n";
if(prod || intra::in) fsh +=
if(gproduct || intra::in) fsh +=
"uniform mediump float uPLevel;\n";
if(many_cell_types) fsh +=
@ -1971,7 +1971,7 @@ void raygen::create() {
fmain += " mediump vec4 position;\n";
fmain += " mediump vec4 tangent;\n";
if(prod || intra::in) {
if(gproduct || intra::in) {
fmain += " mediump float zspeed = 1.;\n";
fmain += " mediump float xspeed = 1.;\n";
fmain += " mediump float zpos = 0.;\n";
@ -2195,7 +2195,7 @@ struct raycast_map {
if(!c) continue;
intra::may_switch_to(c);
int id =p.first;
if(prod) {
if(gproduct) {
ms[id+c->type-2] = Id;
ms[id+c->type-1] = Id;
}

View File

@ -16,7 +16,7 @@ EX hyperpoint final_coords(hyperpoint h) {
if(sn::in() || !bt::in())
return ultra_normalize(h);
#if CAP_BT
if(bt::in() && !prod)
if(bt::in() && !mproduct)
return bt::bt_to_minkowski(h);
#endif
return h;
@ -121,7 +121,7 @@ EX namespace reg3 {
EX bool in() {
if(fake::in()) return FPIU(in());
if(geometry == gCubeTiling && (cubes_reg3 || !PURE)) return true;
return WDIM == 3 && !euclid && !bt::in() && !nonisotropic && !hybri && !kite::in();
return WDIM == 3 && !euclid && !bt::in() && !nonisotropic && !mhybrid && !kite::in();
}
EX void compute_ultra() {

View File

@ -1569,7 +1569,7 @@ EX void show() {
if(among(pmodel, mdJoukowsky, mdJoukowskyInverted)) {
animator(XLAT("Möbius transformations"), skiprope_rotation, 'S');
}
if(!prod) {
if(!mproduct) {
dialog::addBoolItem(XLAT("circle"), ma == maCircle, '4');
dialog::add_action([] () { ma = maCircle;
rotation_center = centerover;

View File

@ -265,13 +265,13 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
"t.z = (sin(uCamera) * cos(zl) * cos(d) - sin(zl) * cos(uCamera)) / uz;\n"
;
}
else if(pmodel == mdDisk && MDIM == 3 && !spherespecial && !prod) {
else if(pmodel == mdDisk && MDIM == 3 && !spherespecial && !gproduct) {
shader_flags |= SF_DIRECT;
}
else if(glhr::noshaders) {
shader_flags |= SF_PIXELS;
}
else if(pmodel == mdDisk && GDIM == 3 && !spherespecial && !nonisotropic && !prod) {
else if(pmodel == mdDisk && GDIM == 3 && !spherespecial && !nonisotropic && !gproduct) {
coordinator += "t /= (t[3] + uAlpha);\n";
vsh += "uniform mediump float uAlpha;";
shader_flags |= SF_DIRECT | SF_BOX | SF_ZFOG;
@ -454,7 +454,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 && pmodel == mdPerspective) {
else if(GDIM == 3 && WDIM == 2 && hyperbolic && context_fog && geom3::same_in_same() && pmodel == mdPerspective) {
vsh +=
"uniform mediump mat4 uRadarTransform;\n"
"uniform mediump sampler2D tAirMap;\n"
@ -586,7 +586,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) id |= 1;
if(WDIM == 2 && GDIM == 3 && hyperbolic && context_fog && geom3::same_in_same()) id |= 1;
shared_ptr<glhr::GLprogram> selected;
if(matched_programs.count(id)) selected = matched_programs[id];
@ -720,7 +720,7 @@ void display_data::set_projection(int ed, ld shift) {
glhr::projection_multiply(glhr::frustum(cd->tanfov, cd->tanfov * cd->ysize / cd->xsize));
glhr::projection_multiply(glhr::scale(1, -1, -1));
if(nisot::local_perspective_used()) {
if(prod) {
if(gproduct) {
for(int i=0; i<3; i++) NLP[3][i] = NLP[i][3] = 0;
NLP[3][3] = 1;
}

View File

@ -22,7 +22,7 @@ EX namespace shmupballs {
EX }
ld sqdist(shiftpoint a, shiftpoint b) {
if(prod) return pow(hdist(a, b), 2);
if(gproduct) return pow(hdist(a, b), 2);
else return intval(a.h, unshift(b, a.shift));
}
@ -422,7 +422,7 @@ void shootBullet(monster *m) {
bullet->base = m->base;
bullet->at = m->at;
if(WDIM == 3) bullet->at = bullet->at * cpush(2, 0.15 * SCALE);
if(prod) bullet->ori = m->ori;
if(gproduct) bullet->ori = m->ori;
bullet->type = moBullet;
bullet->set_parent(m);
bullet->pid = m->pid;
@ -441,7 +441,7 @@ void shootBullet(monster *m) {
monster* bullet = new monster;
bullet->base = m->base;
bullet->at = m->at * cspin(0, WDIM-1, TAU * i/8);
if(prod) bullet->ori = m->ori;
if(gproduct) bullet->ori = m->ori;
if(WDIM == 3) bullet->at = bullet->at * cpush(2, 0.15 * SCALE);
bullet->type = moBullet;
bullet->set_parent(m);
@ -3057,7 +3057,7 @@ bool celldrawer::draw_shmup_monster() {
if(!ths || !h) {
drawPlayerEffects(view, V, c, m->type);
if(WDIM == 3) {
if(prod) {
if(gproduct) {
hyperpoint h = m->ori * C0; // ztangent(1)
view = view * spin(-atan2(h[1], h[0]));
}
@ -3154,7 +3154,7 @@ bool celldrawer::draw_shmup_monster() {
default:
if(WDIM == 3) {
if(prod) {
if(gproduct) {
hyperpoint h = m->ori * xtangent(1);
view = view * spin(-atan2(h[1], h[0]));
}

97
sky.cpp
View File

@ -6,6 +6,12 @@ EX bool context_fog = true;
EX ld camera_level;
EX bool draw_sky = true;
EX bool camera_sign;
EX bool camera_over(ld x) {
if(camera_sign) return camera_level <= x;
return camera_level >= x;
}
#if MAXMDIM >= 4 && CAP_GL
@ -37,7 +43,7 @@ EX struct dqi_sky *sky;
EX void prepare_sky() {
sky = NULL;
if(euclid) {
if(euclid && !geom3::sph_in_euc()) {
if(WDIM == 3 || GDIM == 2) return;
if(no_wall_rendering) return;
shiftmatrix T = ggmatrix(currentmap->gamestart());
@ -46,7 +52,7 @@ EX void prepare_sky() {
queuepolyat(T * zpush(cgi.SKY+0.5) * xpush(cgi.SKY+0.5), cgi.shSun, 0xFFFF00FF, PPR::SKY);
}
else {
sky = &queuea<dqi_sky> (PPR::MISSILE);
sky = &queuea<dqi_sky> (euclid ? PPR::EUCLIDEAN_SKY : PPR::MISSILE);
}
}
@ -57,6 +63,7 @@ shiftmatrix sky_cview;
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 */
int sk = get_skybrightness();
@ -184,6 +191,7 @@ void compute_skyvertices(const vector<sky_item>& sky) {
}
if(true) {
hyperpoint tctr = tile_center();
cellwalker cw0(c, i);
cellwalker cw = cw0;
do {
@ -197,7 +205,7 @@ void compute_skyvertices(const vector<sky_item>& sky) {
transmatrix T1 = Id;
do {
vertices.push_back(tC0(T1));
vertices.push_back(T1 * tctr);
vcolors.push_back(colors[cw.at].first);
T1 = T1 * currentmap->adj(cw.at, cw.spin);
cw += wstep; cw++;
@ -210,15 +218,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) ctr = ctr + p;
normalize(ctr);
ctr = 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(h);
h = 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;
@ -249,13 +258,14 @@ void compute_skyvertices(const vector<sky_item>& sky) {
void dqi_sky::draw() {
if(!vid.usingGL || sky.empty() || skyvertices.empty()) return;
#if CAP_VR
transmatrix s = (vrhr::rendering() ? vrhr::master_cview : cview()).T * inverse(sky_cview.T);
#else
transmatrix s = cview().T * inverse(sky_cview.T);
#endif
if(euclid) be_euclidean_infinity(s);
for(int ed = current_display->stereo_active() ? -1 : 0; ed<2; ed+=2) {
if(global_projection && global_projection != ed) continue;
current_display->next_shader_flags = GF_VARCOLOR;
@ -282,7 +292,27 @@ color_t skycolor(cell *c) {
return gradient(0x4040FF, 0xFFFFFF, 0, z, 63);
}
EX const ld star_val = 2;
/** move an Euclidean matrix to V(C0) == C0 */
EX void be_euclidean_infinity(transmatrix& V) { for(int i=0; i<3; i++) V[i][3] = 0; }
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;
if(!have_stars) return;
ld val = cgi.SKY+star_val;
if(rev) val = -val;
if(euclid) {
auto V1 = V; be_euclidean_infinity(V1.T);
queuepolyat(V1 * zpush(val), sh, col, PPR::EUCLIDEAN_SKY);
}
else {
queuepolyat(V * zpush(val), sh, col, PPR::SKY);
}
}
void celldrawer::draw_ceiling() {
@ -291,19 +321,17 @@ void celldrawer::draw_ceiling() {
auto add_to_sky = [this] (color_t col, color_t col2) {
if(sky) sky->sky.emplace_back(c, V, col, col2);
};
switch(ceiling_category(c)) {
/* ceilingless levels */
case 1: {
if(euclid) return;
if(fieldpattern::fieldval_uniq(c) % 3 == 0) {
queuepolyat(V * zpush(cgi.SKY+star_val), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY);
}
if(euclid && !geom3::sph_in_euc()) return;
if(fieldpattern::fieldval_uniq(c) % 3 == 0)
draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
add_to_sky(0x00000F, 0x00000F);
if(c->land == laAsteroids) {
if(fieldpattern::fieldval_uniq(c) % 9 < 3) {
queuepolyat(V * zpush(-star_val-cgi.SKY), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY);
}
if(fieldpattern::fieldval_uniq(c) % 9 < 3)
draw_star(V, cgi.shNightStar, 0xFFFFFFFF, true);
int sk = get_skybrightness(-1);
auto sky = draw_shapevec(c, V * MirrorZ, cgi.shFullFloor.levels[SIDE_SKY], 0x000000FF + 0x100 * (sk/17), PPR::SKY);
if(sky) sky->tinf = NULL, sky->flags |= POLY_INTENSE;
@ -312,7 +340,7 @@ void celldrawer::draw_ceiling() {
}
case 2: {
if(euclid) return;
if(euclid && !geom3::sph_in_euc()) return;
color_t col;
color_t skycol;
@ -320,25 +348,19 @@ void celldrawer::draw_ceiling() {
case laWineyard:
col = 0x4040FF;
skycol = 0x8080FF;
if(emeraldval(c) / 4 == 11) {
queuepolyat(V * zpush(cgi.SKY+star_val), cgi.shSun, 0xFFFF00FF, PPR::SKY);
}
if(emeraldval(c) / 4 == 11) draw_star(V, cgi.shSun, 0xFFFF00FF);
break;
case laDesert:
col = 0x2020C0;
skycol = 0x8080FF;
if(emeraldval(c) / 4 == 11) {
queuepolyat(V * zpush(cgi.SKY+star_val), cgi.shSun, 0xFFFF00FF, PPR::SKY);
}
if(emeraldval(c) / 4 == 11) draw_star(V, cgi.shSun, 0xFFFF00FF);
break;
case laFrog:
col = 0x4040FF;
skycol = 0x8080FF;
if(zebra40(c) / 4 == 1) {
queuepolyat(V * zpush(cgi.SKY+star_val), cgi.shSun, 0xFFFF00FF, PPR::SKY);
}
if(zebra40(c) / 4 == 1) draw_star(V, cgi.shSun, 0xFFFF00FF);
break;
case laPower:
@ -395,7 +417,7 @@ void celldrawer::draw_ceiling() {
case 3: {
add_to_sky(0, 0);
if(camera_level <= cgi.WALL) return;
if(camera_over(cgi.WALL)) return;
if(c->land == laMercuryRiver) fcol = linf[laTerracotta].color, fd = 1;
if(qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE_WALL], darkena(fcol, fd, 0xFF), PPR::WALL);
forCellIdEx(c2, i, c)
@ -410,7 +432,7 @@ void celldrawer::draw_ceiling() {
case 4: {
add_to_sky(0x00000F, 0x00000F);
if(camera_level <= cgi.HIGH2) return;
if(camera_over(cgi.HIGH)) return;
auto ispal = [&] (cell *c0) { return c0->land == laPalace && among(c0->wall, waPalace, waClosedGate, waOpenGate); };
color_t wcol2 = 0xFFD500;
if(ispal(c)) {
@ -428,15 +450,13 @@ void celldrawer::draw_ceiling() {
if(among(c->wall, waClosedGate, waOpenGate) && qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE_WALL], 0x202020FF, PPR::WALL);
if(euclid) return;
if(true) {
queuepolyat(V * zpush(cgi.SKY+star_val), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY);
}
draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
break;
}
case 6: {
add_to_sky(skycolor(c), 0x4040C0);
if(camera_level <= cgi.HIGH2) return;
if(camera_over(cgi.HIGH2)) return;
color_t wcol2 = winf[waRuinWall].color;
if(c->landparam == 1)
forCellIdEx(c2, i, c) if(c2->landparam != 1)
@ -453,10 +473,9 @@ void celldrawer::draw_ceiling() {
case 7: {
add_to_sky(0x00000F, 0x00000F);
if(fieldpattern::fieldval_uniq(c) % 5 < 2) {
queuepolyat(V * zpush(cgi.SKY+star_val), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY);
}
if(camera_level <= cgi.HIGH2) return;
if(fieldpattern::fieldval_uniq(c) % 5 < 2)
draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
if(camera_over(cgi.HIGH2)) return;
color_t wcol2 = winf[waColumn].color;
if(c->landparam == 1)
forCellIdEx(c2, i, c) if(c2->landparam != 1)
@ -473,7 +492,7 @@ void celldrawer::draw_ceiling() {
case 5: {
add_to_sky(0x00000F, 0x00000F);
if(camera_level <= cgi.WALL) return;
if(camera_over(cgi.WALL)) return;
if(pseudohept(c)) {
forCellIdEx(c2, i, c)
@ -483,9 +502,7 @@ void celldrawer::draw_ceiling() {
draw_shapevec(c, V, qfi.fshape->levels[SIDE_WALL], darkena(fcol, fd, 0xFF), PPR::WALL);
if(euclid) return;
if(true) {
queuepolyat(V * zpush(cgi.SKY+star_val), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY);
}
draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
}
}
}

View File

@ -278,7 +278,7 @@ EX void initgame() {
if(cwt.at->land == laCrossroads2) {
cell *c = cwt.at;
if(hybri) { c = hybrid::get_where(c).first; PIU( c->cmove(0) ); }
if(mhybrid) { c = hybrid::get_where(c).first; PIU( c->cmove(0) ); }
c->landparam = 12;
c->cmove(0)->landparam = 44;
c->cmove(0)->land = laCrossroads2;
@ -1405,14 +1405,14 @@ EX void set_geometry(eGeometry target) {
gp::param.second = 0;
}
#endif
if(DUAL && geometry != gArchimedean && !hybri)
if(DUAL && geometry != gArchimedean && !mhybrid)
variation = ginf[geometry].default_variation;
#if CAP_BT
if(bt::in() || WDIM == 3 || kite::in() || arb::in()) if(!hybri) variation = eVariation::pure;
if(bt::in() || WDIM == 3 || kite::in() || arb::in()) if(!mhybrid) variation = eVariation::pure;
#endif
if(S3 >= OINF) variation = eVariation::pure;
if(INVERSE && !hybri) variation = gp::variation_for(gp::param);
if(ginf[target].default_variation == eVariation::pure && geometry != gArchimedean && !hybri)
if(INVERSE && !mhybrid) variation = gp::variation_for(gp::param);
if(ginf[target].default_variation == eVariation::pure && geometry != gArchimedean && !mhybrid)
variation = eVariation::pure;
geometry_settings(was_default);
@ -1442,7 +1442,7 @@ EX void set_variation(eVariation target) {
return;
}
if(target != eVariation::pure) {
if(bt::in() || sol || kite::in() || WDIM == 3) if(!prod) geometry = gNormal;
if(bt::in() || sol || kite::in() || WDIM == 3) if(!mproduct) geometry = gNormal;
}
auto& cd = ginf[gCrystal];
if(target == eVariation::bitruncated && cryst && cd.sides == 8 && cd.vertex == 4) {