#include "rogueviz.h" // Impossible Ring visualization // used in: // https://youtu.be/3WejR74o6II // https://youtu.be/ztodGQDK810 // usage: -cylon namespace rogueviz { namespace cylon { bool on; ld cscale = .2; ld cylball; struct iring { geometry_information *icgi; static const int frames = 32; static const int cols = 256; static const int steps = 2048; array, frames> ptriangle[2]; vector huess[2]; vector path; hpcshape ball; void init() { icgi = &cgi; unsigned difh = 256; int mh = 255; color_t base = 0xFF; auto& hues = huess[0]; for(unsigned y=0; y> 1) | 0xFF); ld delta = 0.004; transmatrix T = cspin(1, 2, 45*degree); int switchat = nil ? 1024 : 2048; auto step = [&] (int id) { ld alpha = id * 1. / steps * 2 * M_PI; if(id < switchat) return T * point3(cos(alpha) * delta, sin(alpha) * delta, 0); else return T * point3(cos(alpha) * delta, 0, sin(alpha) * delta); }; ld dmin = 0, dmax = 1; auto shift = [&] (ld d) { delta = d; hyperpoint start = C0; for(int a=0; aflags |= POLY_TRIANGLES; cgi.last->tinf = &floor_texture_vertices[0]; cgi.last->texture_offset = 0; cgi.finishshape(); cgi.extra_vertices(); } if(cylball) { ball.prio = PPR::WALL; cgi.make_ball(ball, cylball, 2); cgi.finishshape(); cgi.extra_vertices(); } } }; iring *ir; void reset() { if(ir) delete ir; ir = nullptr; } bool draw_ptriangle(cell *c, const shiftmatrix& V) { if(!on) return false; if(ir && ir->icgi != &cgi) reset(); if(!ir) { ir = new iring; ir->init(); // growthrate(); } if(c == cwt.at) { int frid = (ticks % 1000) * ir->frames / 1000; for(int sa: {0, 1}) for(int side=0; sidecols; side++) { auto &s = queuepoly(V, ir->ptriangle[sa][frid][side], ir->huess[sa][256*6/ir->cols * side]); ensure_vertex_number(*s.tinf, s.cnt); /* auto& s1 = queuepoly(V * nisot::translate(td.at), ir->pcube[side], gradient(tcolors[td.tcolor], magiccolors[side], 0, .2, 1)); ensure_vertex_number(*s1.tinf, s1.cnt); */ } if(cylball) { long long isp = isize(ir->path); transmatrix T = ir->path[isp-1 - (ticks * isp / int(anims::period)) % isp]; T = nisot::parallel_transport(inverse(T), -point3(0, cscale + cylball, 0)); queuepoly(V * T, ir->ball, 0xFFFFFFFF); } } return false; } bool cylanim = false; void o_key(o_funcs& v) { if(on) v.push_back(named_functionality("ring size", [] { dialog::editNumber(cscale, 0, 1, .01, .1, "", ""); dialog::reaction = reset; })); } auto hchook = addHook(hooks_drawcell, 100, draw_ptriangle) #if CAP_COMMANDLINE + addHook(hooks_args, 100, [] { using namespace arg; if(0) ; else if(argis("-cylon")) { on = true; } else if(argis("-cyls")) { shift_arg_formula(cscale); } else if(argis("-cylanim")) { cylanim = !cylanim; } else if(argis("-cylball")) { shift_arg_formula(cylball); } else return 1; return 0; }) #endif + addHook(anims::hooks_anim, 100, [] { if(!ir || !cylanim || !on) return; centerover = currentmap->gamestart(); long long isp = isize(ir->path); View = ir->path[isp-1 - (ticks * isp / int(anims::period)) % isp]; shift_view(point3(0, 0.3, 0)); anims::moved(); }) + addHook(hooks_o_key, 80, o_key) + addHook(rvtour::hooks_build_rvtour, 152, [] (vector& v) { using namespace tour; v.push_back( tour::slide{"Impossible architecture in Nil/impossible ring", 18, LEGAL::NONE | QUICKGEO, "Ring with a square cross-section. Cut it in half. Rotate one of the two halves by 90°, " "keeping one of the two ends connected to the other half. Do this in Nil geometry, so the other pair of ends remains connected too.\n\n" "Move with mouse/arrows/PgUpDn. Press '5' to enable animation, 'o' to change ring size.\n\n", [] (presmode mode) { setCanvas(mode, '0'); slidecommand = "animation"; if(mode == pmKey) { tour::slide_backup(cylanim, !cylanim); } if(mode == pmStart) { stop_game(); set_geometry(gNil); tour::slide_backup(mapeditor::drawplayer, false); tour::slide_backup(on, true); tour::slide_backup(smooth_scrolling, true); tour::slide_backup(nilv::nilperiod, make_array(3, 3, 3)); start_game(); playermoved = false; } }} ); }); }}