// 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 { #if CAP_PORTALS 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(mhybrid && 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(mproduct) { 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"); ccolor::set_random(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"); ccolor::set_random(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 starter; bool vr_keys(int sym, int uni) { if(intra::in && !starter.count(intra::current)) starter[intra::current] = cwt.at; const Uint8 *keystate = SDL12_GetKeyState(NULL); #if CAP_SDL2 if(keystate[SDL_SCANCODE_LALT] || keystate[SDL_SCANCODE_RALT]) #else if(keystate[SDLK_LALT] || keystate[SDLK_RALT]) #endif { if(sym == 'e' && intra::in) { println(hlog, "intra::current = ", intra::current); intra::switch_to(2); if(starter.count(intra::current)) cwt.at = centerover = starter[intra::current]; fullcenter(); View = cspin90(0, 1); playermoved = false; walking::handle(); return true; } if(sym == 'h' && intra::in) { intra::switch_to(0); if(starter.count(intra::current)) cwt.at = centerover = starter[intra::current]; fullcenter(); View = cspin90(0, 1); playermoved = false; walking::handle(); return true; } if(sym == 's' && intra::in) { intra::switch_to(6); if(starter.count(intra::current)) cwt.at = centerover = starter[intra::current]; fullcenter(); View = cspin90(0, 1); playermoved = false; walking::handle(); return true; } if(sym == ',') { camera_speed *= 1.2; println(hlog, "camera_speed set to ", camera_speed); return true; } if(sym == '.') { camera_speed /= 1.2; println(hlog, "camera_speed set to ", camera_speed); return true; } #if CAP_VR if(sym == 'a') { vrhr::absolute_unit_in_meters *= 1.2; walking::eye_level *= 1.2; println(hlog, "vr absolute unit set to ", vrhr::absolute_unit_in_meters); return true; } if(sym == 'z') { vrhr::absolute_unit_in_meters /= 1.2; walking::eye_level /= 1.2; println(hlog, "vr absolute unit set to ", vrhr::absolute_unit_in_meters); return true; } #endif if(sym == 'w') { walking::switch_walking(); println(hlog, "walking set to ", ONOFF(walking::on)); return true; } #if CAP_VR if(sym == 'x') { vrhr::always_show_hud = false; return true; } #endif } return false; } // all generators will add to the current scene #if CAP_VR #define IF_VR(x) x #else #define IF_VR(x) #endif auto hooks = // generate scene with H3, H2xE, E3, S2xE (8x6), S3 (16-cell) with floors; runs automatically arg::add3("-intra-floors", create_intra_floors) + arg::add3("-check-shape", check_shape) // generate scene with H3 and Solv landscape, need X Y parameters, runs automatically + arg::add3("-intra-solv", create_intra_solv) // generate S2xE with triangles (-intra-start to run it) + arg::add3("-intra-120", create_intra_120) // generate S3 with triangles (-intra-start to run it) + arg::add3("-intra-1440", create_intra_1440) // generate binary-tiling H2xE with floors to the current scene, runs automatically + arg::add3("-intra-bxe", create_intra_bxe) // generate Sol with floors to the current scene, runs autimatically + arg::add3("-intra-sol", create_intra_sol) //+ arg::add3("-intra-more", create_intra_more); + arg::add3("-intra-demo-floors", [] { walking::colors_of_floors = { 0xFFFF40, 0xD0D000, 0xC0FFC0, 0x80C080, 0xC0FFFF, 0x40FFFF, 0x8080FF, 0x0000FF, 0xFF80FF, 0xFF00FF, 0x64BF95, 0xA4FFD5, 0xFFFDD0, 0xFFD080 }; }) + addHook_rvslides(10, ([] (string s, vector& 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_VR( slide_backup(vrhr::hsm, vrhr::eHeadset::holonomy); slide_backup(vrhr::eyes, vrhr::eEyes::truesim); slide_backup(vrhr::cscr, vrhr::eCompScreen::eyes); ) starter.clear(); rogueviz::rv_hook(hooks_handleKey, 101, vr_keys); popScreenAll(); resetGL(); }; }; struct loader { string desc; char key; reaction_t loader; }; auto add = [&] (string s, string desc, string youtube, string twitter, vector loaders) { 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"); for(auto& loader: loaders) slide_action(mode, loader.key, loader.desc, loader.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').\n\n" "In VR, you might want to prefer the VR version, which adds extra blocks to Solv to improve the performance.\n\n" "Note: this is a very complex shader, so compiling it may take long time!\n\n" "Hotkeys, mostly useful when showing VR to someone:\n\n" "Alt+EHS -- go to Euclidean/hyperbolic/spherical space, Alt+,. -- change the camera speed, Alt+AZ -- change altitude, Alt+W -- switch walking, Alt+X -- change HUD" , "https://youtu.be/yqUv2JO2BCs", "https://twitter.com/ZenoRogue/status/1496867204419452935", {loader{"run this visualization", 'r', load("portalscene3.lev", 0.2174492, 600)}, loader{"run this visualization (VR)", 'v', load("portalscene3-solv.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", {loader{"run this visualization", 'r', load("solv-h3-scene.lev", 0.05, 3000)}}); })); } #undef IF_VR #endif }