diff --git a/commandline.cpp b/commandline.cpp index cc664a61..600970ae 100644 --- a/commandline.cpp +++ b/commandline.cpp @@ -119,6 +119,10 @@ EX namespace arg { #endif if(old != x && r) r(); } + + EX void shift_arg_formula_matrix(struct hr::trans23& x) { + shift(); x = parsematrix23(args()); // TODO animate + } #if HDR diff --git a/drawing.cpp b/drawing.cpp index 53d9acfd..063882d4 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -925,13 +925,29 @@ ld period_at(ld y) { } } +void apply_ori_gl(glvertex& g) { + auto Ori = pconf.mori().v2; + tie(g[0], g[1]) = make_pair( + Ori[0][0] * g[0] + Ori[0][1] * g[1], + Ori[1][0] * g[0] + Ori[1][1] * g[1] + ); + } + +void apply_iori_gl(glvertex& g) { + auto Ori = pconf.mori().v2; + tie(g[0], g[1]) = make_pair( + Ori[0][0] * g[0] + Ori[1][0] * g[1], + Ori[0][1] * g[0] + Ori[1][1] * g[1] + ); + } + void adjust(bool tinf) { periods.resize(isize(glcoords)); if(!models::model_straight) for(auto& g: glcoords) - models::apply_orientation(g[0], g[1]); + apply_ori_gl(g); for(int i = 0; i 0) continue; ld c1 = ah1[1], c2 = -ah2[1]; if(c1 < 0) c1 = -c1, c2 = -c2; @@ -2030,8 +2046,8 @@ void dqi_poly::draw() { if(l || lastl) { for(int i=0; i d1(dim, dim); + dim = 3; t.v2 = v2 * T.v2; + dim = 4; t.v3 = v3 * T.v3; + return t; + } + }; + +inline trans23 *gen_trans23() { return new trans23; } + /** mirror image */ constexpr transmatrix Mirror = diag(1,-1,1,1); @@ -1167,6 +1186,16 @@ EX transmatrix iso_inverse(const transmatrix& T) { return inverse(T); } +/** inverse a guaranteed rotation */ +EX transmatrix rot_inverse(const transmatrix& T) { + return transpose(T); + } + +/** inverse a guaranteed rotation */ +EX trans23 rot_inverse(const trans23& T) { + return trans23(rot_inverse(T.v2), rot_inverse(T.v3)); + } + /** \brief T inverse a matrix T = O*S, where O is isometry and S is a scaling matrix (todo optimize) */ EX transmatrix z_inverse(const transmatrix& T) { return inverse(T); diff --git a/hypgraph.cpp b/hypgraph.cpp index f12934db..7db31524 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -253,8 +253,7 @@ void move_y_to_z(hyperpoint& H, pair coef) { template void makeband(shiftpoint H, hyperpoint& ret, const T& f) { ld zlev = find_zlev(H.h); - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H.h); auto r = move_z_to_y(H.h); ld x, y, yf, zf=0; @@ -272,8 +271,7 @@ template void makeband(shiftpoint H, hyperpoint& ret, const T& f) { ld yzf = y * zf; y *= yf; ret = hpxyz(x / M_PI, y / M_PI, 0); move_y_to_z(ret, r); - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); if(zlev != 1 && use_z_coordinate()) apply_depth(ret, yzf / M_PI); return; @@ -397,9 +395,9 @@ EX void apply_perspective(const hyperpoint& H, hyperpoint& ret) { EX void apply_nil_rotation(hyperpoint& H) { if(nil) { nilv::convert_ref(H, nilv::model_used, nilv::nmSym); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); nilv::convert_ref(H, nilv::nmSym, pconf.rotational_nil); - models::apply_orientation(H[1], H[0]); + models::apply_iori(H); } } @@ -454,8 +452,7 @@ EX void threepoint_projection(const hyperpoint& H, hyperpoint& ret) { hyperpoint H1 = H; find_zlev(H1); if(true) { - models::apply_orientation_yz(H1[1], H1[2]); - models::apply_orientation(H1[0], H1[1]); + models::apply_ori(H1); } auto p = pconf.twopoint_param; @@ -501,16 +498,14 @@ EX void threepoint_projection(const hyperpoint& H, hyperpoint& ret) { geometry = gCubeTiling; ret = sxy; - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); } #endif EX vector> extra_projections; EX void make_axial(hyperpoint H, hyperpoint& ret, const hr::function& f) { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); ret[0] = f(H); ld axi = pconf.axial_angle; @@ -531,8 +526,7 @@ EX void make_axial(hyperpoint H, hyperpoint& ret, const hr::function 1e-9) - height += H[1] * (pow(zlev, models::ocos) - 1); - if(abs(models::ocos) > 1e-9 && models::osin) - height += H[0] * models::osin * (pow(zlev, models::ocos) - 1) / models::ocos; - else if(models::osin) - height += H[0] * models::osin * log(zlev); + if(abs(ocos) > 1e-9) + height += H[1] * (pow(zlev, ocos) - 1); + if(abs(ocos) > 1e-9 && osin) + height += H[0] * osin * (pow(zlev, ocos) - 1) / ocos; + else if(osin) + height += H[0] * osin * log(zlev); } - ret[1] = models::ocos + H[1]; + ret[1] = ocos + H[1]; ret[2] = GDIM == 3 ? H[2] : 0; if(MAXMDIM == 4) ret[3] = 1; if(zlev != 1 && use_z_coordinate()) @@ -824,8 +817,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { case mdQuadrant: { H = space_to_perspective(H); - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); tie(H[0], H[1]) = make_pair((H[0] + H[1]) / sqrt(2), (H[1] - H[0]) / sqrt(2)); @@ -840,8 +832,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret[0] = -H[1] * x - 1; ret[1] = H[1] / x + 1; - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } @@ -858,19 +849,13 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { apply_nil_rotation(H); - if(hyperbolic) { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); - } + if(hyperbolic) models::apply_ori(H); ret = hyperbolic ? deparabolic13(H) : H; ret *= .5; ret[LDIM] = 1; - if(hyperbolic) { - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); - } + if(hyperbolic) models::apply_iori(ret); if(!vrhr::rendering()) ret = lp_apply(ret); @@ -879,32 +864,24 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { case mdHorocyclicEqa: { - if(hyperbolic) { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); - } + if(hyperbolic) models::apply_ori(H); ret = hyperbolic ? deparabolic13(H) : H; ret[0] = exp(-ret[0]) - 1; ret *= .5; ret[LDIM] = 1; - if(hyperbolic) { - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); - } + if(hyperbolic) models::apply_iori(ret); break; } case mdConformalSquare: { find_zlev(H); - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); if(euclid) H[0] /= pconf.fisheye_param, H[1] /= pconf.fisheye_param; ret = to_square(H); - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } @@ -914,10 +891,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret *= .5; ret[LDIM] = 1; - if(hyperbolic) { - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); - } + if(hyperbolic) models::apply_iori(ret); if(!vrhr::rendering()) ret = lp_apply(ret); @@ -1080,8 +1054,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { } case mdSimulatedPerspective: { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); auto yz = move_z_to_y(H); hyperpoint Hl = xpush(-pconf.twopoint_param) * H; hyperpoint Hr = xpush(+pconf.twopoint_param) * H; @@ -1100,28 +1073,24 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret[0] = -ret[0]; ret[1] = -ret[1]; move_y_to_z(ret, yz); - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } case mdTwoHybrid: { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); auto yz = move_z_to_y(H); ret = compute_hybrid(H, whateveri[0]); move_y_to_z(ret, yz); - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } case mdJoukowsky: case mdJoukowskyInverted: { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); // with equal speed skiprope: models::apply_orientation(H[1], H[0]); if(pconf.skiprope) { @@ -1168,7 +1137,6 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret[0] = ret[0] / r2; ret[1] = -ret[1] / r2; move_y_to_z(ret, yz); - models::apply_orientation(ret[1], ret[0]); /* @@ -1181,10 +1149,9 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret[1] = log(mod); */ } else { - move_y_to_z(ret, yz); - models::apply_orientation(ret[0], ret[1]); + move_y_to_z(ret, yz); } - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } @@ -1193,14 +1160,14 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { H = space_to_perspective(H); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); pair p = polygonal::compute(H[0], H[1]); - models::apply_orientation(p.second, p.first); ret[0] = p.first; ret[1] = p.second; ret[2] = 0; + models::apply_iori(ret); break; } @@ -1211,7 +1178,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { H = space_to_perspective(H); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); H[0] += 1; double rad = H[0]*H[0] + H[1]*H[1]; @@ -1232,7 +1199,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret[0] /= -(1-mt) * 90._deg; ret[1] /= (1-mt) * 90._deg; - models::apply_orientation(ret[1], ret[0]); + models::apply_iori(ret); } else makeband(H_orig, ret, band_conformal); @@ -1329,8 +1296,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { case mdWerner: { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); find_zlev(H); // ignored for now @@ -1344,8 +1310,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret[2] = 0; ret[3] = 1; - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } @@ -1417,7 +1382,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { case mdRotatedHyperboles: { // ld zlev = <- not implemented find_zlev(H); // + vid.depth; - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); ld y = asin_auto(H[1]); ld x = asin_auto_clamp(H[0] / cos_auto(y)); @@ -1532,8 +1497,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { case mdPanini: { find_zlev(H); - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); ld proh = sqrt(H[2]*H[2] + curvature() * H[0] * H[0]); H /= proh; @@ -1541,8 +1505,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret = H; ret[2] = 0; ret[3] = 1; - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } @@ -1550,8 +1513,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { find_zlev(H); H = space_to_perspective(H); - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); ld u = H[0], v = H[1]; if(abs(u) > 1e-3 && abs(v) > 1e-3) { @@ -1564,8 +1526,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) { ret[2] = 0; ret[3] = 1; - models::apply_orientation(ret[1], ret[0]); - models::apply_orientation_yz(ret[2], ret[1]); + models::apply_iori(ret); break; } @@ -2264,11 +2225,11 @@ EX void centerpc(ld aspd) { } if(set_multi && multi::two_focus) { - pconf.model_orientation = atan2(multi_point) / degree; + pconf.mori() = spin( atan2(multi_point) ); auto& d = pconf.twopoint_param; d = hdist0(multi_point); if(among(pmodel, mdJoukowsky, mdJoukowskyInverted)) { - pconf.model_orientation += 90; + pconf.mori() = pconf.mori() * spin90(); pconf.model_transition = sinh(d) / (1 + cosh(d)); pconf.dualfocus_autoscale = true; } @@ -2603,8 +2564,7 @@ EX void draw_model_elements() { hyperpoint H = xpush(p * pconf.twopoint_param) * ypush0(h); hyperpoint res = compute_hybrid(H, 2 | mode); - models::apply_orientation(res[0], res[1]); - models::apply_orientation_yz(res[2], res[1]); + models::apply_iori(res); curvepoint(res * current_display->radius); } queuecurve(shiftless(Id), ringcolor, 0, PPR::CIRCLE); @@ -2616,9 +2576,9 @@ EX void draw_model_elements() { case mdTwoPoint: case mdSimulatedPerspective: fallthrough: { if(set_multi) return; /* no need */ - ld a = -pconf.model_orientation * degree; - put_x(shiftless(xspinpush(a, +pconf.twopoint_param)), ringcolor >> 8); - put_x(shiftless(xspinpush(a, -pconf.twopoint_param)), ringcolor >> 8); + auto T = rot_inverse(pconf.mori().get()); + put_x(shiftless(T * xpush(+pconf.twopoint_param)), ringcolor >> 8); + put_x(shiftless(T * xpush(-pconf.twopoint_param)), ringcolor >> 8); return; } @@ -2626,8 +2586,7 @@ EX void draw_model_elements() { vid.linewidth *= 5; for(int i=0; i<=3; i++) { hyperpoint h = xspinpush0(120._deg*i, pconf.twopoint_param); - models::apply_orientation(h[1], h[0]); - models::apply_orientation_yz(h[2], h[1]); + models::apply_iori(h); curvepoint(h); } @@ -2773,7 +2732,7 @@ EX void draw_boundary(int w) { h[broken_coord] = -sin_auto(a*degree) * rem; h[0] = sin_auto(a*degree) * eps * s; h[unbroken_coord] = cos_auto(a*degree); - models::apply_orientation(h[1], h[0]); + models::apply_iori(h); curvepoint(h); } queuecurve(shiftless(Id), periodcolor, 0, PPR::CIRCLE).flags |= POLY_FORCEWIDE; @@ -2793,13 +2752,14 @@ EX void draw_boundary(int w) { ld x = sin(a * pconf.twopoint_param * b / 90); ld y = 0; ld z = -sqrt(1 - x*x); - models::apply_orientation(y, x); + hyperpoint h0 = hpxyz(x, y, z); + models::apply_iori(h0); hyperpoint h1; - applymodel(shiftless(hpxyz(x,y,z)), h1); + applymodel(shiftless(h0), h1); - models::apply_orientation(h1[0], h1[1]); + models::apply_ori(h1); h1[1] = abs(h1[1]) * b; - models::apply_orientation(h1[1], h1[0]); + models::apply_iori(h1); curvepoint(h1); } @@ -2814,7 +2774,7 @@ EX void draw_boundary(int w) { if(GDIM == 3) return; if(pmodel == mdBand && pconf.model_transition != 1) return; bool bndband = (among(pmodel, mdBand, mdMiller, mdGallStereographic, mdCentralCyl) ? hyperbolic : sphere); - transmatrix T = spin(-pconf.model_orientation * degree); + transmatrix T = rot_inverse(pconf.mori().get()); ld right = 90._deg - 1e-5; if(bndband) queuestraight(T * ypush0(hyperbolic ? 10 : right), 2, lc, fc, p); @@ -2840,7 +2800,8 @@ EX void draw_boundary(int w) { case mdHalfplane: if(hyperbolic && GDIM == 2) { - queuestraight(xspinpush0(-pconf.model_orientation * degree - 90._deg, fakeinf), 1, lc, fc, p); + transmatrix Ori = rot_inverse(pconf.mori().get()); + queuestraight(Ori * spin270() * xpush0(fakeinf), 1, lc, fc, p); return; } break; @@ -2982,9 +2943,9 @@ EX void change_shift(shiftpoint& h, ld by) { tie(h[0], h[1]) = make_pair(h[0] * ca - h[1] * sa, h[1] * ca + h[0] * sa); } else if((mdinf[pmodel].flags & mf::uses_bandshift) || (sphere && pmodel == mdSpiral)) { - h.h = spin(pconf.model_orientation * degree) * h.h; + h.h = pconf.mori().get() * h.h; h.h = xpush(-by) * h.h; - h.h = spin(-pconf.model_orientation * degree) * h.h; + h.h = rot_inverse(pconf.mori().get()) * h.h; } } @@ -2999,10 +2960,10 @@ EX void change_shift(shiftmatrix& T, ld by) { } } else if((mdinf[pmodel].flags & mf::uses_bandshift) || (sphere && pmodel == mdSpiral)) { - T.T = spin(pconf.model_orientation * degree) * T.T; + T.T = pconf.mori().get() * T.T; T.T = xpush(-by) * T.T; fixmatrix(T.T); - T.T = spin(-pconf.model_orientation * degree) * T.T; + T.T = rot_inverse(pconf.mori().get()) * T.T; } } @@ -3045,7 +3006,7 @@ EX void optimize_shift(shiftmatrix& T) { } else if(((mdinf[pmodel].flags & mf::uses_bandshift) && T[LDIM][LDIM] > 30) || (sphere && pmodel == mdSpiral)) { - T.T = spin(pconf.model_orientation * degree) * T.T; + T.T = pconf.mori().get() * T.T; hyperpoint H = tC0(T.T); find_zlev(H); @@ -3058,7 +3019,7 @@ EX void optimize_shift(shiftmatrix& T) { T.shift += x; T.T = xpush(-x) * T.T; fixmatrix(T.T); - T.T = spin(-pconf.model_orientation * degree) * T.T; + T.T = rot_inverse(pconf.mori().get()) * T.T; } } @@ -3436,8 +3397,7 @@ EX hyperpoint lie_log(const shiftpoint h1) { EX hyperpoint lie_log_correct(const shiftpoint H_orig, hyperpoint& H) { find_zlev(H); if(hyperbolic) { - models::apply_orientation_yz(H[1], H[2]); - models::apply_orientation(H[0], H[1]); + models::apply_ori(H); return lie_log(shiftless(H)); } return lie_log(H_orig); diff --git a/menus.cpp b/menus.cpp index 77da41f2..0832b9f8 100644 --- a/menus.cpp +++ b/menus.cpp @@ -953,7 +953,7 @@ EX void showStartMenu() { specialland = racing::race_lands[rand() % isize(racing::race_lands)]; start_game(); pmodel = mdBand; - pconf.model_orientation = racing::race_angle; + pconf.mori() = racing::race_angle; racing::race_advance = 1; vid.yshift = 0; pconf.camera_angle = 0; diff --git a/models.cpp b/models.cpp index e3068ae7..c44815c8 100644 --- a/models.cpp +++ b/models.cpp @@ -119,18 +119,15 @@ EX namespace models { EX ld rotation_xz = 90; EX ld rotation_xy2 = 90; EX int do_rotate = 1; - EX ld ocos, osin, ocos_yz, osin_yz; EX ld cos_ball, sin_ball; EX bool model_straight, model_straight_yz; + EX void apply_ori(hyperpoint& h) { if(!model_straight) h = pconf.mori().get() * h; } + EX void apply_iori(hyperpoint& h) { if(!model_straight) h = iso_inverse(pconf.mori().get()) * h; } #if HDR - // screen coordinates to logical coordinates: apply_orientation(x,y) + // screen coordinates to logical coordinates: apply_orientation(x,y) // logical coordinates back to screen coordinates: apply_orientation(y,x) template - void apply_orientation(A& x, A& y) { if(!model_straight) tie(x,y) = make_pair(x*ocos + y*osin, y*ocos - x*osin); } - template - void apply_orientation_yz(A& x, A& y) { if(!model_straight_yz) tie(x,y) = make_pair(x*ocos_yz + y*osin_yz, y*ocos_yz - x*osin_yz); } - template void apply_ball(A& x, A& y) { tie(x,y) = make_pair(x*cos_ball + y*sin_ball, y*cos_ball - x*sin_ball); } #endif @@ -151,12 +148,8 @@ EX namespace models { EX void configure() { ld ball = -pconf.ballangle * degree; cos_ball = cos(ball), sin_ball = sin(ball); - ocos = cos(pconf.model_orientation * degree); - osin = sin(pconf.model_orientation * degree); - ocos_yz = cos(pconf.model_orientation_yz * degree); - osin_yz = sin(pconf.model_orientation_yz * degree); - model_straight = (ocos > 1 - 1e-9); - model_straight_yz = GDIM == 2 || (ocos_yz > 1-1e-9); + model_straight = (pconf.mori().get()[0][0] > 1 - 1e-9); + model_straight_yz = GDIM == 2 || (pconf.mori().get()[2][2] > 1-1e-9); if(history::on) history::apply(); if(!euclid) { @@ -474,7 +467,7 @@ EX namespace models { add_edit(vpconf.alpha); } - if(has_orientation(vpmodel)) { + /* TODO if(has_orientation(vpmodel)) { dialog::addSelItem(XLAT("model orientation"), fts(vpconf.model_orientation) + "°", 'l'); dialog::add_action([] () { dialog::editNumber(vpconf.model_orientation, 0, 360, 90, 0, XLAT("model orientation"), ""); @@ -485,13 +478,13 @@ EX namespace models { dialog::editNumber(vpconf.model_orientation_yz, 0, 360, 90, 0, XLAT("model orientation (y/z plane)"), ""); }); } - } + } */ if(among(vpmodel, mdPerspective, mdHorocyclic) && nil) { - dialog::addSelItem(XLAT("model orientation"), fts(vpconf.model_orientation) + "°", 'l'); + /* TODO dialog::addSelItem(XLAT("model orientation"), fts(vpconf.model_orientation) + "°", 'l'); dialog::add_action([] () { dialog::editNumber(vpconf.model_orientation, 0, 360, 90, 0, XLAT("model orientation"), ""); - }); + }); */ dialog::addSelItem(XLAT("rotational or Heisenberg"), fts(vpconf.rotational_nil), 'L'); dialog::add_action([] () { dialog::editNumber(vpconf.rotational_nil, 0, 1, 1, 1, XLAT("1 = Heisenberg, 0 = rotational"), ""); @@ -850,7 +843,7 @@ EX namespace models { } else if(argis("-mori")) { PHASEFROM(2); - shift_arg_formula(vpconf.model_orientation); + shift_arg_formula_matrix(vpconf.mori()); } else if(argis("-mets")) { PHASEFROM(2); @@ -868,11 +861,6 @@ EX namespace models { PHASEFROM(2); shift_arg_formula(vpconf.rotational_nil); } - else if(argis("-mori2")) { - PHASEFROM(2); - shift_arg_formula(vpconf.model_orientation); - shift_arg_formula(vpconf.model_orientation_yz); - } else if(argis("-crot")) { PHASEFROM(2); shift_arg_formula(models::rotation); @@ -987,8 +975,8 @@ EX namespace models { addsaverenum(p.model, pp+"used model", mdDisk); if(&p.model == &pmodel) param_custom(pmodel, "projection|Poincare|Klein|half-plane|perspective", menuitem_projection, '1'); - param_f(p.model_orientation, pp+"mori", sp+"model orientation", 0); - param_f(p.model_orientation_yz, pp+"mori_yz", sp+"model orientation-yz", 0); + // TODO param_f(p.model_orientation, pp+"mori", sp+"model orientation", 0); + // TODO param_f(p.model_orientation_yz, pp+"mori_yz", sp+"model orientation-yz", 0); param_f(p.top_z, sp+"topz", 5) -> editable(1, 20, .25, "maximum z coordinate to show", "maximum z coordinate to show", 'l'); diff --git a/racing.cpp b/racing.cpp index 90ed0524..996703be 100644 --- a/racing.cpp +++ b/racing.cpp @@ -698,7 +698,7 @@ EX void reset_race() { bool inrec = false; -EX ld race_angle = 90; +EX trans23 race_angle = cspin90(0, 1); EX bool force_standard_centering() { return nonisotropic || mhybrid || quotient || closed_or_bounded; @@ -793,7 +793,7 @@ EX bool set_view() { } if(GDIM == 3 && WDIM == 2) View = spin180() * cspin(2, 1, 90._deg + shmup::playerturny[multi::cpid]) * spin270() * View; - else if(GDIM == 2) View = spin(race_angle * degree) * View; + else if(GDIM == 2) View = race_angle.v2 * View; return true; } @@ -846,7 +846,7 @@ auto hook = }) + addHook(hooks_configfile, 100, [] { param_f(racing::race_advance, "race_advance"); - param_f(racing::race_angle, "race_angle"); + // TODO param_f(racing::race_angle, "race_angle"); param_i(racing::ghosts_to_show, "race_ghosts_to_show"); param_i(racing::ghosts_to_save, "race_ghosts_to_save"); param_b(racing::guiding, "race_guiding"); @@ -982,7 +982,7 @@ void race_projection() { dialog::addBoolItem(XLAT("band"), pmodel == mdBand, '2'); dialog::add_action([] () { pmodel = mdBand; - pconf.model_orientation = race_angle; + pconf.mori() = race_angle; race_advance = 1; vid.yshift = 0; pconf.camera_angle = 0; @@ -996,7 +996,7 @@ void race_projection() { dialog::addBoolItem(XLAT("half-plane"), pmodel == mdHalfplane, '3'); dialog::add_action([] () { pmodel = mdHalfplane; - pconf.model_orientation = race_angle + 90; + pconf.mori() = race_angle * spin90(); race_advance = 0.5; vid.yshift = 0; pconf.camera_angle = 0; @@ -1035,11 +1035,11 @@ void race_projection() { else dialog::addBreak(100); if(GDIM == 2) { - dialog::addSelItem(XLAT("race angle"), fts(race_angle), 'a'); + // TODO dialog::addSelItem(XLAT("race angle"), fts(race_angle), 'a'); dialog::add_action([] () { - dialog::editNumber(race_angle, 0, 360, 15, 90, XLAT("race angle"), ""); - int q = pconf.model_orientation - race_angle; - dialog::reaction = [q] () { pconf.model_orientation = race_angle + q; }; + // TODO dialog::editNumber(race_angle, 0, 360, 15, 90, XLAT("race angle"), ""); + auto q = rot_inverse(race_angle) * pconf.mori(); + dialog::reaction = [q] () { pconf.mori() = race_angle * q; }; }); } diff --git a/screenshot.cpp b/screenshot.cpp index 64c85a33..e4aad960 100644 --- a/screenshot.cpp +++ b/screenshot.cpp @@ -1365,7 +1365,7 @@ EX void apply() { if(ballangle_rotation) { if(models::has_orientation(vpconf.model)) - vpconf.model_orientation += ballangle_rotation * 360 * t / period; + vpconf.mori() = trans23(spin(ballangle_rotation * 360 * t / period)) * vpconf.mori(); else vpconf.ballangle += ballangle_rotation * 360 * t / period; } @@ -1925,7 +1925,7 @@ startanim null_animation { "", no_init, [] { gamescreen(); }}; #if CAP_STARTANIM startanim joukowsky { "Joukowsky transform", no_init, [] { dynamicval dm(pmodel, mdJoukowskyInverted); - dynamicval dt(pconf.model_orientation, ticks / 25.); + dynamicval dt(pconf.mori(), spin( ticks / 25. )); dynamicval dv(vid.use_smart_range, 2); dynamicval ds(pconf.scale, 1/4.); models::configure(); @@ -1936,7 +1936,7 @@ startanim joukowsky { "Joukowsky transform", no_init, [] { startanim bandspin { "spinning in the band model", no_init, [] { dynamicval dm(pmodel, mdBand); - dynamicval dt(pconf.model_orientation, ticks / 25.); + dynamicval dt(pconf.mori(), spin( ticks / 25. )); dynamicval dv(vid.use_smart_range, 2); models::configure(); gamescreen(); diff --git a/shaders.cpp b/shaders.cpp index ab705ff0..19697cc1 100644 --- a/shaders.cpp +++ b/shaders.cpp @@ -56,10 +56,12 @@ EX map> matched_programs; glhr::glmatrix model_orientation_gl() { glhr::glmatrix s = glhr::id; - for(int a=0; auRotNil != -1) { - glUniform1f(selected->uRotCos, models::ocos); - glUniform1f(selected->uRotSin, models::osin); + glUniform1f(selected->uRotCos, pconf.mori().get()[0][0]); + glUniform1f(selected->uRotSin, pconf.mori().get()[1][0]); glUniform1f(selected->uRotNil, pconf.rotational_nil); } @@ -786,10 +788,12 @@ void display_data::set_projection(int ed, ld shift) { pp = glhr::tmtogl_transpose(NLP) * pp; if(get_shader_flags() & SF_ORIENT) { - if(GDIM == 3) for(int a=0; a<4; a++) - models::apply_orientation_yz(pp[a][1], pp[a][2]); - for(int a=0; a<4; a++) - models::apply_orientation(pp[a][0], pp[a][1]); + for(int a=0; a<4; a++) { + hyperpoint row; + for(int b=0; b<4; b++) row[b] = pp[a][b]; + models::apply_ori(row); + for(int b=0; b<4; b++) pp[a][b] = row[b]; + } } glUniformMatrix4fv(selected->uPP, 1, 0, pp.as_array()); diff --git a/util.cpp b/util.cpp index f9ec73fa..22ad46be 100644 --- a/util.cpp +++ b/util.cpp @@ -129,6 +129,8 @@ struct exp_parser { cld parse(int prio = 0); + transmatrix parsematrix(int prio = 0); + ld rparse(int prio = 0) { return validate_real(parse(prio)); } int iparse(int prio = 0) { return int(floor(rparse(prio) + .5)); } @@ -470,12 +472,80 @@ cld exp_parser::parse(int prio) { return res; } +int coord_id(char ch) { + if(ch == 'x') return 0; + if(ch == 'y') return 1; + if(ch == 'z') return 2; + if(ch == 'w') return 3; + if(ch == 't') return MDIM-1; + return -1; + } + +ld angle_unit(char ch) { + if(ch == 'r') return 1; + if(ch == 'd') return degree; + if(ch == 't') return TAU; + if(ch == 'l') return -1; + return 0; + } + +transmatrix exp_parser::parsematrix(int prio) { + skip_white(); + if(s[at] && s[at+1] && s[at+2] && s[at+3] == '(') { + ld unit = angle_unit(s[at]); + int c0 = coord_id(s[at+1]); + int c1 = coord_id(s[at+2]); + if(c0 >= 0 && c1 >= 0 && c0 != c1 && unit) { + at += 4; + ld angle = validate_real(parsepar()); + if(unit == -1) return lorentz(c0, c1, angle); + else return cspin(c0, c1, angle); + } + } + transmatrix res; + if(next() == '(') { + at++; + res = parsematrix(); + force_eat(")"); + } + else { + string token = next_token(); + if(token == "id") res = Id; + else if(token == "view") res = View; + else throw hr_parse_exception("unknown matrix: " + token); + } + while(true) { + skip_white(); + if(next() == '*' && prio <= 20) at++, res = res * parsematrix(30); + } + return res; + } + EX ld parseld(const string& s) { exp_parser ep; ep.s = s; return ep.rparse(); } +EX transmatrix parsematrix(const string& s) { + exp_parser ep; + ep.s = s; + return ep.parsematrix(); + } + +EX trans23 parsematrix23(const string& s) { + trans23 t; + #if MAXMDIM == 3 + t.v2 = t.v3 = parsematrix(s); + #else + auto& dim = cginf.g.homogeneous_dimension; + dynamicval d1(dim, dim); + dim = 3; t.v2 = parsematrix(s); + dim = 4; t.v3 = parsematrix(s); + #endif + return t; + } + EX int parseint(const string& s) { exp_parser ep; ep.s = s;