// E3 -> H2xE -> Solv: // -run -debug-portal -1 -canvas-random 100 -geo beti -intra-add -intra-bxe 4 4 3 -intra-sol 4 4 3 -ray-do -noplayer // S2xE->S3: // -debug-portal -1 -run -canvas-random 0 -intra-120 -intra-add -intra-1440 -intra-start -ray-do #include "../rogueviz/rogueviz.h" namespace hr { namespace intraf { using namespace intra; void set_wall(cell *c, color_t col) { c->wall = waWaxWall; c->landparam = col; } map plane; cellwalker flatspin(cellwalker cw, int i) { if(hybri && cw.spin < cw.at->type - 2) cw.spin = gmod(cw.spin + (cw.mirrored ? -i : i), cw.at->type - 2); return cw; } cellwalker gstrafe(cellwalker cw, int i) { if(reg3::in()) return currentmap->strafe(cw, i); if(prod) { if(i == cw.at->type-2 || i == cw.at->type-1) return cellwalker(cw.at->move(i), cw.spin); else for(int k: {-1, 1}) if(i == flatspin(cw, k).spin) return cellwalker(cw.at->move(i), flatspin(flatspin(cw, k) + wstep, +k).spin); } if(euc::in()) return cellwalker(cw.at->move(i), cw.spin); throw hr_exception("unknown gstrafe"); } void make_plane(cellwalker cw, int d) { if(plane.count(cw)) return; plane[cw] = d; auto& ss = currentmap->get_cellshape(cw.at); for(int i=0; itype; i++) if(ss.dirdist[i][cw.spin] == 1) make_plane(gstrafe(cw, i), d+1); } void build_wall(cellwalker cw, color_t a, color_t b) { println(hlog, "trying to build wall in ", full_geometry_name()); cw += wstep; plane.clear(); make_plane(cw, 0); for(auto p: plane) set_wall(p.first.at, p. second & 1 ? a : b); println(hlog, "success, ", isize(plane)); } void check_shape() { start_game(); auto sh = currentmap->get_cellshape(cwt.at); int j = 0; for(auto f: sh.faces) { j++; for(int i=0; iallcells()) { println(hlog, currentmap->full_shvid(c), " : ", currentmap->get_corner(c, 0), currentmap->get_corner(c, 1), currentmap->get_corner(c, 2)); } hybrid::csteps = 10; set_geometry(gProduct); start_game(); vector bound; PIU( [&] { cell *s = currentmap->gamestart(); hyperpoint h = currentmap->get_corner(s, 1); for(cell *c: currentmap->allcells()) { hyperpoint j = currentmap->relative_matrix(c, s, C0) * C0; if(hdist(h, j) > 90._deg) c->wall = waPalace; } for(cell *c: currentmap->allcells()) if(c->wall == waPalace) { int nei = 0; forCellCM(c1, c) if(c1->wall != waPalace) nei++; if(nei == 1) bound.push_back(c); } auto ang = [&] (cell *c) { hyperpoint j = currentmap->relative_matrix(c, s, C0) * C0; j = gpushxto0(h) * j; return atan2(j[0], j[1]); }; for(cell *c: bound) println(hlog, "j= ", ang(c)); sort(bound.begin(), bound.end(), [&] (cell *a, cell *b) { return ang(a) < ang(b); }); int id = 0; for(auto b: bound) set_wall(b, ((id++)&1) ? 0xFFFFFF : 0x202020); } ()); for(int i=0; igamestart(); auto vs = currentmap->get_cellshape(s).vertices_only_local; println(hlog, vs); hyperpoint h = vs[1]; for(cell *c: currentmap->allcells()) { hyperpoint j = currentmap->relative_matrix(c, s, C0) * C0; // hyperpoint j = inverse(currentmap->relative_matrix(cwt.at, c, C0)) * C0; if(hdist(h, j) > 90._deg) set_wall(c, (celldistance(c, s)&1) ? 0xFF80FF : 0xFF00FF); } } void recurse(int r, cell *c, int i, int j) { setdist(c, 7, nullptr); forCellCM(c1, c) setdist(c1, 7, nullptr); c->wall = waNone; if(r == 1) { if(sol) { int flip = (j&2)>>1; set_wall(c->cmove(6^flip), 0xC000C0); set_wall(c->cmove(7^flip), 0x800080); } else { set_wall(c->cmove((j&1)), 0x64BF95); set_wall(c->cmove(1-(j&1)), 0x449F75); } } else { if(sol) { recurse(r-1, c->cmove(6), 2*i, j>>1); recurse(r-1, c->cmove(7), 2*i+1, j>>1); } else { recurse(r-1, c->cmove(0), i, j); recurse(r-1, c->cmove(1), i, j); } } } void connect_portal_x(cellwalker cw1, cellwalker cw2, int spin) { setdist(cw1.cpeek(), 7, nullptr); setdist(cw2.cpeek(), 7, nullptr); set_wall(cw1.cpeek(), 0xFF0000); set_wall(cw2.cpeek(), 0xFF0000); connect_portal(cw1, cw2, spin); } void recurse_portal(int r, cell *cl, cell *cr) { connect_portal_x(cellwalker(cl, 6), cellwalker(cr, 5), 3); if(r > 1) { recurse_portal(r-1, cl->cmove(0), cr->cmove(0)); recurse_portal(r-1, cl->cmove(1), cr->cmove(1)); } } vector portals; void create_intra_bxe() { println(hlog, "called create_intra_bxe"); patterns::whichCanvas = 'r'; patterns::rwalls = 100; if(intra::in) intra::become(); else stop_game(); hybrid::csteps = 0; arg::shift(); int x = arg::argi(); arg::shift(); int y = arg::argi(); arg::shift(); int z = arg::argi(); vector > h(y); for(int i=0; icmove(2); for(int i=0; icmove(5); println(hlog, h); for(int i=0; icmove(3), ((j+(i>>1))&1) ? 0xA4FFD5 : 0x64BF95); recurse(z, h[i][j], i, j); } become(); start(isize(intra::data)-1); for(int i=0; imove(0); cr = cr->move(1); } } } void recurse_portal_solv1(int r, cell *cl, cell *cr) { connect_portal_x(cellwalker(cl, 0), cellwalker(cr, 4), 0); if(r > 1) { recurse_portal_solv1(r-1, cl->cmove(6), cr->cmove(6)); recurse_portal_solv1(r-1, cl->cmove(7), cr->cmove(7)); } } void recurse_portal_solv2(int r, cell *cl, cell *cr) { connect_portal_x(cellwalker(cl, 1), cellwalker(cr, 5), 0); if(r > 1) { recurse_portal_solv2(r-1, cl->cmove(7), cr->cmove(6)); } } void create_intra_sol() { println(hlog, "called create_intra_sol"); patterns::whichCanvas = 'r'; patterns::rwalls = 100; if(intra::in) intra::become(); else stop_game(); arg::shift(); int x = arg::argi(); arg::shift(); int y = arg::argi(); arg::shift(); int z = arg::argi(); vector > h(y); for(int i=0; icmove(0); for(int i=0; icmove(1); for(int i=1; icmove(5); for(int i=0; icmove(4); for(int i=0; icmove(2^((i>>1)&1)), 0xFFFDD0); set_wall(h[i][j]->cmove(3^((i>>1)&1)), 0xFFE080); recurse(z, h[i][j], i, j); } become(); start(isize(intra::data)-1); for(int i=0; i& v) { println(hlog, "called with s='", s, "'"); if(s != "portal") return; using namespace tour; auto load = [] (string s, ld x, int y) { return [s, x, y] { slide_backup(vid.cells_drawn_limit, 100); slide_backup(ray::max_cells, 999999); slide_backup(walking::on, true); slide_backup(walking::eye_level, x); mapstream::loadMap(s); slide_backup(ray::fixed_map, true); slide_backup(ray::max_iter_intra, y); #if CAP_VR slide_backup(vrhr::hsm, vrhr::eHeadset::holonomy); slide_backup(vrhr::eyes, vrhr::eEyes::truesim); slide_backup(vrhr::cscr, vrhr::eCompScreen::eyes); #endif popScreenAll(); resetGL(); }; }; auto add = [&] (string s, string desc, string youtube, string twitter, reaction_t loader) { v.push_back(tour::slide{ s, 10, tour::LEGAL::NONE | tour::QUICKSKIP | tour::QUICKGEO | tour::ALWAYS_TEXT, desc, [=] (tour::presmode mode) { setCanvas(mode, '0'); if(youtube != "") slide_url(mode, 'y', "YouTube link", youtube); if(twitter != "") slide_url(mode, 't', "Twitter link", twitter); slide_url(mode, 'b', "Bridges paper link", "https://archive.bridgesmathart.org/2022/bridges2022-297.html"); slide_action(mode, 'r', "run this visualization", loader); slidecommand = "portal options"; if(mode == tour::pmKey) pushScreen(intra::show_portals); rogueviz::pres::non_game_slide_scroll(mode); } }); }; add("inter-geometric portals", "In this world we can find portals between six different geometries. The camera is in 'walking mode' i.e. restricted to keep close to the floor (this can be disabled with '5').", "https://youtu.be/yqUv2JO2BCs", "https://twitter.com/ZenoRogue/status/1496867204419452935", load("portalscene3.lev", 0.2174492, 600) ); add("curved landscape", "Here we create portals between Solv and H3 geometries, resulting in a scene looking a bit like a curved landscape.", "", "https://twitter.com/ZenoRogue/status/1446127100516130826", load("solv-h3-scene.lev", 0.05, 3000)); })); } }