embeddings:: shmup fixes

This commit is contained in:
Zeno Rogue 2023-02-04 19:40:49 +01:00
parent d67b157904
commit 2fe39a6613
5 changed files with 73 additions and 77 deletions

View File

@ -2257,6 +2257,10 @@ EX void display_embedded_errors() {
dialog::addInfo(XLAT("error: currently works only in binary tiling and similar"), 0xC00000);
return;
}
if(shmup::on && cgi.emb->no_spin()) {
dialog::addInfo(XLAT("error: this embedding does not work in shmup"), 0xC00000);
return;
}
if(meuclid && spatial_embedding == seCliffordTorus) {
rug::clifford_torus ct;
ld h = ct.xh | ct.yh;

View File

@ -236,6 +236,7 @@ EX }
virtual hyperpoint logical_to_base(hyperpoint h) = 0;
virtual ld anim_center_z() { return center_z(); }
virtual hyperpoint anim_tile_center();
virtual void logical_fix(transmatrix&) = 0;
virtual bool is_euc_in_product() { return false; }
virtual bool is_product_embedding() { return false; }
@ -380,6 +381,17 @@ struct emb_none : embedding_method {
}
return h;
}
void logical_fix(transmatrix& T) {
if(nonisotropic) {
hyperpoint h = tC0(T);
transmatrix rot = gpushxto0(h) * T;
fix_rotation(rot);
T = rgpushxto0(h) * rot;
}
else fixmatrix(T);
fixelliptic(T);
}
};
/** embeddings methods that are not emb_none */
@ -407,14 +419,27 @@ struct emb_actual : embedding_method {
h[3] = 1;
return h;
}
void logical_fix(transmatrix& T) {
hyperpoint a = T * tile_center();
hyperpoint i0 = actual_to_intermediate(a);
auto l0 = intermediate_to_logical * i0;
auto l = l0; l[2] = 0;
auto i = logical_to_intermediate * l;
auto rot0= inverse(intermediate_to_actual_translation(i0)) * T ;
auto rot = intermediate_to_logical_scaled * rot0 * logical_scaled_to_intermediate;
ld alpha = atan2(rot[0][1], rot[0][0]);
T = intermediate_to_actual_translation(i) * spin(alpha);
fixelliptic(T);
}
};
/** embed in the 3D variant of the same geometry */
struct emb_same_in_same : emb_actual {
virtual bool is_same_in_same() { return true; }
transmatrix intermediate_to_actual_translation(hyperpoint i) override { return rgpushxto0(i); }
hyperpoint actual_to_intermediate(hyperpoint a) override { return a; }
transmatrix intermediate_to_actual_translation(hyperpoint i) override { return rgpushxto0(logical_to_actual(i)); }
hyperpoint actual_to_intermediate(hyperpoint a) override { return actual_to_logical(a); }
hyperpoint orthogonal_move(const hyperpoint& h, ld z) override {
ld u = 1;
if(h[2]) z += asin_auto(h[2]), u /= cos_auto(asin_auto(h[2]));
@ -478,6 +503,12 @@ struct emb_same_in_same : emb_actual {
return hpxy3(h[0] * u, h[1] * u, 0);
}
void logical_fix(transmatrix& T) override {
// optimization
for(int i=0; i<4; i++) T[i][2] = T[2][i] = i == 2;
fixmatrix(T);
fixelliptic(T);
}
};
/** embed in the product geometry */
@ -539,7 +570,7 @@ struct emb_sphere_in_low : emb_actual {
bool is_sph_in_low() override { return true; }
bool is_depth_limited() override { return true; }
transmatrix intermediate_to_actual_translation(hyperpoint i) override {
return map_relative_push(logical_to_actual(i));
return map_relative_push(logical_to_actual(i)) * zpush(-1);
}
hyperpoint actual_to_intermediate(hyperpoint a) override { return actual_to_logical(a); }
ld center_z() { return 1; }
@ -596,6 +627,12 @@ struct emb_sphere_in_low : emb_actual {
h[2] = z; h[3] = 1;
return h;
}
void logical_fix(transmatrix& T) {
fix4(T);
fixmatrix(T);
fixelliptic(T);
}
};
/** abstract class for embeddings of Euclidean plane; these embeddings are not isotropic */

View File

@ -1449,28 +1449,27 @@ EX transmatrix shift_object(transmatrix Position, const transmatrix& ori, const
}
case smEmbedded: {
if(cgi.emb->is_euc_in_hyp() || cgi.emb->is_sph_in_low()) {
geom3::light_flip(true);
transmatrix T = rgpushxto0(direct_exp(direction));
geom3::light_flip(false);
return Position * cgi.emb->base_to_actual(T);
// optimization -- should work without it
if(cgi.emb->is_same_in_same()) return Position * rgpushxto0(direct_exp(direction));
if(gproduct) {
return Position * cgi.emb->intermediate_to_actual_translation(ori * cgi.emb->logical_to_intermediate * direction);
}
if(cgi.emb->is_euc_in_sph()) Position = inverse(View) * Position;
auto P = inverse_shift(ggmatrix(cwt.at), shiftless(Position));
transmatrix rot = inverse(cgi.emb->map_relative_push(Position * tile_center())) * Position;
ld z = cgi.emb->center_z();
if(z) rot = rot * lzpush(z);
transmatrix urot = unswap_spin(rot);
hyperpoint a = P * tile_center();
hyperpoint i0 = cgi.emb->actual_to_intermediate(a);
auto l0 = cgi.emb->intermediate_to_logical * i0;
auto l = l0; l[2] = 0;
auto i = cgi.emb->logical_to_intermediate * l;
auto rot1 = inverse(cgi.emb->intermediate_to_actual_translation(i)) * P;
auto rot = cgi.emb->intermediate_to_logical_scaled * rot1 * cgi.emb->logical_scaled_to_intermediate;
geom3::light_flip(true);
transmatrix T = rgpushxto0(direct_exp(urot * direction));
geom3::light_flip(false);
T = cgi.emb->base_to_actual(T);
auto res = Position * inverse(rot) * T * rot;
if(cgi.emb->is_euc_in_sph()) res = View * res;
return res;
auto par = cgi.emb->logical_to_intermediate * rot * direction;
if(cgi.emb->is_sph_in_low()) par = cspin180(0, 1) * par; // reason unknown
auto tra = cgi.emb->intermediate_to_actual_translation(par);
return Position * inverse(rot1) * tra * rot1;
}
default: throw hr_exception("unknown shift method in shift_object");
}

View File

@ -2025,14 +2025,9 @@ EX void adjust_eye(transmatrix& T, cell *c, ld sign) {
T = T * lzpush(sign * (cgi.SLEV[sl] - cgi.FLOOR - vid.eye + i));
}
/** achieve top-down perspective */
EX transmatrix default_spin() {
return cspin90(0, 1) * cgi.emb->intermediate_to_logical_scaled;
}
EX bool shmup_inverted() {
if(!embedded_plane) return false;
return (vid.wall_height < 0) ^ (cgi.emb->is_euc_in_nil() || cgi.emb->is_euc_in_sl2());
return vid.wall_height < 0;
}
EX void centerpc(ld aspd) {
@ -2056,8 +2051,8 @@ EX void centerpc(ld aspd) {
centerover = pc->base;
transmatrix T = pc->at;
if(nonisotropic) {
transmatrix rot = inverse(rgpushxto0(T * C0)) * T;
if(embedded_plane) {
transmatrix rot = inverse(cgi.emb->intermediate_to_actual_translation(cgi.emb->actual_to_intermediate(T * tile_center()))) * T;
T = T * inverse(rot);
adjust_eye(T, pc->base, +1);
T = T * rot;
@ -2069,11 +2064,13 @@ EX void centerpc(ld aspd) {
View = iview_inverse(T);
if(gproduct) NLP = ortho_inverse(pc->ori);
if(WDIM == 2) {
// already taken into account in gproduct
rotate_view(cgi.emb->intermediate_to_logical_scaled);
// right => upwards
rotate_view(cspin90(0, 1));
// apply playerturny
if(shmup_inverted()) rotate_view(cspin180(2, 1));
if(gproduct)
rotate_view( cspin(2, 1, -90._deg - shmup::playerturny[id]) * cspin90(0, 1));
else
rotate_view( cspin(2, 1, -90._deg - shmup::playerturny[id]) * default_spin());
rotate_view( cspin(2, 1, -90._deg - shmup::playerturny[id]));
}
return;
}

View File

@ -105,7 +105,6 @@ void monster::reset() {
stunoff = 0; blowoff = 0; fragoff = 0; footphase = 0;
inertia = Hypc; ori = Id; vel = 0;
swordangle = 0;
if(cgip && cgi.emb && cgi.emb->is_euc_in_product()) ori = cgi.emb->intermediate_to_logical_scaled;
}
using namespace multi;
@ -185,51 +184,11 @@ cell *monster::findbase(const shiftmatrix& T, int maxsteps) {
else return findbaseAround(T, base, maxsteps);
}
/** fix the matrix, including the appropriate fixes for nonisotropic, embedded_plane, and elliptic space */
void full_fix(transmatrix& T) {
if(embedded_plane) {
if(cgi.emb->is_sph_in_low()) {
for(int i=0; i<4; i++) T[i][3] = 0, T[3][i] = 0;
T[3][3] = 1;
fixmatrix(T);
}
else if(cgi.emb->is_same_in_same()) {
for(int i=0; i<4; i++) T[i][2] = 0, T[2][i] = 0;
T[2][2] = 1;
fixmatrix(T);
}
else if(gproduct) {
fixmatrix(T);
}
else {
hyperpoint h = T * tile_center();
transmatrix rot = iso_inverse(cgi.emb->map_relative_push(h)) * T;
if(cgi.emb->is_euc_in_sph()) rot = rot * lzpush(1);
fix_rotation(rot);
if(cgi.emb->is_hyp_in_solnih()) h[0] = 0;
else if(cgi.emb->is_euc_in_nil()) h[1] = 0;
T = cgi.emb->map_relative_push(h) * rot;
if(cgi.emb->is_euc_in_sph()) T = T * lzpush(-1);
fixmatrix(T);
}
}
else if(nonisotropic) {
hyperpoint h = tC0(T);
transmatrix rot = gpushxto0(h) * T;
fix_rotation(rot);
T = rgpushxto0(h) * rot;
}
else
fixmatrix(T);
fixelliptic(T);
}
void monster::rebasePat(const shiftmatrix& new_pat, cell *c2) {
if(isVirtual) {
at = new_pat.T;
virtualRebase(this);
full_fix(at);
cgi.emb->logical_fix(at);
pat = shiftless(at);
if(multi::players == 1 && this == shmup::pc[0])
current_display->which_copy = back_to_view(ggmatrix(base));
@ -239,7 +198,7 @@ void monster::rebasePat(const shiftmatrix& new_pat, cell *c2) {
at = inverse_shift(gmatrix[base], new_pat);
transmatrix old_at = at;
virtualRebase(this);
full_fix(at);
cgi.emb->logical_fix(at);
if(base != c2) {
if(fake::split()) println(hlog, "fake error");
else {
@ -257,7 +216,7 @@ void monster::rebasePat(const shiftmatrix& new_pat, cell *c2) {
pat = new_pat;
base = c2;
at = inverse_shift(gmatrix[c2], pat);
full_fix(at);
cgi.emb->logical_fix(at);
}
bool trackroute(monster *m, shiftmatrix goal, double spd) {