#include "rogueviz.h" // for this video: https://youtu.be/Rhjv_PazzZE namespace hr { namespace embchess { namespace smoothcam { using namespace rogueviz::smoothcam; } /** load Chess? */ EX bool with_chess = false; /** load other models? */ EX bool with_models = false; /** including the CGtrader models? (not included here) */ EX bool cgtrader_models = false; /** floor disabled */ EX bool no_floor = false; /** do not include the models inside the house for faster transition */ EX bool light_models = false; /** higher periods needs to be set to display scaffold correctly */ int periods = 1; /** how many chess moves performed */ int chess_moves = 0; vector> map54_edges; vector map54_nodes; vector> map534_edges; vector map534_nodes; struct embset { string name; geom3::eSpatialEmbedding se; ld walls, scale, depth, eye, sun, sky, star; embset(const string& n, geom3::eSpatialEmbedding se, ld walls, ld scale, ld depth, ld eye, ld sun, ld sky, ld star) : name(n), se(se), walls(walls), scale(scale), depth(depth), eye(eye), sun(sun), sky(sky), star(star) {} embset() {} }; embset current() { embset e; e.name = "current"; e.se = geom3::spatial_embedding; e.scale = geom3::euclid_embed_scale; auto actscale = e.scale; if(e.se == geom3::seDefault) { e.scale = 0; actscale = 1; } e.walls = vid.wall_height / actscale; e.depth = vid.depth / e.walls; e.eye = (vid.eye-vid.depth) / e.walls; e.sun = vid.sun_size / e.walls; e.sky = vid.sky_height; e.star = vid.star_height; e.se = geom3::spatial_embedding; return e; } void activate(const embset& e) { if(GDIM == 2) invoke_embed(geom3::seDefault); embset c = current(); geom3::changing_embedded_settings = true; geom3::switch_always3(); geom3::euclid_embed_scale = e.se == geom3::seDefault ? 1 : e.scale; vid.wall_height = e.walls * geom3::euclid_embed_scale; vid.depth = e.depth * vid.wall_height; vid.eye = vid.depth + e.eye * vid.wall_height; vid.sun_size = e.sun * vid.wall_height; vid.sky_height = e.sky; vid.star_height = e.star; geom3::spatial_embedding = e.se; geom3::switch_always3(); geom3::changing_embedded_settings = false; if(e.se != c.se) { if(vid.usingGL) resetGL(); } delete_sky(); pmodel = default_model(); }; embset emb_lerp(const embset& a, const embset& b, ld f) { embset e; e.name = lalign(0, "lerp(", a, ", ", b, ", ", f, ")"); e.se = b.se; e.scale = lerp(a.scale, b.scale, f); e.walls = lerp(a.walls, b.walls, f); e.depth = lerp(a.depth, b.depth, f); e.eye = lerp(a.eye, b.eye, f); e.sun = lerp(a.sun, b.sun, f); e.sky = lerp(a.sky, b.sky, f); e.star = lerp(a.star, b.star, f); return e; } void print(hstream& hs, const embset& e) { print(hlog, "embset{.name=\"", e.name, "\", .se=eEmbeddingMethod(", int(e.se), "), .walls=", e.walls, ", .scale=", e.scale, ", .depth=", e.depth, ", .eye=", e.eye, ", .sun=", e.sun, ", .sky=", e.sky, ", .star=", e.star, "}"); } embset edefault = embset("default", geom3::seDefault, 1.2, 0, 0, 1.5, 0.333333, 10, 9); embset edefaulti = embset("default", geom3::seDefault, -1.2, 0, 0, 1.5, 0.333333, 10, 9); // embset eincyl = embset{.name="in cylinder", .se=geom3::seCylinderE, .walls=0.75, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.6}; embset eincyl = embset("in cylinder E", geom3::seCylinderE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4); embset eoutcyl = embset("out cylinder E", geom3::seCylinderE, -1.2, M_PI/10, 0, 1.5, 0.3, 10, 9); embset eouthoro = embset("out horosphere", geom3::seLowerCurvature, 1.2, 0.1, 0, 1.5, 0.25, 8, 7.5); embset einhoro = embset("in horosphere", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 12, 11); embset einhoro_small = embset("in horosphere (small sky)", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 18, 17); embset esolv = embset("solv", geom3::seSol, 1.2, 0.1, 0, 1.5, 0.25, 12, 11); embset einnih = embset("in NIH", geom3::seNIH, -1.2, 0.1, 0, 1.5, 0.25, 12, 11); embset eoutnih = embset("out NIH", geom3::seNIH, 1.2, 0.1, 0, 1.5, 0.25, 8, 7.5); embset eclifford = embset("Clifford", geom3::seCliffordTorus, 1.2, M_PI/10, -0.0561826, 1.5, 0.25, 2.55, 2.3); embset enil = embset("Nil flat", geom3::seNil, 1.2, 0.1, 0, 1.5, 0.25, 12, 11); embset esl2 = embset("SL(2,R) flat", geom3::seSL2, 1.2, 0.1, 0, 1.5, 0.25, 12, 11); embset eincylh = embset("in cylinderH", geom3::seCylinderH, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4); embset eincylhe = embset("in cylinderHE", geom3::seCylinderHE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4); embset eincylnil = embset("in cylinder Nil", geom3::seCylinderNil, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4); embset eincylsl = embset("in cylinder SL(2,R)", geom3::seCylinderSL2, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4); embset einhorocyl = embset("in horocylinder", geom3::seCylinderHoro, -1.2, M_PI/10, 0, 1.5, 0.10472, 8, 7.5); embset eouthorocyl = embset("out horocylinder", geom3::seCylinderHoro, 1.2, M_PI/10, 0, 1.5, 0.10472, 4, 3.5); embset eprodh_flat = embset("hyperbolic product (flat)", geom3::seProductH, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4); embset eprodh_concave = embset("hyperbolic product (concave)", geom3::seProductH, 1.2, M_PI/10, 1, 1.5, 0.10472, 2.6, 2.4); embset eprods_flat = embset("spherical product (flat)", geom3::seProductS, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4); embset eprods_concave = embset("spherical product (concave)", geom3::seProductS, 1.2, M_PI/10, 0.8333, 1.5, 0.10472, 2.6, 2.4); embset& edok() { return vid.wall_height > 0 ? edefault : edefaulti; } vector embsets = { edefault, eincyl, eoutcyl, eouthoro, einhoro, einhoro_small, esolv, eclifford, einnih, eoutnih, enil, esl2, eincylh, eincylhe, eincylnil, eincylsl, einhorocyl, eouthorocyl, eprodh_flat, eprodh_concave, eprods_flat, eprods_concave }; ld fix_chess = 0; int draw_digger = 0; bool move_cat = false; vector xmap = { {"......B..........p#"}, {".................p#"}, {"..xxxxxxxx.......p#"}, {"..xxxxxxxx..T....p#"}, {"..xxxxxxxx.....T.p#"}, {"..xxxxxxxx...~~..p#"}, {"..xxxxxxxx..~uv~.p#"}, {"..xxxxxxxx..~vu~.p#"}, {"..xxxxxxxx..~~~~.p#"}, {"..xxxxxxxx......Tp#"}, {".............T...p#"}, {"......C..........p#"}, {"......p..........p#"}, {".>>>..p..DDDDDDD.p#"}, {".>>>..pK.DddddrD.p#"}, {".>>>..pK.DdddtdD.p#"}, {"......pK.DdddddD.p#"}, {"..e...p..DOD+DOD.p#"}, {"......p.....p....p#"}, {"....^.pppppppppppp#"}, }; void build_map(); ld hmul = 1; set house1, house2; vector ac, bac; using namespace rogueviz::objmodels; void prepare_tf(); hyperpoint adjust(hyperpoint h) { h = cspin90(1, 2) * h * 40. + point3(-0.5, -0.5, 0); return h; } hyperpoint rechess(hyperpoint h) { h[2] = lerp(cgi.FLOOR, cgi.WALL, 0.01-h[2]/4 * hmul * 2 / 0.6) + fix_chess; if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } struct split_model_data : gi_extension { map, vector>> objs_at; void render(const shiftmatrix& V, int x, int y); }; struct chessmodel : public model { void process_triangle(vector& hys, vector& tot, bool textured, object *co) override { for(auto& h: hys) h = adjust(h); hyperpoint norm = (hys[1] - hys[0]) ^ (hys[2] - hys[0]); norm /= hypot_d(3, norm); ld y = .5 + (.2 * norm[0] + .16 * norm[1] + .14 * norm[2]); glvertex shade = glhr::makevertex(0, y, 0); glvertex shadecol = glhr::makevertex(y, y, y); auto elen = [] (hyperpoint a, hyperpoint b) { return ceil(hypot_d(3, a-b) * 5); }; int parts = max( max(elen(hys[0], hys[1]), elen(hys[0], hys[2])), elen(hys[1], hys[1]) ); // if(parts > 8) println(hlog, "parts = ", parts, " levels = ", tie(hys[0][2], hys[1][2], hys[2][2]), " .. ", hys); // if(parts > 8) return; auto tri = [&] (int a, int b) { cgi.hpcpush(rechess(hys[0] + (hys[1] - hys[0]) * a / parts + (hys[2] - hys[0]) * b / parts)); if(textured) { co->tv.tvertices.push_back(glhr::pointtogl(tot[0] + (tot[1] - tot[0]) * a / parts + (tot[2] - tot[0]) * b / parts)); co->tv.colors.push_back(shadecol); } else { co->tv.tvertices.push_back(shade); } }; for(int a=0; a&) cgi.ext[fname + "-SPLIT"]; if(!md) { md = std::make_unique(); auto& md0 = get(); split(md0, *md); } return *md; } }; bool ispiece(color_t col) { return among(col, color_t(0xFFFFFFFF), color_t(0x202020FF), color_t(0x2B2B2BFF)); } void chessmodel::split(model_data& md, split_model_data& smd) { cgi.extra_vertices(); map, map>>> mm; for(auto& obj: md.objs) { for(int i=obj->sh.s; ish.e; i+=3) { hyperpoint ctr = Hypc; array hs; for(int j=0; j<3; j++) hs[j] = GDIM == 2 ? cgi.hpc[i+j] : cgi.emb->actual_to_logical(cgi.hpc[i+j]); ctr += hs[0]; ctr += hs[1]; ctr += hs[2]; ctr /= 3; int x = floor(ctr[0] + .5); int y = floor(ctr[1] + .5); int ax = x + 6, ay = y + 6; if(chess_moves >= 1 && ispiece(obj->color)) { if(ax == 6) { if(ay == 8) ay = 6; else if(ay == 6) ay = 8; } } if(chess_moves >= 2 && ispiece(obj->color)) { if(ax == 6) { if(ay == 3) ay = 5; else if(ay == 5) ay = 3; } } if(chess_moves >= 3 && ispiece(obj->color)) { if(ax == 8) { if(ay == 9) ay = 7, ax = 7; } } for(int j=0; j<3; j++) mm[{ax,ay}][obj->color].emplace_back(hs[j] - hyperpoint(x, y, 0, 0), obj->tv.tvertices[i+j-obj->sh.s]); } } for(auto& a: mm) for(auto& b: a.second) { auto& objs = smd.objs_at[a.first]; objs.push_back(make_shared()); auto co = &*objs.back(); cgi.bshape(co->sh, PPR::THORNS); cgi.last->flags |= POLY_TRIANGLES; cgi.last->texture_offset = 0; cgi.last->tinf = &co->tv; co->tv.texture_id = floor_textures->renderedTexture; if(GDIM == 2) cgi.last->tinf = nullptr; co->color = b.first; if(co->color == 0xCCCCCCFF) co->color = GDIM == 2 ? 0 : 0xFFE080FF; else if(co->color == 0x5B5B5BFF) co->color = GDIM == 2 ? 0 : 0x807020FF; // else for(auto& v: b.second) v.first = cspin180(0, 1) * v.first; for(auto v: b.second) { cgi.hpcpush(GDIM == 2 ? v.first : cgi.emb->logical_to_actual(v.first)); co->tv.tvertices.push_back(v.second); } cgi.finishshape(); } cgi.extra_vertices(); if(0) for(auto& p: smd.objs_at) { println(hlog, p.first, " : ", isize(p.second), " objects"); for(auto& obj: p.second) { vector hs; for(int i=obj->sh.s; ish.e; i++) hs.push_back(cgi.hpc[i]); if(isize(hs) > 3) hs.resize(3); println(hlog, "vertices: ", obj->sh.e - obj->sh.s, " of color ", obj->color, " : ", hs); } } } void split_model_data::render(const shiftmatrix& V, int x, int y) { for(auto& obj: objs_at[{x, y}]) if(obj->color) { queuepoly(V, obj->sh, obj->color); } } chessmodel chess("rogueviz/models/", "Polyfjord_Chess_Set.obj"); struct bunnymodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h = cspin(0, 1, 15._deg) * h; h[0] *= 800; h[1] *= 800; h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(-0.000333099, -0.00186996, h[2]) * hmul * 4/3.); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } bunnymodel(string a, string b) : model(a,b) {} }; bunnymodel bunny("rogueviz/models/", "bunny.obj"); struct catmodel : public model { hyperpoint transform(hyperpoint h) override { if(0) println(hlog, "scale = 1 to ", lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, 1) * hmul * 4/3.) - lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, 0) * hmul * 4/3.) ); h = cspin90(1, 2) * h; h = cspin180(0, 1) * h; h = cspin(1, 0, 30._deg) * h; h[0] *= 6; h[1] *= 6; h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, h[2]) * hmul * 4/3.) / 8.3272 * 6; if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } void load_obj(model_data& md) override { model::load_obj(md); for(auto& o: md.objs) if(o->mtlname == "whiskers") o->sh.prio = PPR::TRANSPARENT_WALL; } catmodel(string a, string b) : model(a,b) {} }; catmodel maxwellcat("rogueviz/models/", "maxwellcat.obj"); struct tulipmodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h = cspin180(0, 1) * h; h[0] *= 400; h[1] *= 400; h[0] -= 0.1*2; h[1] += 0.36*2; h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0, -0.00307639, h[2]) * hmul); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } tulipmodel(string a, string b) : model(a,b) {} }; tulipmodel tulip("rogueviz/models/", "tulip.obj"); tulipmodel tulip1("rogueviz/models/", "tulip1.obj"); tulipmodel tulip2("rogueviz/models/", "tulip2.obj"); struct diggermodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h[0] *= 50; h[1] *= 50; /* h[0] *= 400; h[1] *= 400; h[0] -= 0.1*2; h[1] += 0.36*2; */ h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00027, -0.0549454, h[2]) * hmul * 1.5); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } diggermodel(string a, string b) : model(a,b) {} }; diggermodel digger("rogueviz/models/", "digger.obj"); struct tablemodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h[1] -= 0.005; h[0] *= 100; h[1] *= 100; /* h[0] *= 400; h[1] *= 400; h[0] -= 0.1*2; h[1] += 0.36*2; */ h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0, -0.008, h[2]) * hmul / 2); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } tablemodel(string a, string b) : model(a,b) {} }; tablemodel table("rogueviz/models/", "table.obj"); struct cheesemodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h[0] *= 15; h[1] *= 15; /* h[0] *= 400; h[1] *= 400; h[0] -= 0.1*2; h[1] += 0.36*2; */ h[0] -= 0.2; h[2] = lerp(cgi.FLOOR, cgi.WALL, (ilerp(0.00577916, -0.01166, h[2])/3 + 1.05) * hmul / 2); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } cheesemodel(string a, string b) : model(a,b) {} }; cheesemodel cheese("rogueviz/models/", "cheese.obj"); struct coffeemodel : public model { int cid; hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h[0] += 0.00077; h[1] += 0.011; h[0] *= 200; h[1] *= 200; if(cid == 1) h[0] += 0.3; if(cid == 2) h[1] += 0.5; h[2] = lerp(cgi.FLOOR, cgi.WALL, (ilerp(-0.0083, -0.0089, h[2])) * 1.2 / 10 + .51); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } coffeemodel(string a, string b, int _id) : model(a,b), cid(_id) {} }; /* need different file names */ coffeemodel coffee1("rogueviz/models/", "coffee.obj", 1), coffee2("rogueviz/models/", "./coffee.obj", 2); struct lilymodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h[0] += 0.67; h[1] -= 0.36; h[0] *= 5; h[1] *= 5; h[2] = lerp(cgi.LAKE, cgi.FLOOR, ilerp(0.018, -0.0496, h[2]) * hmul); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } lilymodel(string a, string b) : model(a,b) {} }; lilymodel lily("rogueviz/models/", "lily.obj"); struct duckmodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h[0] += 3.8; h[1] -= 2; h[2] = lerp(cgi.LAKE, cgi.FLOOR, ilerp(0.056, -0.408, h[2]) * hmul * 1.5); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } duckmodel(string a, string b) : model(a,b) {} }; duckmodel duck("rogueviz/models/", "duck.obj"); struct ratmodel : public model { hyperpoint transform(hyperpoint h) override { h = cspin90(1, 2) * h; h[0] *= 100; h[1] *= 100; h[2] *= 100; h[0] /= 3 * 3; h[1] /= 3 * 3; h[2] /= 3 * 3; h = cspin(0, 1, 135._deg) * h; h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(1/9., 1/9. - 1.2, h[2]) * hmul); if(GDIM == 3) h = cgi.emb->logical_to_actual(h); else h[2] = 1; return h; } ratmodel(string a, string b) : model(a,b) {} }; ratmodel rat("rogueviz/models/", "spinning-rat.obj"); bool hedge_constructed = false; const int hx = 7; array hedge_visited; array hdirs = {1, hx, hx*hx, -1, -hx, -hx*hx}; array, hx*hx*hx> hedge_dirs; int hstart; void construct_hedge() { for(int x=0; x inorder = {hstart}; for(int i=0; i 0 && co == hx-1) continue; if(hedge_visited[at+hdirs[dir]]) continue; hedge_visited[at+hdirs[dir]] = true; hedge_dirs[at].push_back(dir); inorder.push_back(at+hdirs[dir]); } } /* int qty = hx*hx*hx-1; while(qty > 0) { int at = hrand(hx*hx*hx); if(!hedge_visited[at]) continue; int dir = hrand(6); int co = (at / abs(hdirs[dir])) % hx; if(hdirs[dir] < 0 && co == 0) continue; if(hdirs[dir] > 0 && co == hx-1) continue; if(hedge_visited[at+hdirs[dir]]) continue; hedge_visited[at+hdirs[dir]] = true; hedge_dirs[at].push_back(dir); qty--; } */ } void add_oct(transmatrix T, int idx, int face, ld len) { array p; for(int i=0; i<3; i++) { p[i] = C03; p[i][i] = ((face>>i)&1) ? len/2 : -len/2; p[i] = cgi.emb->logical_scaled_to_intermediate * p[i]; } hyperpoint c = (p[0] + p[1] + p[2]) / 3; for(int f=0; f<3; f++) { hyperpoint a = p[f] - c; hyperpoint b = p[(f+1)%3] - c; texture_order([&] (ld x, ld y) { hyperpoint h = c + a * x + b * y; hyperpoint t = T * cpush(0, h[0]) * cpush(1, h[1]) * cpush(2, h[2]) * C0; cgi.hpcpush(t); }); } if(true) for(auto d: hedge_dirs[idx]) { hyperpoint h = C0; h[d%3] = (d<3 ? -len: len); h = cgi.emb->logical_scaled_to_intermediate * h; transmatrix T1 = T; for(int i=0; i<3; i++) if(h[i]) T1 = T1 * cpush(i, h[i]); add_oct(T1, idx + hdirs[d], face, len); } } void create_hedge(model_data& md) { if(!hedge_constructed) construct_hedge(); hyperpoint start = cgi.emb->logical_to_actual(point31(0, 0, cgi.FLOOR)); hyperpoint npt = cgi.emb->logical_to_actual(point31(0.01, 0, cgi.FLOOR)); transmatrix S = cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point31(0, 0, cgi.emb->center_z() + cgi.FLOOR)); ld len = hdist(start, npt) * 100 / 7; len *= 3; if(vid.wall_height < 0) len = -len; md.objs.resize(8); for(int i=0; i<8; i++) { md.objs[i] = make_shared (); auto& obj = *md.objs[i]; obj.color = 0xFF00FF; if(i & 1) obj.color ^= 0x200000; if(i & 2) obj.color ^= 0x20000000; if(i & 4) obj.color ^= 0x2000; cgi.bshape(obj.sh, PPR::FLOOR_DRAGON); cgi.last->flags |= POLY_TRIANGLES; cgi.last->texture_offset = 0; cgi.last->tinf = &obj.tv; obj.tv.texture_id = floor_textures->renderedTexture; add_oct(S * lzpush(-len/2), hstart, i, len); cgi.finishshape(); bind_floor_texture(obj.sh, cgi.shFeatherFloor.id); } cgi.extra_vertices(); } void draw_hedge(const shiftmatrix& V) { auto& md = (unique_ptr&) cgi.ext["hedge"]; if(!md) { md = std::make_unique(); create_hedge(*md); } md->render(V); } void fat_line(const shiftmatrix& V1, const hyperpoint h1, const shiftmatrix& V2, const hyperpoint h2, color_t col, int prec, ld lw) { dynamicval df(fat_edges, true); dynamicval dlw(vid.linewidth, lw); gridline(V1, h1, V2, h2, col, prec); } int scaffoldx = 0, scaffoldy = 0, scaffoldb = 0, scaffoldx_move = 0, scaffoldy_move; template void draw_map54(const shiftmatrix& S, const T& f, color_t col) { for(auto p: map54_nodes) queuepoly(S * rgpushxto0(f(p)), cgi.shSnowball, 0xFFFFFFFF); for(auto& p: map54_edges) fat_line(S, f(p.first), S, f(p.second), (abs(p.first[1])<1e-3 && abs(p.second[1])<1e-3 && scaffoldx && scaffoldy) ? 0xFFFFFFFF : col, 2, 0.01); } void draw_scaffold(const shiftmatrix& V) { ld levz = log(2); if(nih) levz = 1; ld levx = 1; if(hyperbolic) levx = exp(-cgi.FLOOR); levx *= 5; if(scaffoldx == 1) for(int z=-5; z<=5; z++) for(int s=-20; s<=20; s++) { shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(s*levx,0,0)); queuepoly(S, cgi.shSnowball, 0xFFFFFFFF); fat_line(S, C0, S, lzpush(-levz) * C0, (s == 0 && scaffoldy) ? 0xFFFFFFFF : 0xFF0000FF, 2, 0.01); for(int s=0; s<8; s++) fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+0)/8.,0,0)) * C0, S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+1)/8.,0,0)) * C0, 0x8000FFFF, 2, 0.01); } if(scaffoldx == 2) { if(hyperbolic) { draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(h[1],0,0)) * zpush(h[0]) * C0; }, 0xFFD500FF); } if(sol) { draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(h[1],0,0)) * zpush(-h[0]) * C0; }, 0xFFD500FF); } if(nih) { draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(-h[1]/log(2),0,0)) * zpush(h[0]/log(2)) * C0; }, 0xFFD500FF); } } ld levy = 5; if(scaffoldy == 1) for(int z=-5; z<=5; z++) for(int s=-20; s<=20; s++) { shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,s*levy,0)); queuepoly(S, cgi.shSnowball, 0xFFFFFFFF); fat_line(S, C0, S, lzpush(sol ? levz : -levz) * C0, (s == 0 && scaffoldx) ? 0xFFFFFFFF : 0x0000FFFF, 2, 0.01); for(int s=0; s<8; s++) fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0, levy*(s+0)/8.,0)) * C0, S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0, levy*(s+1)/8.,0)) * C0, 0x0080FF, 2, 0.01); } if(scaffoldy == 2) { if(hyperbolic) { draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1],0)) * zpush(h[0]) * C0; }, 0x80D500FF); } if(sol) { draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1],0)) * zpush(h[0]) * C0; }, 0x80D500FF); } if(nih) { draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1]/log(3),0)) * zpush(h[0]/log(3)) * C0; }, 0x80D500FF); } } if(scaffoldb == 1) for(int z=-5; z<=5; z++) for(int sx=-5; sx<=5; sx++) for(int sy=-5; sy<=5; sy++) { shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(sx*levx,sy*levy,0)); queuepoly(S, cgi.shSnowball, 0xFFFFFFFF); fat_line(S, C0, S, lzpush(-levz) * C0, 0xFF0000FF, 2, 0.01); for(int s=0; s<8; s++) { fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+0)/8.,0,0)) * C0, S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+1)/8.,0,0)) * C0, 0xFF8000FF, 2, 0.01); fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,levy*(s+0)/8.,0)) * C0, S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,levy*(s+1)/8.,0)) * C0, 0xFF8000FF, 2, 0.01); } } if(scaffoldb == 2 && hyperbolic) { for(auto h: map534_nodes) queuepoly(V * rgpushxto0(h), cgi.shSnowball, 0xFFFFFFFF); for(auto h: map534_edges) fat_line(V, h.first, V, h.second, 0xFFFFFFFF, 2, 0.01); } } string fixed_random_digits = "1100002102001211"; void draw_shape(const shiftmatrix& V, vector tab, color_t col, ld mul = 1) { int n = isize(tab); for(int i=0; iitem == itHyperstone) c->item = itNone; if(false) { if(c == cwt.at) chess.render(V); } else { auto co = euc::full_coords2(c); char& chr = xmap[gmod(co.second, 20)][gmod(co.first, 20)]; char ch = chr; if(no_floor && ch != '^') ch = '<'; // if(co.first == 0 && co.second == 0) bunny.render(V); switch(ch) { case 'r': if(GDIM == 3 && with_models) { rat.render(V); } else { drawMonsterType(moMouse, c, V * spin(-135._deg), 0x804000, 0, 0x804000); } break; case '<': c->wall = waChasm; house1.erase(c); house2.erase(c); fat_line(V, cgi.emb->logical_to_actual(point31(0.5, 0.5, 0)), V, cgi.emb->logical_to_actual(point31(0.5, -0.5, 0)), 0xFFFFFFFF, 2, 0.001); fat_line(V, cgi.emb->logical_to_actual(point31(0.5, 0.5, 0)), V, cgi.emb->logical_to_actual(point31(-0.5, 0.5, 0)), 0xFFFFFFFF, 2, 0.001); break; case 'u': { if(!cgtrader_models) break; if(GDIM == 3 && with_models) { lily.render(V); c->item = itNone; } else c->item = itWet; break; } case 'v': { if(!cgtrader_models) break; if(GDIM == 3 && with_models) duck.render(V); else { draw_shape(V, {-0.164988, 0.0033671, -0.114197, 0.0638159, 0.0401905, 0.063635, 0.10735, 0.0268375, 0.10735, -0.0268375, 0.0401905, -0.063635, -0.114197, -0.0638159, -0.164988, -0.0033671, }, 0xC0C0C0FF, 2); draw_shape(V, {-0.0753584, 0.00669852, -0.111558, 0.0184533, -0.0812589, 0.0326711, -0.161669, 0.0479953, -0.10074, 0.0780737, -0.0184331, 0.0896519, 0.0830064, 0.065399, 0.113269, 0.0335611, 0.117466, 0.0151028, 0.117466, -0.0151028, 0.113269, -0.0335611, 0.0830064, -0.065399, -0.0184331, -0.0896519, -0.10074, -0.0780737, -0.161669, -0.0479953, -0.0812589, -0.0326711, -0.111558, -0.0184533, -0.0753584, -0.00669852, }, 0x806010FF, 2); draw_shape(V, {0.164139, 0.0109426, 0.200142, 0.0185786, 0.239985, 0.00848005, 0.239985, -0.00848005, 0.200142, -0.0185786, 0.164139, -0.0109426, }, 0xE0E000FF, 2); draw_shape(V, {0.0820785, 0.00670028, 0.0963908, 0.0243072, 0.121722, 0.0352575, 0.159071, 0.0361908, 0.183838, 0.028672, 0.199268, 0.00844354, 0.199268, -0.00844354, 0.183838, -0.028672, 0.159071, -0.0361908, 0.121722, -0.0352575, 0.0963908, -0.0243072, 0.0820785, -0.00670}, 0x106010FF, 2); } break; } case 'B': if(GDIM == 3 && with_models) bunny.render(V); else { auto V1 = V * spin270(); draw_shape(V1, {-0.272437, 0.00681093, -0.247911, 0.0339604, -0.199391, 0.0506926, -0.165034, 0.0336804, -0.151363, 0.0100908, -0.151363, -0.0100908, -0.165034, -0.0336804, -0.199391, -0.0506926, -0.247911, -0.0339604, -0.272437, -0.00681093, }, 0xFFFFFFFF, 2); draw_shape(V1, {-0.209613, 0.00676172, -0.161797, 0.0741567, -0.107602, 0.100877, 0.0033535, 0.103959, 0.100724, 0.0738645, 0.134426, 0.0369672, 0.14796, 0.00672545, 0.14796, -0.00672545, 0.134426, -0.0369672, 0.100724, -0.0738645, 0.0033535, -0.103959, -0.107602, -0.100877, -0.161797, -0.0741567, -0.209613, -0.00676172, }, 0xC0C0C0FF, 2); draw_shape(V1, {0.0502023, 0.0167341, 0.0737312, 0.0536227, 0.151647, 0.0876183, 0.240969, 0.0441211, 0.272441, 0.0102165, 0.272441, -0.0102165, 0.240969, -0.0441211, 0.151647, -0.0876183, 0.0737312, -0.0536227, 0.0502023, -0.0167341, }, 0xD0D0D0FF, 2); draw_shape(V1, {0.103977, 0.0268328, 0.0267753, 0.0468568, -0.0536042, 0.063655, -0.00335237, 0.0972189, 0.094003, 0.080574, 0.144678, 0.0571982, 0.154836, 0.0437579, 0.134405, 0.0268809, }, 0xC0C0C0FF, 2); draw_shape(V1 * MirrorY, {0.103977, 0.0268328, 0.0267753, 0.0468568, -0.0536042, 0.063655, -0.00335237, 0.0972189, 0.094003, 0.080574, 0.144678, 0.0571982, 0.154836, 0.0437579, 0.134405, 0.0268809, }, 0xC0C0C0FF, 2); draw_shape(V1, {0.168425, 0.0235794, 0.178774, 0.0505965, 0.188982, 0.0269974, }, 0xC00000FF, 2); draw_shape(V1 * MirrorY, {0.168425, 0.0235794, 0.178774, 0.0505965, 0.188982, 0.0269974, }, 0xC00000FF, 2); } break; case 't': if(!cgtrader_models) break; if(GDIM == 2) c->wall = waRoundTable; else if(with_models && !light_models) { c->wall = waNone; table.render(V); cheese.render(V); coffee1.render(V); coffee2.render(V); } break; case 'C': if(GDIM == 3 && with_models) maxwellcat.render(V); else { dynamicval b(mapeditor::drawplayer, true); drawPlayer(moPlayer, c, V * spin90(), 0xFFFFFFFF, 0); } if(move_cat) { move_cat = false; mapeditor::drawplayer = true; chr = '.'; cwt.at = c; vid.sspeed = -5; cwt.spin = 1; vid.axes = 0; } break; case 'e': if(!cgtrader_models) break; if(GDIM == 3 && draw_digger == 2) digger.render(V); break; case 'K': { if(!cgtrader_models) break; int a = gmod(co.first + co.second, 3); if(GDIM == 3 && with_models) { auto gtulip = [&] (int a, int b) -> tulipmodel& { char ch = fixed_random_digits[5*a+b]; if(ch == '0') return tulip; if(ch == '1') return tulip1; if(ch == '2') return tulip2; return tulip2; }; gtulip(a, 0).render(V); gtulip(a, 1).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(1/3., 1/3., 0))); gtulip(a, 2).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(1/3., -1/3., 0))); gtulip(a, 3).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(-1/3., 1/3., 0))); gtulip(a, 4).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(-1/3., -1/3., 0))); } else { vector tcols = {0xFFFF80FF, 0xFF1010FF, 0xC000C0FF}; draw_shape(V*spin90(), {-0.202738, 0.0236527, -0.145213, 0.135082, -0.0438177, 0.1719, 0.0708783, 0.178883, 0.220846, 0.125712, 0.120989, 0.0705769, 0.219991, 0.00338448, 0.219991, -0.00338448, 0.120989, -0.0705769, 0.220846, -0.125712, 0.0708783, -0.178883, -0.0438177, -0.1719, -0.145213, -0.135082, -0.202738, -0.0236527}, tcols[a], 2); } break; } case 'H': if(GDIM == 3) draw_hedge(V); else queuepoly(V, cgi.shGem[0], 0xFF00FF); break; case '^': { c->wall = no_floor ? waChasm : waNone; auto ax = co.first - scaffoldx_move * 20; auto ay = co.second - scaffoldy_move * 20; if(ax >= 0 && ay >= 0 && ax < 20 && ay < 20) draw_scaffold(V); break; } case '>': c->wall = draw_digger ? waChasm : waNone; break; } if(with_chess) chess.get_split().render(V, gmod(co.first, 20), gmod(co.second, 20)); } return false; } ld fov, otanfov; void switch_fpp_fixed() { auto& cd = current_display; transmatrix tView; ld ys; tView = View; otanfov = (cd->xsize/2) / cd->radius * 2; auto d = vid.depth; if(GDIM == 3) invoke_embed(geom3::seNone); else { invoke_embed(geom3::seDefault); activate(edefault); } if(GDIM == 3) { ld tfov = vid.fov * degree / 2; cd->tanfov = tan(tfov); ld yshift = (otanfov - vid.depth) / cd->tanfov; println(hlog, "yshift = ", yshift, " from ", vid.yshift); View = Id; for(int a=0; a<2; a++) for(int b=0; b<2; b++) View[a][b] = tView[a][b]; for(int a=0; a<2; a++) View[a][3] = tView[a][2]; println(hlog, tie(tView[2][0], tView[2][1])); shift_view(zpush0(yshift)); playermoved = false; } else { pconf.cam() = Id; vid.yshift = 0; ys = tView[2][3]; println(hlog, "ys = ", ys, " from ", tView); otanfov = ys * cd->tanfov + d; cd->radius = cd->xsize / otanfov; pconf.scale = cd->radius / cd->scrsize; } if(GDIM == 2) { View = spin90() * View; View[0][2] = tView[0][3]; View[1][2] = tView[1][3]; } } void load_anim(string fname) { fhstream f(fname, "r"); mapstream::cellbyid = ac; while(isize(mapstream::cellbyid) < 400 * 400) for(auto c: ac) mapstream::cellbyid.push_back(c); smoothcam::enable(); smoothcam::load_animation(f); } void append_anim(string fname) { smoothcam::backup(); load_anim(fname); smoothcam::append_backup(); } void save_anim(string fname) { fhstream f(fname, "w"); for(int i=0; ic); if(co == gp::loc{0, 0}) draw_star(cw->V, cgi.shSun, 0xFFFF00FF); if(house2.count(cw->c)) { color_t col = (domcol << 8) | 0xFF; color_t wcol1 = (gradient(0, domcol, 0, .9, 1) << 8) | 0xFF; color_t wcol2 = (gradient(0, domcol, 0, .8, 1) << 8) | 0xFF; if(house1.count(cw->c)) forCellIdEx(c2, i, cw->c) if(!house1.count(c2)) { placeSidewall(cw->c, i, SIDE_HIGH, cw->V, (i&1)?wcol1:wcol2); placeSidewall(cw->c, i, SIDE_HIGH2, cw->V, (i&1)?wcol1:wcol2); } forCellIdEx(c2, i, cw->c) if(!house2.count(c2)) { placeSidewall(cw->c, i, SIDE_HIGH2, cw->V, (i&1)?wcol1:wcol2); } if(house1.count(cw->c) != house2.count(cw->c)) draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE_HIGH], col, PPR::REDWALL); if(house2.count(cw->c)) draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE_HIGH2], (domroof << 8) | 0xFF, PPR::REDWALL); auto co = euc::full_coords2(cw->c); int x = gmod(co.first, 20); int y = gmod(co.second, 20); char ch = xmap[y][x]; if(ch == 'O') { placeSidewall(cw->c, 1, SIDE_HIGH, cw->V, 0xC0E0FFC0); ((dqi_poly&)(*ptds.back())).tinf = nullptr; } } color_t skycol = our_skycolor(cw->c); g_add_to_sky(cw->c, cw->V, skycol, skycol); return true; } int cells_drawn = 50, split_qty = 1; void build_map() { for(cell *c: bac) { c->land = laCanvas; c->wall = waNone; // Chasm; // waNone; c->item = itNone; c->monst = moNone; c->mpdist = 0; c->landparam = 0x205020; auto co = euc::full_coords2(c); int x = gmod(co.first, 20); int y = gmod(co.second, 20); ac[x + 20*y + gmod(gdiv(co.first, 20), periods) * 400 + gmod(gdiv(co.second, 20), periods) * 400 * periods] = c; char ch = xmap[y][x]; switch(ch) { case 'x': c->landparam = ((x+y) & 1) ? 0x807020 : 0xFFE080; break; case '1': c->wall = waRed3; house2.insert(c); c->landparam = domcol; break; case '2': c->wall = waRed2; break; case '3': c->wall = waRed3; break; case '#': c->wall = waBarrier; break; case 'T': c->wall = waCTree; break; case 'D': c->wall = waWaxWall; house1.insert(c); house2.insert(c); c->landparam = domcol; break; case 't': case 'r': case 'd': c->wall = waNone; house2.insert(c); c->landparam = domcolf; break; case '+': c->wall = waNone; house2.insert(c); c->landparam = domcol; break; case 'O': c->wall = waWaxWall; house2.insert(c); c->landparam = domcol; break; case 'u': case 'v': case '~': c->wall = waShallow; break; case 'p': c->land = laCrossroads; floorcolors[laCrossroads] = 0x808080; break; // c->landparam = 0xC0C080; case '>': if(draw_digger) c->wall = waChasm; break; } } } ld square_diagram_size = 1000; void enable_square_diagram() { rogueviz::rv_hook(hooks_frame, 100, [] { if(square_diagram_size >= 1000) return; auto p = [] (ld x, ld y) { return hpxy(x, y); }; for(int i=0; i<4; i++) { ld si = square_diagram_size; ld big = 100; curvepoint(p(si, big)); curvepoint(p(si, -big)); curvepoint(p(big, -big)); curvepoint(p(big, big)); curvepoint(p(si, big)); queuecurve(shiftless(Id) * cspin(0, 1, i*90._deg), 0, 0xFF, PPR::CIRCLE).flags |= POLY_ALWAYS_IN; } }); } bool activated = false; void o_key(o_funcs& v); void build() { auto& T0 = euc::eu_input.user_axes; T0[0][0] = 20 * periods; T0[1][1] = 20 * periods; euc::eu_input.twisted = 0; T0[0][1] = 0; T0[1][0] = 0; euc::build_torus3(); geometry = gEuclidSquare; variation = eVariation::pure; start_game(); bac = currentmap->allcells(); ac.resize(bac.size()); build_map(); } void enable() { if(activated) return; tour::slide_backup(activated, true); if(!params.count("square_diagram_size")) param_f(square_diagram_size, "square_diagram_size"); stop_game(); tour::slide_backup(never_invert, true); tour::slide_backup(vid.wallmode, 3); tour::slide_backup(vid.monmode, 2); geometry = gArchimedean; variation = eVariation::pure; arcm::current.parse("4^5"); start_game(); resetview(); View = spin(45._deg); if(1) { dynamicval d(min_cells_drawn, cells_drawn); // vid.cells_generated_limit = 9999; // vid.cells_drawn_limit = 9999; // vid.use_smart_range = 2; drawthemap(); } auto f = [] (hyperpoint h) { return deparabolic13(h); }; set seen; for(auto c: dcal) if(gmatrix.count(c)) { map54_nodes.push_back(f(unshift(gmatrix[c]*C0))); seen.insert(c); } for(auto c: dcal) if(seen.count(c)) forCellEx(c1, c) if(seen.count(c1)) if(c1 hs(qty+1); hs[0] = h; hs[qty] = h1; for(int a=qty/2; a; a/=2) for(int i=0; i dg(geometry, gSol); dynamicval dr(nisot::rk_steps, 500); ld x = coord; start = C0; middle = point31(0, x, 0); auto bmiddle = point31(x, 0, 0); target = point31(x, x, 0); nlh = inverse_exp_newton(target, 200); nlh[2] *= -1; println(hlog, "best newton: ", hypot_d(3, nlh), " via ", nlh, " result ", nisot::numerical_exp(nlh)); nlh1 = inverse_exp(shiftless(middle)); nlh2 = inverse_exp(shiftless(bmiddle)); println(hlog, "intermediate: ", hypot_d(3, nlh1) * 2, " via ", nlh1); println(hlog, "Pythagoras: ", x * sqrt(2)); } add_stat(mode, [id, coord] { cmode |= sm::SIDE; calcparam(); vid.cells_drawn_limit = 0; drawthemap(); // flat_model_enabler fme; initquickqueue(); solv_grapher g(MirrorZ * ypush(5 * angle / 90._deg) * cspin(1, 2, .9 * angle / 90._deg) * spin(angle/2) * xyzscale(lerp(1, 0.8, angle / 90._deg))); ld maxtime = 10 * sqrt(2) + 5; auto frac_of = [&] (ld t, ld z) { return t - z * floor(t/z); }; ld t = inHighQual ? geodesic_t : frac_of((ticks - geo_zero) / 500, maxtime); auto draw_path = [&] (auto f, color_t col) { vid.linewidth *= 10; for(ld t=0; t<=maxtime; t+=1/16.) curvepoint(f(t)); queuecurve(g.T, col, 0, PPR::LINE); auto be_shadow = [&] (hyperpoint& h) { // ld part = 1 - angle / 90._deg; // h[0] += h[2] * part / 10; h[2] = 0; }; for(ld t=0; t<=25; t+=1/16.) { hyperpoint h = f(t); be_shadow(h); curvepoint(h); } queuecurve(g.T, col & 0xFFFFFF40, 0, PPR::LINE); vid.linewidth /= 10; hyperpoint eaglepos = f(t); hyperpoint next_eaglepos = f(t + 1e-2); auto z = eaglepos[2]; // queuepolyat(g.pos(x+z * .1,y,1.5) * spin(s), cgi.shEagle, 0x40, PPR::MONSTER_SHADOW).outline = 0; drawMonsterType(moEagle, nullptr, g.T * eupush(eaglepos) * solvscale(z) * rspintox(next_eaglepos - eaglepos) * xyzscale(2), col >> 8, t, 0); be_shadow(eaglepos); be_shadow(next_eaglepos); auto& bp = cgi.shEagle; if(bp.she > bp.shs && bp.she < bp.shs + 1000) { auto& p = queuepolyat(g.T * eupush(eaglepos) * solvscale(z) * rspintox(next_eaglepos - eaglepos) * xyzscale(2), bp, 0x18, PPR::TRANSPARENT_SHADOW); p.outline = 0; p.subprio = -100; p.offset = bp.shs; p.cnt = bp.she - bp.shs; p.flags &=~ POLY_TRIANGLES; p.tinf = NULL; return; } }; color_t pythagoras = 0xcd7f32FF; color_t hyperb = 0xaaa9adFF; color_t solv = 0xFFD500FF; write_in_space(g.T * rgpushxto0(point31(-.5, -.5, 1)) * MirrorY * zpush(-1), 72, 1, "A", 0xFF); write_in_space(g.T * rgpushxto0(point31(coord+.5, coord+.5, 1)) * MirrorY * zpush(-1), 72, 1, "B", 0xFF); if(id >= 1) write_in_space(g.T * rgpushxto0(point31(0, coord+.5, 1)) * MirrorY * zpush(-1), 72, 1, "C", 0xFF); if(id >= 0) draw_path([&] (ld t) { return t < coord * sqrt(2) ? point31(t/sqrt(2), t/sqrt(2), 0) : target; }, pythagoras); if(id >= 1) draw_path([&] (ld t) { ld len = hypot_d(3, nlh1); dynamicval g(geometry, gSol); if(t < len) return nisot::numerical_exp(nlh1 * t / len); else if(t < len*2) return rgpushxto0(middle) * nisot::numerical_exp(nlh2 * (t-len) / len); else return target; }, hyperb); if(id >= 2) draw_path([&] (ld t) { ld len = hypot_d(3, nlh); dynamicval g(geometry, gSol); if(t < len) return nisot::numerical_exp(nlh * t / len); else return target; }, solv); auto cat = [] (PPR x) { if(x == PPR::MONSTER_SHADOW) return 1; else if(x == PPR::MONSTER_BODY) return 2; else return 0; }; for(int i=1; iprio) < cat(ptds[i-1]->prio)) { swap(ptds[i], ptds[i-1]); i--; } else i++; quickqueue(); dialog::init(); dialog_may_latex("\\textsf{from $(0,0,0)$ to $(10,10,0)$}", "from (0,0,0) to (10,10,0)", forecolor, 150); dialog::addBreak(100); dialog_may_latex("\\textsf{XY plane}", "XY plane", pythagoras >> 8); dialog_may_latex("\\textsf{$"+fts(coord)+"\\sqrt{2}$ (Pythagoras)}", fts(coord) + "√2 (Pythagoras)", pythagoras >> 8); ld len = coord * sqrt(2); dialog_may_latex("\\textsf{$" + fts(len) + "$}", fts(len), pythagoras >> 8); if(id >= 1) { dialog::addBreak(100); dialog_may_latex("\\textsf{YZ + XZ}", "YZ + XZ", hyperb >> 8); dialog_may_latex("\\textsf{hyperbolic geodesics}", "hyperbolic geodesics", hyperb >> 8); ld len = 2 * hypot_d(3, nlh1); dialog_may_latex("\\textsf{$" + fts(len) + "$}", fts(len), hyperb >> 8); } else dialog::addBreak(300); if(id >= 2) { dialog::addBreak(100); dialog_may_latex("\\textsf{optimal}", "optimal", solv >> 8); dialog_may_latex("\\textsf{no sharp bends}", "no sharp bends", solv >> 8); ld len = hypot_d(3, nlh); dialog_may_latex("\\textsf{$"+fts(len)+"$}", fts(len), solv >> 8); } else dialog::addBreak(300); dialog::display(); return false; }); } using namespace rogueviz::pres; string defs = "\\def\\map{m}" "\\def\\VofH{V}" "\\def\\dist{\\delta}" "\\def\\ra{\\rightarrow}" "\\def\\bbH{\\mathbb{H}}" "\\def\\bbE{\\mathbb{E}}" "\\renewcommand{\\rmdefault}{\\sfdefault}\\sf" ; void act_or_config() { if(activated) pushScreen(show); else { enable(); popScreenAll(); mapeditor::drawplayer = false; } } slide embchess_slides[] = { {"3D world", 999, LEGAL::NONE | QUICKGEO | QUICKSKIP | USE_SLIDE_NAME, "This is the world from our YouTube video 'Non-Euclidean Third Dimension'. " "You can activate it by pressing '5', and then press '5' again " "to access various options. The next slides are slides from that video.\n\n", [] (presmode mode) { setCanvas(mode, '0'); slide_url(mode, 'y', "YouTube link", "https://youtu.be/Rhjv_PazzZE"); slide_action(mode, 'a', "activate / configure", act_or_config); if(mode == pmKey) act_or_config(); }}, {"Euler's polyhedron formula", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, "This is a proof that a sphere cannot be tiled with squares.", [] (presmode mode) { latex_slide(mode, defs+R"=( {\color{remph}Euler's polyhedron formula: } \begin{itemize} \item $F+V-E = 2$ \item $F$ -- the number of {\color{remph}faces} (square grid: the number of squares $n$) \item $V$ -- the number of {\color{remph}vertices} (square grid: also $n$) \item $E$ -- the number of {\color{remph}edges} (square grid: $2n$) \item $F + V - E = n + n - 2n = 0 = 2$ \end{itemize} )=", sm::NOSCR, 150); }}, {"from A to B in Solv 1", 999, LEGAL::NONE | QUICKGEO | NOTITLE, "How to get from A to B in Solv as quickly as possible? The first attempt is to do so without leaving the plane. Since the XY plane in Solv has Euclidean geometry, we can compute the length of such a path using the Pythagoras theorem." "Press '5' to switch to the 3D view." , [] (presmode mode) { println(hlog, "A mode ", int(mode)); empty_screen(mode); geodesic_screen(mode, 0); no_other_hud(mode); } }, {"from A to B in Solv 2", 999, LEGAL::NONE | QUICKGEO | NOTITLE, "But we can do it faster like this, using two hyperbolic geodesics. " , [] (presmode mode) { println(hlog, "B mode ", int(mode)); empty_screen(mode); geodesic_screen(mode, 1); no_other_hud(mode); } }, {"from A to B in Solv 3", 999, LEGAL::NONE | QUICKGEO | NOTITLE, "And even faster, do it like this, avoiding sharp bends." , [] (presmode mode) { println(hlog, "C mode ", int(mode)); empty_screen(mode); geodesic_screen(mode, 2); no_other_hud(mode); } }, {"final slide", 123, LEGAL::ANY | NOTITLE | QUICKSKIP | FINALSLIDE, "End of the presentation.", [] (presmode mode) { } }, }; auto embchess_ah = /* enable this unit */ arg::add3("-embchess", enable) + arg::add3("-embperiods", [] { arg::shift(); periods = arg::argi(); }) + arg::add3("-emb-noceil", [] { rogueviz::rv_hook(hooks_ceiling, 100, [] (celldrawer*) { return true; }); }) + arg::add3("-chessmul", [] { arg::shift(); hmul = arg::argf(); }) + arg::add3("-embset", [] { arg::shift(); string ss = arg::args(); for(auto& e: embsets) if(appears(e.name, ss)) activate(e); }) + arg::add3("-embscaffold", [] { arg::shift(); scaffoldx = arg::argi(); arg::shift(); scaffoldy = arg::argi(); arg::shift(); scaffoldb = arg::argi(); }) + arg::add3("-embscaffold-move", [] { arg::shift(); scaffoldx_move = arg::argi(); arg::shift(); scaffoldy_move = arg::argi(); }) + arg::add3("-embwchess", [] { with_chess = !with_chess; }) + arg::add3("-embfix", [] { arg::shift(); fix_chess = arg::argf(); }) + arg::add3("-embwmodel", [] { with_models = !with_models; }) + arg::add3("-embwmlight", [] { with_models = true; light_models = true; }) + arg::add3("-embwdig", [] { arg::shift(); draw_digger = arg::argi(); }) + arg::add3("-embload", [] { arg::shift(); load_anim(arg::args()); }) + arg::add3("-embappend", [] { arg::shift(); append_anim(arg::args()); }) + arg::add3("-embsave", [] { arg::shift(); save_anim(arg::args()); }) + arg::add3("-embt0", [] { smoothcam::animate_on = false; smoothcam::handle_animation(0); playermoved = false; }) + arg::add3("-embt1", [] { smoothcam::animate_on = false; smoothcam::handle_animation(1-1e-7); playermoved = false; }) + arg::add3("-embmin", [] { arg::shift(); cells_drawn = arg::argi(); }) + arg::add3("-emb-chess-moves", [] { arg::shift(); chess_moves = arg::argi(); }) + arg::add3("-emb-sqd", enable_square_diagram) #if CAP_VIDEO + arg::add3("-embtrans-test", [] { arg::shift(); transition_test(arg::argf()); }) #endif + arg::add3("-emb-no-floor", [] { no_floor = true; }) #if CAP_VIDEO + arg::add3("-embtrans", [] { arg::shift(); anims::videofile = arg::args(); arg::shift(); ld a = arg::argf(); arg::shift(); ld b = arg::argf(); arg::shift(); int t = arg::argi(); transition(a, b, t); }) #endif + arg::add3("-avp", [] { semidirect_rendering = true; vid.consider_shader_projection = false; }) #if CAP_VIDEO + arg::add3("-embforward", [] { arg::shift(); int t = arg::argi(); arg::shift(); anims::videofile = arg::args(); arg::shift(); ld d = arg::argf(); animate_forward(d, t); }) #endif + arg::add3("-emb-goforward", [] { arg::shift(); ld d = arg::argf(); for(int i=0; i<1000; i++) { shift_view(ztangent(-d / 1000.)); optimizeview(); spinEdge(100); } }); ; auto embchess_show = addHook_slideshows(100, [] (tour::ss::slideshow_callback cb) { cb(XLAT("non-Euclidean third dimension"), &embchess_slides[0], '3'); }); } }