#include "rogueviz.h" // for this video: https://youtu.be/Rhjv_PazzZE namespace hr { /** 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; namespace smoothcam { using namespace rogueviz::smoothcam; } 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 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(); auto wh = vid.wall_height; 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(); if(vid.wall_height * wh < 0) View = MirrorY * View; pmodel = default_model(); }; embset 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{.name="default", .se=geom3::seDefault, .walls=1.2, .scale=0, .depth=0, .eye=1.5, .sun=0.333333, .sky=10, .star=9}; embset edefaulti = embset{.name="default", .se=geom3::seDefault, .walls=-1.2, .scale=0, .depth=0, .eye=-1.5, .sun=0.333333, .sky=10, .star=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{.name="in cylinder E", .se=geom3::seCylinderE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset eoutcyl = embset{.name="out cylinder E", .se=geom3::seCylinderE, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.3, .sky=10, .star=9}; embset eouthoro = embset{.name="out horosphere", .se=geom3::seLowerCurvature, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5}; embset einhoro = embset{.name="in horosphere", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; embset einhoro_small = embset{.name="in horosphere (small sky)", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=18, .star=17}; embset esolv = embset{.name="solv", .se=geom3::seSol, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; embset einnih = embset{.name="in NIH", .se=geom3::seNIH, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; embset eoutnih = embset{.name="out NIH", .se=geom3::seNIH, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5}; embset eclifford = embset{.name="Clifford", .se=geom3::seCliffordTorus, .walls=1.2, .scale=M_PI/10, .depth=-0.0561826, .eye=1.5, .sun=0.25, .sky=2.55, .star=2.3}; embset enil = embset{.name="Nil flat", .se=geom3::seNil, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; embset esl2 = embset{.name="SL(2,R) flat", .se=geom3::seSL2, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; embset eincylh = embset{.name="in cylinderH", .se=geom3::seCylinderH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset eincylhe = embset{.name="in cylinderHE", .se=geom3::seCylinderHE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset eincylnil = embset{.name="in cylinder Nil", .se=geom3::seCylinderNil, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset eincylsl = embset{.name="in cylinder SL(2,R)", .se=geom3::seCylinderSL2, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset einhorocyl = embset{.name="in horocylinder", .se=geom3::seCylinderHoro, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=8, .star=7.5}; embset eouthorocyl = embset{.name="out horocylinder", .se=geom3::seCylinderHoro, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.5}; embset eprodh_flat = embset{.name="hyperbolic product (flat)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset eprodh_concave = embset{.name="hyperbolic product (concave)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=1, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset eprods_flat = embset{.name="spherical product (flat)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; embset eprods_concave = embset{.name="spherical product (concave)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0.8333, .eye=1.5, .sun=0.10472, .sky=2.6, .star=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#"}, }; namespace embchess { void build_map(); ld hmul; set domek1, domek2; 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"); ld minz = 100, maxz = -100; ld minx = 100, maxx = -100; ld miny = 100, maxy = -100; 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[0] *= 400; h[1] *= 400; h[0] -= 0.1*2; h[1] += 0.36*2; */ 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[0] *= 400; h[1] *= 400; h[0] -= 0.1*2; h[1] += 0.36*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; if(h[2] < minz) minz = h[2]; if(h[2] > maxz) maxz = h[2]; if(h[0] < minx) minx = h[0]; if(h[0] > maxx) maxx = h[0]; if(h[1] < miny) miny = h[1]; if(h[1] > maxy) maxy = h[1]; 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); } hyperpoint inverse_exp_newton(hyperpoint h, int iter) { auto approx = inverse_exp(shiftless(h)); for(int i=0; i g(geometry, gCubeTiling); p = xpush(i * length / MAX_X) * cspin(1, 2, alpha) * ypush0(width*z); p = lT * p; } p = direct_exp(p); cgi.hpcpush(p); #if CAP_GL if(floor_textures) utt.tvertices.push_back(glhr::makevertex(0, true ? 0.549 - s * 0.45 * sin(alpha) : 0.999, 0)); #endif }; for(int i=0; iflags |= POLY_TRIANGLES | POLY_PRINTABLE; cgi.finishshape(); cgi.extra_vertices(); return pipe; } void fat_line(const shiftmatrix& V1, const hyperpoint h1, const shiftmatrix& V2, const hyperpoint h2, color_t col, int prec, ld lw) { if(nonisotropic) { auto nV1 = V1 * rgpushxto0(h1); hyperpoint U2 = inverse_shift(nV1, V2*rgpushxto0(h2)) * C0; auto& p = get_noniso_pipe(U2, lw, ePipeEnd::ball); queuepoly(nV1, p, col); return; } ld d = hdist(V1.T*h1, V2.T*h2); shiftmatrix T = V1 * rgpushxto0(h1); transmatrix S = rspintox(inverse_shift(T, V2) * h2); transmatrix U = rspintoc(inverse_shift(T*S, shiftless(C0)), 2, 1); auto& p = queuepoly(T * S * U, cgi.generate_pipe(d, lw, ePipeEnd::ball), col); p.intester = xpush0(d/2); } 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); } } /* static bool first = true; if(first) println(hlog, tie(minx, maxx), tie(miny, maxy), tie(minz, maxz)); first = false; */ string losowo = "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); static bool first = true; if(first) println(hlog, tie(minx, maxx), tie(miny, maxy), tie(minz, maxz)); first = false; } else { drawMonsterType(moMouse, c, V * spin(-135._deg), 0x804000, 0, 0x804000); } break; case '<': c->wall = waChasm; domek1.erase(c); domek2.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(GDIM == 3 && with_models) { lily.render(V); c->item = itNone; } else c->item = itWet; break; } case 'v': { 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(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(GDIM == 3 && draw_digger == 2) digger.render(V); break; case 'K': { int a = gmod(co.first + co.second, 3); if(GDIM == 3 && with_models) { auto gtulip = [&] (int a, int b) -> tulipmodel& { char ch = losowo[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) { // pconf.camera_angle = 90; ld tfov = vid.fov * degree / 2; cd->tanfov = tan(tfov); // tanfov * z + depth = fov // z = (fov - depth) / tanfov ld yshift = (otanfov - vid.depth) / cd->tanfov; // drawthemap(); // centerpc(INF); // shift_view(zpush0(yshift)); println(hlog, "yshift = ", yshift, " from ", vid.yshift); // playermoved = false; // vid.fov = fov; // vid.yshift = 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])); // rotate_view(cspin90(2, 1)); shift_view(zpush0(yshift)); playermoved = false; } else { pconf.camera_angle = 0; 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(domek2.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(domek1.count(cw->c)) forCellIdEx(c2, i, cw->c) if(!domek1.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(!domek2.count(c2)) { placeSidewall(cw->c, i, SIDE_HIGH2, cw->V, (i&1)?wcol1:wcol2); } if(domek1.count(cw->c) != domek2.count(cw->c)) draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE_HIGH], col, PPR::REDWALL); if(domek2.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; domek2.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; domek1.insert(c); domek2.insert(c); c->landparam = domcol; break; case 't': case 'r': case 'd': c->wall = waNone; domek2.insert(c); c->landparam = domcolf; break; case '+': c->wall = waNone; domek2.insert(c); c->landparam = domcol; break; case 'O': c->wall = waWaxWall; domek2.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; } } } void enable() { arg::shift(); hmul = arg::argf(); stop_game(); never_invert = true; vid.wallmode = 3; 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; }); } ld square_diagram_size = 10; void enable_square_diagram() { param_f(square_diagram_size, "square_diagram_size"); rogueviz::rv_hook(hooks_frame, 100, [] { 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; } }); } 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" ; slide solv_slides[] = { {"from A to B in Solv 1", 999, LEGAL::NONE | QUICKGEO | NOTITLE, "not written" , [] (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, "not written" , [] (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, "not written" , [] (presmode mode) { println(hlog, "C mode ", int(mode)); empty_screen(mode); geodesic_screen(mode, 2); no_other_hud(mode); } }, {"Euler's polyhedron formula", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, "-show the formula", [] (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); }}, {"final slide", 123, LEGAL::ANY | NOTITLE | QUICKSKIP | FINALSLIDE, "FINAL SLIDE", [] (presmode mode) { empty_screen(mode); add_stat(mode, [] { dialog::init(); color_t d = dialog::dialogcolor; dialog::addTitle("Thanks for your attention!", 0xC00000, 200); dialog::addBreak(100); dialog::addTitle("twitter.com/zenorogue/", d, 150); dialog::display(); return true; }); no_other_hud(mode); } }, }; auto embchess_ah = 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) + arg::add3("-embtrans-test", [] { arg::shift(); transition_test(arg::argf()); }) + arg::add3("-emb-no-floor", [] { no_floor = true; }) + 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); }) + arg::add3("-avp", [] { semidirect_rendering = true; vid.consider_shader_projection = false; }) + 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); }) + 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("Solv geodesics"), &solv_slides[0], 'S'); }); }}