namespace rogueviz { namespace graph { bool graph_on; vector formula; color_t graphcolor; transmatrix ts[3]; using namespace hyperpoint_vec; 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; bool snubon; hyperpoint cor; void kframe() { if(snubon) { 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(C0, -1); r->flat = h; 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(); rug::alternate_texture = tdata.textureid; #endif } void create_model(); void run_snub(int v, int w) { snubon = false; 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)"); specialland = laCanvas; patterns::whichCanvas = 'A'; // vid.wallmode = 1; need_reset_geometry = true; printf("start game\n"); printf("distlimit = %d\n", base_distlimit); precalc(); printf("distlimit = %d\n", base_distlimit); start_game(); 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] = 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]); ts[0] = rel * gmatrix[t0] * ddspin(t0, (cw - 1 + wstep).spin); ts[1] = rel * gmatrix[t1]; ts[2] = rel * gmatrix[t2] * 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()); printf("sideangles "); for(int i=0; i<3; i++) printf("%lf ", double(sav[i])); printf("\n"); xts0 = tC0(ts[0]); println(hlog, "original ", xts0); cor = rel * gmatrix[cc] * C0; rug::reopen(); 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; rug::rug_perspective = hyperbolic; showstartmenu = false; snubon = true; rug::invert_depth = hyperbolic; } void create_model() { int v = global_v; rug::clear_model(); ld x = (mousex - current_display->xcenter + .0) / vid.xres; ld y = (mousey - current_display->ycenter + .0) / vid.yres; ld alpha = atan2(y, x); ld h = hypot(x, y); hyperpoint chk = ts[0] * xspinpush0(alpha, h); mts[0] = chk; mts[1] = spin(-2*M_PI/v) * chk; mts[2] = matrix2 * chk; hyperpoint c[5]; for(int i=0; i<5; i++) c[i] = hpxy(sin(2 * i * M_PI/5), cos(2 * i * M_PI/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); // printf("%lf ", f[0]); 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); transmatrix t = hyperbolic ? rotmatrix(M_PI, 0, 2) * xpush(sin(ticks * M_PI / 8000.)) : rotmatrix(ticks * M_PI / 8000., 0, 2); 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; } } hyperpoint err = hpxyz(500,0,0); bool iserror(hyperpoint h) { return sqhypot_d(2, h) > 10000 || std::isnan(h[0]) || std::isnan(h[1]) || std::isnan(h[2]) || std::isinf(h[0]) || std::isinf(h[1]) || std::isinf(h[2]); } hyperpoint xy_to_point(ld x, ld y) { if(sphere && hypot(x, y) > 1) return err; return hpxy(x, y); } hyperpoint find_point(ld t) { exp_parser ep; auto &dict = ep.extra_params; dict["t"] = t; dict["phi"] = t * 2 * M_PI; dict["x"] = tan(t * M_PI - M_PI/2); for(auto& ff: formula) { ep.s = ff; string varname = ""; ep.at = 0; while(!among(ep.next(), '=', -1)) varname += ep.next(), ep.at++; ep.at++; cld x = ep.parse(); if(!ep.ok()) return err; dict[varname] = x; } if(!dict.count("y") && dict.count("r")) return xspinpush0(real(dict["phi"]), real(dict["r"])); if(dict.count("z") && dict.count("x")) return hpxyz(real(dict["x"]), real(dict["y"]), real(dict["z"])); if(dict.count("z")) { return xy_to_point(real(dict["z"]), imag(dict["z"])); } return xy_to_point(real(dict["x"]), real(dict["y"])); } hyperpoint gcurvestart = err; void xcurvepoint(hyperpoint h) { curvepoint(cwtV * h); if(iserror(gcurvestart)) gcurvestart = h; else if(sphere && intval(gcurvestart, h) > .1) { queuecurve(graphcolor, 0, PPR::LINE); curvepoint(cwtV * h); gcurvestart = h; } } void finish() { if(!iserror(gcurvestart)) { queuecurve(graphcolor, 0, PPR::LINE); gcurvestart = err; } } int small_limit = 6, big_limit = 20; void draw_to(ld t0, hyperpoint h0, ld t1, hyperpoint h1, int small = 0, int big = 0) { if(iserror(h0) || iserror(h1) || intval(h0, h1) < .01) small++; else small = 0; if(small >= small_limit || big >= big_limit) { xcurvepoint(h1); return; } if(t1-t0 < 1e-6) { finish(); return; } ld t2 = (t0 + t1) / 2; hyperpoint h2 = find_point(t2); draw_to(t0, h0, t2, h2, small, big+1); draw_to(t2, h2, t1, h1, small, big+1); } int editwhich = -1; void show_graph() { cmode = sm::SIDE | sm::MAYDARK; gamescreen(0); dialog::init(XLAT("graph")); for(int i=0; i= 0) { if(dialog::handle_edit_string(sym, uni)) ; else if(doexiton(sym, uni)) editwhich = -1; } else { handlePanning(sym, uni); dialog::handleNavigation(sym, uni); // if(doexiton(sym, uni)) popScreen(); } }; } void frame() { if(graphcolor) { hyperpoint h0 = find_point(0); hyperpoint h1 = find_point(1); if(!iserror(h0)) xcurvepoint(h0); draw_to(0, h0, 1, h1); finish(); } } #if CAP_COMMANDLINE int readArgs() { using namespace arg; if(0) ; else if(argis("-dgraph")) { PHASE(3); showstartmenu = false; pushScreen(show_graph); shift(); while(args().find("=") != string::npos) { formula.emplace_back(args()); shift(); } graphcolor = arghex(); } else if(argis("-dgs")) { small_limit = argi(); } else if(argis("-dgl")) { big_limit = argi(); } else return 1; return 0; } #endif auto xhook = addHook(hooks_args, 100, readArgs) + addHook(hooks_frame, 0, frame); } }