#include "rogueviz.h" namespace rogueviz { #if CAP_ARCM namespace pentagonal { transmatrix ts[3]; hyperpoint facingdir(array& a) { hyperpoint tmp = (a[1]-a[0]) ^ (a[2]-a[0]); tmp /= sqrt(tmp|tmp); return tmp; } vector> sideangles; cell *p0, *t0, *t1, *t2, *cc; hyperpoint cor; void kframe() { queuestr(gmatrix[p0], 0.6, "P0", 0xFFFFFF, 1); queuestr(gmatrix[cc], 0.6, "C", 0xFFFFFF, 1); queuestr(gmatrix[t0], 0.6, "T0", 0xFFFFFF, 1); queuestr(gmatrix[t1], 0.6, "T1", 0xFFFFFF, 1); queuestr(gmatrix[t2], 0.6, "T2", 0xFFFFFF, 1); } hyperpoint xts0; array mts; rug::rugpoint *pt(hyperpoint h, hyperpoint c, int id) { auto r = rug::addRugpoint(shiftless(C0), -1); r->native = h; r->native[3] = 1; if(hyperbolic) r->native[2] = -r->native[2]; r->x1 = (1 + c[0]) / 16 + (id/8) / 8.; r->y1 = (1 + c[1]) / 16 + (id%8) / 8.; r->valid = true; return r; } hyperpoint inplane(array& a, hyperpoint line) { hyperpoint mu = (a[1]-a[0]) ^ (a[2]-a[0]); // (a[0] | mu) == (line * z | mu) return line * (a[0] | mu) / (line | mu); } transmatrix matrix2; #if CAP_TEXTURE bool need_texture = true; texture::texture_data tdata; // = texture::config.data; #endif int global_v, global_w; void make_texture() { #if CAP_TEXTURE rug::renderonce = true; need_texture = false; tdata.whitetexture(); int tw = tdata.twidth; printf("tw = %d\n", tw); int fw = tw / 4; auto pix = [&] (int k, int x, int y) -> unsigned& { return tdata.texture_pixels[y * tw + x + (k&3) * fw + (k>>2) * fw * tw]; }; for(int y=0; y 1) hyp = 1; part(pix(0,x,y), p) = 255 * (1 * hyp + (0.5 + h[p]/2) * (1-hyp)); } tdata.loadTextureGL(); #endif rug::alternate_texture = tdata.textureid; } void create_model(); void enable_hooks(); void run_snub(int v, int w) { global_v = v; global_w = w; printf("set geometry\n"); stop_game(); autocheat = true; int bonus; if(w == 4 && v == 4) bonus = 12; else if(w == 4 && v == 5) bonus = 7; else if(w == 4 && v == 6) bonus = 4; else if(w == 3 && v == 6) bonus = 12; else if(w == 3 && v == 7) bonus = 8; else if(w == 3 && v == 8) bonus = 7; else if(w == 3 && v == 9) bonus = 6; else bonus = 0; gamerange_bonus = genrange_bonus = sightrange_bonus = bonus; set_geometry(gArchimedean); set_variation(eVariation::pure); arcm::current.parse("("+its(v)+",3," + its(w) + ",3,3) (2,3)(1,0)(4)"); check_cgi(); cgi.require_basics(); specialland = laCanvas; patterns::whichCanvas = 'A'; // vid.wallmode = 1; printf("start game\n"); printf("distlimit = %d\n", cgi.base_distlimit); start_game(); enable_hooks(); printf("ok\n"); printf("allcells = %d\n", isize(currentmap->allcells())); sideangles.clear(); printf("gamerange = %d\n", gamerange()); printf("genrange = %d\n", getDistLimit() + genrange_bonus); setdist(cwt.at, 7 - getDistLimit() - genrange_bonus, NULL); bfs(); drawthemap(); if(euclid || sphere) for(cell *c: currentmap->allcells()) gmatrix[c] = shiftless(arcm::archimedean_gmatrix[c->master].second); cellwalker cw(currentmap->gamestart(), 0); p0 = cw.at; t0 = (cw - 1 + wstep).at; t1 = (cw + wstep).at; t2 = (cw + wstep + 1 + wstep - 1).at; // p1 = (cw + wstep + 1 + wstep -1 + wstep).at; cc = (cw - 1 + wstep - 1 + wstep).at; transmatrix rel = inverse(gmatrix[p0].T); ts[0] = rel * gmatrix[t0].T * ddspin(t0, (cw - 1 + wstep).spin); ts[1] = rel * gmatrix[t1].T; ts[2] = rel * gmatrix[t2].T * ddspin(t2, (cw + wstep + 1 + wstep - 1).spin); matrix2 = ts[2] * inverse(ts[0]); for(int i=0; i<3; i++) mts[i] = ts[i] * C0; hyperpoint f = facingdir(mts); for(cell *c: currentmap->allcells()) { int id = arcm::id_of(c->master); if(among(id, 0, 1)) for(int d=0; d hts; for(int i=0; i<3; i++) hts[i] = T * ts[i] * C0; // for(int i=0; i<3; i++) printf("%s ", display(hts[i])); hyperpoint f1 = facingdir(hts); ld scalar = (f|f1); ld alpha = (M_PI - acos(scalar)) / degree; sideangles.emplace_back(alpha, T); } } vector sav; for(auto p: sideangles) sav.push_back(p.first); sort(sav.begin(), sav.end()); println(hlog, "sideangles ", sav); xts0 = tC0(ts[0]); println(hlog, "original ", xts0); cor = rel * gmatrix[cc].T * C0; rug::reopen(); rug::reset_view(); for(auto p: rug::points) p->valid = true; rug::good_shape = true; make_texture(); create_model(); printf("points = %d tris = %d side = %d\n", isize(rug::points), isize(rug::triangles), isize(sideangles)); rug::model_distance = euclid ? 4 : 2; vid.rug_config.model = hyperbolic ? mdPerspective : mdEquidistant; showstartmenu = false; } ld x, y; void create_model() { if(!inHighQual) { x = (mousex - current_display->xcenter + .0) / vid.xres; y = (mousey - current_display->ycenter + .0) / vid.yres; } int v = global_v; rug::clear_model(); ld alpha = atan2(y, x); ld h = hypot(x, y); hyperpoint chk = ts[0] * xspinpush0(alpha, h); mts[0] = chk; mts[1] = spin(-TAU/v) * chk; mts[2] = matrix2 * chk; hyperpoint c[5]; for(int i=0; i<5; i++) c[i] = hpxy(sin(i * TAU/5), cos(i * TAU/5)); hyperpoint tria[5]; tria[0] = mts[0]; tria[1] = inplane(mts, C0); tria[2] = mts[1]; tria[3] = mts[2]; tria[4] = inplane(mts, cor); hyperpoint ctr = Hypc; for(int i=0; i<5; i++) ctr += tria[i]; ctr = inplane(mts, ctr); transmatrix tester = spin(1.1) * xpush(1); int idh = 0; for(hyperpoint h: {ctr, tria[0], tria[1], tria[2], tria[3], tria[4], ctr}) { int good1 = 0, good2 = 0; // printf("%d: ", idh); for(int i=0; i<5; i++) { array testplane; testplane[0] = tester * h; testplane[1] = tester * tria[i]; testplane[2] = tester * tria[(i+1)%5]; hyperpoint f = facingdir(testplane); if(f[0] > -1e-6 || std::isnan(f[0])) good1++; if(f[0] < +1e-6 || std::isnan(f[0])) good2++; } // printf("\n"); if(good1 == 5 || good2 == 5) {ctr = h; break; } idh++; } // printf("idh = %d\n", idh); // printf("createmodel with ticks = %d\n", ticks); transmatrix t = hyperbolic ? hr::cspin180(0, 2) * xpush(sin(ticks * TAU / anims::period)) : hr::cspin(0, 2, ticks * TAU / anims::period); hyperpoint hs = hyperbolic ? hpxyz(0,0,-1) : hpxyz(0,0,0); if(euclid) t = Id; int id = 0; for(auto& p: sideangles) { auto& T = p.second; array hts; auto cpt = pt(hs + t * T * ctr, C0, id); for(int s=0; s<5; s++) hts[s] = pt(hs + t * T * tria[s], c[s], id); for(int s=0; s<5; s++) rug::addTriangle(cpt, hts[s], hts[(s+1)%5]); id++; if(!sphere) id %= global_v; } } bool animated = true; void rugframe() { if(animated) create_model(); displaychr(current_display->xcenter, current_display->ycenter, 0, 10, 'X', 0xFFFFFF); clearMessages(); } void show() { cmode = sm::SIDE | sm::MAYDARK; gamescreen(); dialog::init("Pentagonal Exploration"); auto add_key = [] (char c, int a, int b) { dialog::addBoolItem(lalign(0, "based on {",a,",",b,"}"), global_v == a && global_w == b, c); dialog::add_action([a,b] { run_snub(a, b); }); }; for(int i=3; i<10; i++) add_key('0'+i, i, 3); add_key('$', 4, 4); add_key('%', 5, 4); add_key('^', 6, 4); dialog::addBoolItem_action("animation and mouse control", animated, 'a'); dialog::addSelItem(XLAT("projection"), models::get_model_name(vid.rug_config.model), 'p'); dialog::add_action([] { pushScreen(models::model_menu); }); dialog::addBoolItem(XLAT("set perspective (allows flying with Home/End)"), vid.rug_config.model == mdPerspective, 's'); dialog::add_action([] { auto& m = vid.rug_config.model; m = (m==mdPerspective) ? mdEquidistant : mdPerspective; }); dialog::display(); } void enable_hooks() { rv_hook(rug::hooks_rugframe, 100, rugframe); rv_hook(hooks_o_key, 80, [] (o_funcs& v) { v.push_back(named_dialog("pentagonal exploration", show)); }); } auto xhook = arg::add3("-snub", [] { run_snub(arg::shift_argi(), 3); }) + arg::add3("-snub4", [] { run_snub(arg::shift_argi(), 4); }) + addHook_rvslides(143, [] (string s, vector& v) { if(s != "mixed") return; using namespace tour; v.push_back( tour::slide{"Pentagonal Exploration", 62, LEGAL::NONE | QUICKGEO, "Pentagonal Exploration explained at: http://www.roguetemple.com/z/sims/snub/\n\n" "Move the mouse nearer and further away from the X.", [] (presmode mode) { setCanvas(mode, '0'); slide_url(mode, 'u', "open the URL", "http://www.roguetemple.com/z/sims/snub/"); slide_backup(rug::model_distance); slide_backup(vid.rug_config.model); slide_backup(rug::alternate_texture); if(mode == pmStart) { pentagonal::run_snub(5, 3); } if(mode == pmKey) pushScreen(show); if(mode == 3) { printf("stopping\n"); rug::close(); } }} ); }); } #endif }