diff --git a/graph.cpp b/graph.cpp index c05d2046..9d7d6d09 100644 --- a/graph.cpp +++ b/graph.cpp @@ -810,7 +810,8 @@ EX transmatrix face_the_player(const transmatrix V) { if(GDIM == 2) return V; if(sl2) return V * zpush(cos(ptick(750)) * cgi.plevel / 16); if(prod) return mscale(V, cos(ptick(750)) * cgi.plevel / 16); - if(nonisotropic) return spin_towards(V, C0, 2, 0); + transmatrix dummy; /* used only in prod anyways */ + if(nonisotropic) return spin_towards(V, dummy, C0, 2, 0); return rgpushxto0(tC0(V)); } @@ -7182,14 +7183,16 @@ 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 = inverse(LPe); ld step = max / 20; ld fixed_yshift = 0; for(int i=0; i<20; i++) { - T = solmul_pt(T, LPe, ztangent(-step)); + T = parallel_transport(T, ori, ztangent(-step)); virtualRebase(c, T, true); color_t col; if(isWall3(c, col) || (WDIM == 2 && GDIM == 3 && tC0(T)[2] > cgi.FLOOR)) { - T = solmul_pt(T, LPe, ztangent(step)); + T = parallel_transport(T, ori, ztangent(step)); step /= 2; i = 17; if(step < 1e-3) break; } diff --git a/hyperpoint.cpp b/hyperpoint.cpp index 3aea3cd1..6dac36e2 100644 --- a/hyperpoint.cpp +++ b/hyperpoint.cpp @@ -239,11 +239,13 @@ EX ld volume_auto(ld r) { } } +EX ld asin_clamp(ld x) { return x>1 ? M_PI/2 : x<-1 ? -M_PI/2 : std::isnan(x) ? 0 : asin(x); } + EX ld asin_auto_clamp(ld x) { switch(cgclass) { case gcEuclid: return x; case gcHyperbolic: return asinh(x); - case gcSphere: return x>1 ? M_PI/2 : x<-1 ? -M_PI/2 : std::isnan(x) ? 0 : asin(x); + case gcSphere: return asin_clamp(x); default: return x; } } @@ -980,21 +982,43 @@ bool asign(ld y1, ld y2) { return signum(y1) != signum(y2); } ld xcross(ld x1, ld y1, ld x2, ld y2) { return x1 + (x2 - x1) * y1 / (y1 - y2); } -EX transmatrix solmul_pt(const transmatrix Position, const transmatrix T) { - if(nonisotropic) return nisot::parallel_transport(Position, Id, tC0(T)); - else return Position * T; +EX transmatrix parallel_transport(const transmatrix Position, const transmatrix& ori, const hyperpoint direction) { + if(nonisotropic) return nisot::parallel_transport(Position, direction); + else if(prod) { + hyperpoint h = product::direct_exp(ori * direction); + return Position * rgpushxto0(h); + } + else return Position * rgpushxto0(direct_exp(direction, 100)); } -EX transmatrix solmul_pt(const transmatrix Position, const transmatrix LPe, const hyperpoint h) { - if(nonisotropic || prod) return nisot::parallel_transport(Position, LPe, h); - else return Position * rgpushxto0(direct_exp(h, 100)); +EX void apply_parallel_transport(transmatrix& Position, const transmatrix orientation, const hyperpoint direction) { + Position = parallel_transport(Position, orientation, direction); } -EX transmatrix spin_towards(const transmatrix Position, const hyperpoint goal, int dir, int back) { - transmatrix T = - nonisotropic ? nisot::spin_towards(Position, goal) : - rspintox(inverse(Position) * goal); - if(back < 0) T = T * spin(M_PI); +EX void rotate_object(transmatrix& Position, transmatrix& orientation, transmatrix R) { + if(prod) orientation = orientation * R; + else Position = Position * R; + } + +EX transmatrix spin_towards(const transmatrix Position, transmatrix& ori, const hyperpoint goal, int dir, int back) { + transmatrix T; + ld alpha = 0; + if(nonisotropic) + T = nisot::spin_towards(Position, goal); + else { + hyperpoint U = inverse(Position) * goal; + if(prod) { + hyperpoint h = product::inverse_exp(U); + alpha = asin_clamp(h[2] / hypot_d(3, h)); + U = product_decompose(U).second; + } + T = rspintox(U); + } + if(back < 0) T = T * spin(M_PI), alpha = -alpha; + if(prod) { + if(dir == 0) ori = cspin(2, 0, alpha); + if(dir == 2) ori = cspin(2, 0, alpha - M_PI/2), dir = 0; + } if(dir) T = T * cspin(dir, 0, -M_PI/2); T = Position * T; return T; diff --git a/hypgraph.cpp b/hypgraph.cpp index 8833081d..3275dfdf 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -1315,6 +1315,7 @@ EX void centerpc(ld aspd) { int sl = snakelevel(cwt.at); if(sl && WDIM == 2) T = T * zpush(cgi.SLEV[sl] - cgi.FLOOR); View = inverse(T); + if(prod) nisot::local_perspective = inverse(pc->ori); if(WDIM == 2) rotate_view( cspin(0, 1, M_PI) * cspin(2, 1, M_PI/2 + shmup::playerturny[id]) * spin(-M_PI/2) ); return; } @@ -2086,7 +2087,7 @@ EX transmatrix get_shift_view_of(const hyperpoint H, const transmatrix V) { return V1 * eupush(IV * eupush(H) * V1 * C0); } else { - return inverse(nisot::parallel_transport(inverse(V), Id, -H)); + return inverse(nisot::parallel_transport(inverse(V), -H)); } } diff --git a/nonisotropic.cpp b/nonisotropic.cpp index df3dfe00..cd05b1ca 100644 --- a/nonisotropic.cpp +++ b/nonisotropic.cpp @@ -1193,15 +1193,11 @@ EX namespace nisot { T = push * gtl; } - EX transmatrix parallel_transport(const transmatrix Position, const transmatrix LPe, const hyperpoint h) { - if(prod) { - hyperpoint h = product::direct_exp(inverse(LPe) * product::inverse_exp(h)); - return Position * rgpushxto0(h); - } + EX transmatrix parallel_transport(const transmatrix Position, const hyperpoint direction) { auto P = Position; nisot::fixmatrix(P); - if(!geodesic_movement) return inverse(eupush(Position * translate(-h) * inverse(Position) * C0)) * Position; - return parallel_transport_bare(P, h); + if(!geodesic_movement) return inverse(eupush(Position * translate(-direction) * inverse(Position) * C0)) * Position; + return parallel_transport_bare(P, direction); } EX transmatrix spin_towards(const transmatrix Position, const hyperpoint goal) { diff --git a/shmup.cpp b/shmup.cpp index 02baa40f..10bb8e8f 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -46,6 +46,8 @@ struct monster { // butterflies: last position transmatrix at; transmatrix pat; + /** orientation for the product geometry */ + transmatrix ori; eMonster stk; bool dead; bool notpushed; @@ -67,7 +69,7 @@ struct monster { monster() { dead = false; inBoat = false; parent = NULL; nextshot = 0; stunoff = 0; blowoff = 0; footphase = 0; no_targetting = false; - swordangle = 0; inertia = Hypc; + swordangle = 0; inertia = Hypc; if(prod) ori = Id; } void store(); @@ -363,6 +365,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; bullet->type = moBullet; bullet->parent = m; bullet->pid = m->pid; @@ -381,6 +384,7 @@ void shootBullet(monster *m) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at * cspin(0, WDIM-1, M_PI/4*i); + if(prod) bullet->ori = m->ori; if(WDIM == 3) bullet->at = bullet->at * cpush(2, 0.15 * SCALE); bullet->type = moBullet; bullet->parent = m; @@ -831,7 +835,7 @@ void movePlayer(monster *m, int delta) { if(playerturn[cpid] && canmove && !blown && WDIM == 2) { m->swordangle -= playerturn[cpid]; - nat = nat * spin(playerturn[cpid]); + rotate_object(nat, m->ori, spin(playerturn[cpid])); if(inertia_based) m->inertia = spin(-playerturn[cpid]) * m->inertia; } transmatrix nat0 = nat; @@ -976,19 +980,20 @@ void movePlayer(monster *m, int delta) { if(inertia_based) { if(igo) { go = false; break; } ld r = hypot_d(WDIM, avg_inertia); - nat = solmul_pt(nat, rspintox(avg_inertia) * xpush(r * delta)) * spintox(avg_inertia); - if(WDIM == 3) nat = nat * cspin(0, 2, playerturn[cpid]) * cspin(1, 2, playerturny[cpid]); + apply_parallel_transport(nat, m->ori, rspintox(avg_inertia) * xtangent(r * delta)); + if(WDIM == 3) rotate_object(nat, m->ori, cspin(0, 2, playerturn[cpid]) * cspin(1, 2, playerturny[cpid])); m->vel = r * (600/SCALE); } else if(WDIM == 3) { - nat = solmul_pt(nat1, cpush(0, playerstrafe[cpid]) * cpush(2, playergo[cpid])) * cspin(0, 2, playerturn[cpid]) * cspin(1, 2, playerturny[cpid]); + nat = parallel_transport(nat1, m->ori, point3(playerstrafe[cpid], 0, playergo[cpid])); + rotate_object(nat, m->ori, cspin(0, 2, playerturn[cpid]) * cspin(1, 2, playerturny[cpid])); m->inertia[0] = playerstrafe[cpid] / delta; m->inertia[1] = 0; m->inertia[2] = playergo[cpid] / delta; } else if(playergo[cpid]) { - nat = solmul_pt(nat1, spin(playergoturn[cpid]) * xpush(playergo[cpid])) * spin(-playergoturn[cpid]); - m->inertia = spin(playergoturn[cpid]) * xpush0(playergo[cpid] / delta); + nat = parallel_transport(nat1, m->ori, spin(playergoturn[cpid]) * xtangent(playergo[cpid])); + m->inertia = spin(playergoturn[cpid]) * xtangent(playergo[cpid] / delta); } // spin(span[igo]) * xpush(playergo[cpid]) * spin(-span[igo]); @@ -1417,6 +1422,7 @@ void shoot(eItem it, monster *m) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at * rspintox(inverse(m->pat) * mouseh); + /* ori */ if(WDIM == 3) bullet->at = bullet->at * cpush(2, 0.15 * SCALE); bullet->type = it == itOrbDragon ? moFireball : it == itOrbAir ? moAirball : moBullet; bullet->parent = m; @@ -1509,9 +1515,9 @@ int bulletdir() { return (WDIM == 2) ? 0 : 2; } -transmatrix frontpush(ld x) { - if(WDIM == 2) return xpush(x); - else return cpush(2, x); +hyperpoint fronttangent(ld x) { + if(WDIM == 2) return xtangent(x); + else return ztangent(x); } ld collision_distance(monster *bullet, monster *target) { @@ -1530,6 +1536,7 @@ void spawn_asteroids(monster *bullet, monster *target) { monster* child = new monster; child->base = target->base; child->at = target->at; + child->ori = target->ori; child->type = target->type; child->parent = NULL; child->pid = target->pid; @@ -1564,7 +1571,7 @@ void moveBullet(monster *m, int delta) { m->vel -= delta / speedfactor() / 600000.0; if(m->vel < 0 && m->parent) { // return to the flailer! - nat = spin_towards(m->pat, m->parent->pat * C0, bulletdir(), -1); + nat = spin_towards(m->pat, m->ori, m->parent->pat * C0, bulletdir(), -1); } } else m->vel = bullet_velocity(m->type); @@ -1573,11 +1580,10 @@ void moveBullet(monster *m, int delta) { m->dead = true; if(inertia_based) { - ld r = hypot_d(WDIM, m->inertia); - nat = solmul_pt(nat, rspintox(m->inertia) * xpush(r * delta) * spintox(m->inertia)); + nat = parallel_transport(nat, m->ori, m->inertia * delta); } else - nat = solmul_pt(nat, frontpush(delta * SCALE * m->vel / speedfactor())); + nat = parallel_transport(nat, m->ori, fronttangent(delta * SCALE * m->vel / speedfactor())); cell *c2 = m->findbase(nat); if(m->parent && isPlayer(m->parent) && markOrb(itOrbLava) && c2 != m->base && !isPlayerOn(m->base)) @@ -1682,7 +1688,7 @@ void moveBullet(monster *m, int delta) { if((m2->type == moPalace || m2->type == moFatGuard || m2->type == moSkeleton || m2->type == moVizier || isMetalBeast(m2->type) || m2->type == moTortoise || m2->type == moBrownBug || m2->type == moReptile || m2->type == moSalamander || m2->type == moTerraWarrior) && m2->hitpoints > 1 && !slayer) { - m2->rebasePat(spin_towards(m2->pat, nat0 * C0, 0, 1)); + m2->rebasePat(spin_towards(m2->pat, m->ori, nat0 * C0, 0, 1)); if(m2->type != moSkeleton && !isMetalBeast(m2->type) && m2->type != moReptile && m2->type != moSalamander && m2->type != moBrownBug) m2->hitpoints--; m->dead = true; @@ -1733,7 +1739,7 @@ void moveBullet(monster *m, int delta) { // Knights reflect bullets if(m2->type == moKnight) { if(m->parent && m->parent != &arrowtrap_fakeparent) { - nat = spin_towards(nat, tC0(m->parent->pat), bulletdir(), 1); + nat = spin_towards(nat, m->ori, tC0(m->parent->pat), bulletdir(), 1); m->rebasePat(nat); } m->parent = m2; @@ -1769,7 +1775,7 @@ EX bool dragonbreath(cell *dragon) { int randplayer = hrand(numplayers()); monster* bullet = new monster; bullet->base = dragon; - bullet->at = spin_towards(Id, inverse(gmatrix[dragon]) * tC0(pc[randplayer]->pat), bulletdir(), 1); + bullet->at = spin_towards(Id, bullet->ori, inverse(gmatrix[dragon]) * tC0(pc[randplayer]->pat), bulletdir(), 1); bullet->type = moFireball; bullet->parent = bullet; bullet->pid = randplayer; @@ -2003,7 +2009,7 @@ void moveMonster(monster *m, int delta) { if(h[0] < fabsl(h[1])) return; } else if(!peace::on) { - nat = spin_towards(m->pat, tC0(goal), 0, 1); + nat = spin_towards(m->pat, m->ori, tC0(goal), 0, 1); } } @@ -2051,15 +2057,14 @@ void moveMonster(monster *m, int delta) { if(inertia_based) { if(igo) return; - ld r = hypot_d(WDIM, m->inertia); - nat = solmul_pt(nat, rspintox(m->inertia) * xpush(r * delta) * spintox(m->inertia)); + nat = parallel_transport(nat, m->ori, m->inertia * delta); } else if(WDIM == 3 && igo) { ld fspin = rand() % 1000; - nat = solmul_pt(nat0, cspin(1,2,fspin) * spin(igospan[igo]) * xpush(step) * spin(-igospan[igo]) * cspin(2,1,fspin)); + nat = parallel_transport(nat0, m->ori, cspin(1,2,fspin) * spin(igospan[igo]) * xtangent(step)); } else { - nat = solmul_pt(nat0, spin(igospan[igo]) * xpush(step) * spin(-igospan[igo])); // * spintox(wherePC); + nat = parallel_transport(nat0, m->ori, spin(igospan[igo]) * xtangent(step)); } if(m->type != moRagingBull && !peace::on) @@ -2134,6 +2139,7 @@ void moveMonster(monster *m, int delta) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at; + bullet->ori = m->ori; bullet->type = moTongue; bullet->parent = m; bullet->parenttype = m->type; @@ -2287,6 +2293,7 @@ void moveMonster(monster *m, int delta) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at; + bullet->ori = m->ori; bullet->type = moFireball; bullet->parent = m; additional.push_back(bullet); @@ -2300,6 +2307,7 @@ void moveMonster(monster *m, int delta) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at; + bullet->ori = m->ori; bullet->type = moBullet; bullet->parent = m; bullet->parenttype = moOutlaw; @@ -2312,6 +2320,7 @@ void moveMonster(monster *m, int delta) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at; + bullet->ori = m->ori; bullet->type = moAirball; bullet->parent = m; bullet->pid = i; @@ -2331,6 +2340,7 @@ void moveMonster(monster *m, int delta) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at; + bullet->ori = m->ori; bullet->type = moFlailBullet; bullet->parent = m; bullet->vel = 1/400.0; @@ -2344,6 +2354,7 @@ void moveMonster(monster *m, int delta) { monster* bullet = new monster; bullet->base = m->base; bullet->at = m->at; + bullet->ori = m->ori; bullet->type = moCrushball; bullet->parent = m; bullet->pid = i; diff --git a/system.cpp b/system.cpp index 05e305aa..6217ecc9 100644 --- a/system.cpp +++ b/system.cpp @@ -1189,7 +1189,6 @@ EX void set_geometry(eGeometry target) { if(GDIM == 2 && among(pmodel, mdPerspective, mdGeodesic)) pmodel = mdDisk; if(nonisotropic && old_DIM == 2 && vid.texture_step < 4) vid.texture_step = 4; if(prod) { pmodel = mdPerspective; if(vid.texture_step < 4) vid.texture_step = 4; } - if(prod && shmup::on) shmup::on = false; } } @@ -1288,7 +1287,6 @@ EX void switch_game_mode(char switchWhat) { chaosmode = false; princess::challenge = false; if(sol || bounded) set_geometry(gNormal); - if(prod) set_geometry(hybrid::underlying); dual::disable(); break; #endif @@ -1310,7 +1308,6 @@ EX void switch_game_mode(char switchWhat) { shmup::on = !shmup::on; princess::challenge = false; if(!shmup::on) racing::on = false; - if(prod) set_geometry(hybrid::underlying); break; case rg::randpattern: