From 4bcd23af08e426749d47fe556676816246d5c3dd Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Mon, 15 May 2023 02:48:38 +0200 Subject: [PATCH] rogueviz:: embedded-chess added --- rogueviz/embedded-chess.cpp | 1875 +++++++++++++++++++++++++++++++++++ 1 file changed, 1875 insertions(+) create mode 100644 rogueviz/embedded-chess.cpp diff --git a/rogueviz/embedded-chess.cpp b/rogueviz/embedded-chess.cpp new file mode 100644 index 00000000..44b5d133 --- /dev/null +++ b/rogueviz/embedded-chess.cpp @@ -0,0 +1,1875 @@ +#include "rogueviz.h" + +// for this video: https://youtu.be/Rhjv_PazzZE + +namespace hr { + +/** load Chess? */ +EX bool with_chess = false; +/** load other models? */ +EX bool with_models = false; +/** including the CGtrader models? (not included here) */ +EX bool cgtrader_models = false; +/** floor disabled */ +EX bool no_floor = false; +/** do not include the models inside the house for faster transition */ +EX bool light_models = false; + +/** higher periods needs to be set to display scaffold correctly */ +int periods = 1; + +/** how many chess moves performed */ +int chess_moves = 0; + +namespace smoothcam { +using namespace rogueviz::smoothcam; +} + +vector> map54_edges; +vector map54_nodes; + +vector> map534_edges; +vector map534_nodes; + +struct embset { + string name; + geom3::eSpatialEmbedding se; + ld walls, scale, depth, eye, sun, sky, star; + }; + +embset current() { + embset e; + e.name = "current"; + e.se = geom3::spatial_embedding; + e.scale = geom3::euclid_embed_scale; + auto actscale = e.scale; + if(e.se == geom3::seDefault) { e.scale = 0; actscale = 1; } + e.walls = vid.wall_height / actscale; + e.depth = vid.depth / e.walls; + e.eye = (vid.eye-vid.depth) / e.walls; + e.sun = vid.sun_size / e.walls; + e.sky = vid.sky_height; + e.star = vid.star_height; + e.se = geom3::spatial_embedding; + return e; + } + +void activate(const embset& e) { + if(GDIM == 2) invoke_embed(geom3::seDefault); + embset c = current(); + auto wh = vid.wall_height; + geom3::changing_embedded_settings = true; + geom3::switch_always3(); + geom3::euclid_embed_scale = e.se == geom3::seDefault ? 1 : e.scale; + vid.wall_height = e.walls * geom3::euclid_embed_scale; + vid.depth = e.depth * vid.wall_height; + vid.eye = vid.depth + e.eye * vid.wall_height; + vid.sun_size = e.sun * vid.wall_height; + vid.sky_height = e.sky; + vid.star_height = e.star; + geom3::spatial_embedding = e.se; + geom3::switch_always3(); + geom3::changing_embedded_settings = false; + if(e.se != c.se) { + if(vid.usingGL) resetGL(); + } + delete_sky(); + if(vid.wall_height * wh < 0) View = MirrorY * View; + pmodel = default_model(); + }; + +embset lerp(const embset& a, const embset& b, ld f) { + embset e; + e.name = lalign(0, "lerp(", a, ", ", b, ", ", f, ")"); + e.se = b.se; + e.scale = lerp(a.scale, b.scale, f); + e.walls = lerp(a.walls, b.walls, f); + e.depth = lerp(a.depth, b.depth, f); + e.eye = lerp(a.eye, b.eye, f); + e.sun = lerp(a.sun, b.sun, f); + e.sky = lerp(a.sky, b.sky, f); + e.star = lerp(a.star, b.star, f); + return e; + } + +void print(hstream& hs, const embset& e) { + print(hlog, "embset{.name=\"", e.name, "\", .se=eEmbeddingMethod(", int(e.se), "), .walls=", e.walls, ", .scale=", e.scale, ", .depth=", e.depth, ", .eye=", e.eye, ", .sun=", e.sun, ", .sky=", e.sky, ", .star=", e.star, "}"); + } + +embset edefault = embset{.name="default", .se=geom3::seDefault, .walls=1.2, .scale=0, .depth=0, .eye=1.5, .sun=0.333333, .sky=10, .star=9}; +embset edefaulti = embset{.name="default", .se=geom3::seDefault, .walls=-1.2, .scale=0, .depth=0, .eye=-1.5, .sun=0.333333, .sky=10, .star=9}; +// embset eincyl = embset{.name="in cylinder", .se=geom3::seCylinderE, .walls=0.75, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.6}; +embset eincyl = embset{.name="in cylinder E", .se=geom3::seCylinderE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset eoutcyl = embset{.name="out cylinder E", .se=geom3::seCylinderE, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.3, .sky=10, .star=9}; +embset eouthoro = embset{.name="out horosphere", .se=geom3::seLowerCurvature, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5}; +embset einhoro = embset{.name="in horosphere", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; +embset einhoro_small = embset{.name="in horosphere (small sky)", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=18, .star=17}; +embset esolv = embset{.name="solv", .se=geom3::seSol, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; +embset einnih = embset{.name="in NIH", .se=geom3::seNIH, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; +embset eoutnih = embset{.name="out NIH", .se=geom3::seNIH, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5}; +embset eclifford = embset{.name="Clifford", .se=geom3::seCliffordTorus, .walls=1.2, .scale=M_PI/10, .depth=-0.0561826, .eye=1.5, .sun=0.25, .sky=2.55, .star=2.3}; +embset enil = embset{.name="Nil flat", .se=geom3::seNil, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; +embset esl2 = embset{.name="SL(2,R) flat", .se=geom3::seSL2, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11}; +embset eincylh = embset{.name="in cylinderH", .se=geom3::seCylinderH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset eincylhe = embset{.name="in cylinderHE", .se=geom3::seCylinderHE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset eincylnil = embset{.name="in cylinder Nil", .se=geom3::seCylinderNil, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset eincylsl = embset{.name="in cylinder SL(2,R)", .se=geom3::seCylinderSL2, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset einhorocyl = embset{.name="in horocylinder", .se=geom3::seCylinderHoro, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=8, .star=7.5}; +embset eouthorocyl = embset{.name="out horocylinder", .se=geom3::seCylinderHoro, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.5}; +embset eprodh_flat = embset{.name="hyperbolic product (flat)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset eprodh_concave = embset{.name="hyperbolic product (concave)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=1, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset eprods_flat = embset{.name="spherical product (flat)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; +embset eprods_concave = embset{.name="spherical product (concave)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0.8333, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4}; + +embset& edok() { return vid.wall_height > 0 ? edefault : edefaulti; } + +vector embsets = { + edefault, + eincyl, eoutcyl, eouthoro, einhoro, einhoro_small, esolv, eclifford, einnih, eoutnih, + enil, esl2, eincylh, eincylhe, eincylnil, eincylsl, + einhorocyl, eouthorocyl, eprodh_flat, eprodh_concave, eprods_flat, eprods_concave + }; + +ld fix_chess = 0; + +int draw_digger = 0; + +bool move_cat = false; + +vector xmap = { + {"......B..........p#"}, + {".................p#"}, + {"..xxxxxxxx.......p#"}, + {"..xxxxxxxx..T....p#"}, + {"..xxxxxxxx.....T.p#"}, + {"..xxxxxxxx...~~..p#"}, + {"..xxxxxxxx..~uv~.p#"}, + {"..xxxxxxxx..~vu~.p#"}, + {"..xxxxxxxx..~~~~.p#"}, + {"..xxxxxxxx......Tp#"}, + {".............T...p#"}, + {"......C..........p#"}, + {"......p..........p#"}, + {".>>>..p..DDDDDDD.p#"}, + {".>>>..pK.DddddrD.p#"}, + {".>>>..pK.DdddtdD.p#"}, + {"......pK.DdddddD.p#"}, + {"..e...p..DOD+DOD.p#"}, + {"......p.....p....p#"}, + {"....^.pppppppppppp#"}, + }; + +namespace embchess { + +void build_map(); + +ld hmul; + +set domek1, domek2; + +vector ac, bac; + +using namespace rogueviz::objmodels; + +void prepare_tf(); + +hyperpoint adjust(hyperpoint h) { + h = cspin90(1, 2) * h * 40. + point3(-0.5, -0.5, 0); + return h; + } + +hyperpoint rechess(hyperpoint h) { + h[2] = lerp(cgi.FLOOR, cgi.WALL, 0.01-h[2]/4 * hmul * 2 / 0.6) + fix_chess; + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + +struct split_model_data : gi_extension { + map, vector>> objs_at; + void render(const shiftmatrix& V, int x, int y); + }; + +struct chessmodel : public model { + + void process_triangle(vector& hys, vector& tot, bool textured, object *co) override { + + for(auto& h: hys) h = adjust(h); + + hyperpoint norm = (hys[1] - hys[0]) ^ (hys[2] - hys[0]); + norm /= hypot_d(3, norm); + ld y = .5 + (.2 * norm[0] + .16 * norm[1] + .14 * norm[2]); + glvertex shade = glhr::makevertex(0, y, 0); + glvertex shadecol = glhr::makevertex(y, y, y); + + auto elen = [] (hyperpoint a, hyperpoint b) { return ceil(hypot_d(3, a-b) * 5); }; + + int parts = max( max(elen(hys[0], hys[1]), elen(hys[0], hys[2])), elen(hys[1], hys[1]) ); + // if(parts > 8) println(hlog, "parts = ", parts, " levels = ", tie(hys[0][2], hys[1][2], hys[2][2]), " .. ", hys); + // if(parts > 8) return; + + auto tri = [&] (int a, int b) { + cgi.hpcpush(rechess(hys[0] + (hys[1] - hys[0]) * a / parts + (hys[2] - hys[0]) * b / parts)); + if(textured) { + co->tv.tvertices.push_back(glhr::pointtogl(tot[0] + (tot[1] - tot[0]) * a / parts + (tot[2] - tot[0]) * b / parts)); + co->tv.colors.push_back(shadecol); + } + else { + co->tv.tvertices.push_back(shade); + } + }; + + for(int a=0; a&) cgi.ext[fname + "-SPLIT"]; + + if(!md) { + md = std::make_unique(); + auto& md0 = get(); + split(md0, *md); + } + + return *md; + } + }; + +bool ispiece(color_t col) { + return among(col, color_t(0xFFFFFFFF), color_t(0x202020FF), color_t(0x2B2B2BFF)); + } + +void chessmodel::split(model_data& md, split_model_data& smd) { + cgi.extra_vertices(); + map, map>>> mm; + for(auto& obj: md.objs) { + for(int i=obj->sh.s; ish.e; i+=3) { + hyperpoint ctr = Hypc; + array hs; + for(int j=0; j<3; j++) hs[j] = GDIM == 2 ? cgi.hpc[i+j] : cgi.emb->actual_to_logical(cgi.hpc[i+j]); + ctr += hs[0]; + ctr += hs[1]; + ctr += hs[2]; + ctr /= 3; + int x = floor(ctr[0] + .5); + int y = floor(ctr[1] + .5); + int ax = x + 6, ay = y + 6; + if(chess_moves >= 1 && ispiece(obj->color)) { + if(ax == 6) { if(ay == 8) ay = 6; else if(ay == 6) ay = 8; } + } + if(chess_moves >= 2 && ispiece(obj->color)) { + if(ax == 6) { if(ay == 3) ay = 5; else if(ay == 5) ay = 3; } + } + if(chess_moves >= 3 && ispiece(obj->color)) { + if(ax == 8) { if(ay == 9) ay = 7, ax = 7; } + } + for(int j=0; j<3; j++) + mm[{ax,ay}][obj->color].emplace_back(hs[j] - hyperpoint(x, y, 0, 0), obj->tv.tvertices[i+j-obj->sh.s]); + } + } + for(auto& a: mm) + for(auto& b: a.second) { + auto& objs = smd.objs_at[a.first]; + objs.push_back(make_shared()); + auto co = &*objs.back(); + cgi.bshape(co->sh, PPR::THORNS); + cgi.last->flags |= POLY_TRIANGLES; + cgi.last->texture_offset = 0; + cgi.last->tinf = &co->tv; + co->tv.texture_id = floor_textures->renderedTexture; + if(GDIM == 2) cgi.last->tinf = nullptr; + co->color = b.first; + if(co->color == 0xCCCCCCFF) co->color = GDIM == 2 ? 0 : 0xFFE080FF; + else if(co->color == 0x5B5B5BFF) co->color = GDIM == 2 ? 0 : 0x807020FF; + // else for(auto& v: b.second) v.first = cspin180(0, 1) * v.first; + for(auto v: b.second) { + cgi.hpcpush(GDIM == 2 ? v.first : cgi.emb->logical_to_actual(v.first)); + co->tv.tvertices.push_back(v.second); + } + cgi.finishshape(); + } + cgi.extra_vertices(); + if(0) for(auto& p: smd.objs_at) { + println(hlog, p.first, " : ", isize(p.second), " objects"); + for(auto& obj: p.second) { + vector hs; + for(int i=obj->sh.s; ish.e; i++) hs.push_back(cgi.hpc[i]); + if(isize(hs) > 3) hs.resize(3); + println(hlog, "vertices: ", obj->sh.e - obj->sh.s, " of color ", obj->color, " : ", hs); + } + } + } + +void split_model_data::render(const shiftmatrix& V, int x, int y) { + for(auto& obj: objs_at[{x, y}]) if(obj->color) { + queuepoly(V, obj->sh, obj->color); + } + } + +chessmodel chess("rogueviz/models/", "Polyfjord_Chess_Set.obj"); + +ld minz = 100, maxz = -100; +ld minx = 100, maxx = -100; +ld miny = 100, maxy = -100; + +struct bunnymodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h = cspin(0, 1, 15._deg) * h; + h[0] *= 800; + h[1] *= 800; + h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(-0.000333099, -0.00186996, h[2]) * hmul * 4/3.); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + bunnymodel(string a, string b) : model(a,b) {} + }; + +bunnymodel bunny("rogueviz/models/", "bunny.obj"); + +struct catmodel : public model { + hyperpoint transform(hyperpoint h) override { + + if(0) println(hlog, "scale = 1 to ", + lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, 1) * hmul * 4/3.) + - lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, 0) * hmul * 4/3.) + ); + + h = cspin90(1, 2) * h; + h = cspin180(0, 1) * h; + h = cspin(1, 0, 30._deg) * h; + h[0] *= 6; + h[1] *= 6; + h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, h[2]) * hmul * 4/3.) / 8.3272 * 6; + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + void load_obj(model_data& md) override { + model::load_obj(md); + for(auto& o: md.objs) if(o->mtlname == "whiskers") o->sh.prio = PPR::TRANSPARENT_WALL; + } + catmodel(string a, string b) : model(a,b) {} + }; + +catmodel maxwellcat("rogueviz/models/", "maxwellcat.obj"); + +struct tulipmodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h = cspin180(0, 1) * h; + h[0] *= 400; + h[1] *= 400; + h[0] -= 0.1*2; h[1] += 0.36*2; + h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0, -0.00307639, h[2]) * hmul); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + tulipmodel(string a, string b) : model(a,b) {} + }; + +tulipmodel tulip("rogueviz/models/", "tulip.obj"); +tulipmodel tulip1("rogueviz/models/", "tulip1.obj"); +tulipmodel tulip2("rogueviz/models/", "tulip2.obj"); + +struct diggermodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h[0] *= 50; + h[1] *= 50; + /* h[0] *= 400; + h[1] *= 400; + h[0] -= 0.1*2; h[1] += 0.36*2; */ + h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00027, -0.0549454, h[2]) * hmul * 1.5); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + diggermodel(string a, string b) : model(a,b) {} + }; + +diggermodel digger("rogueviz/models/", "digger.obj"); + +struct tablemodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h[1] -= 0.005; + h[0] *= 100; + h[1] *= 100; + /* h[0] *= 400; + h[1] *= 400; + h[0] -= 0.1*2; h[1] += 0.36*2; */ + h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0, -0.008, h[2]) * hmul / 2); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + tablemodel(string a, string b) : model(a,b) {} + }; + +tablemodel table("rogueviz/models/", "table.obj"); + +struct cheesemodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h[0] *= 15; + h[1] *= 15; + /* h[0] *= 400; + h[1] *= 400; + h[0] -= 0.1*2; h[1] += 0.36*2; */ + h[0] -= 0.2; + h[2] = lerp(cgi.FLOOR, cgi.WALL, (ilerp(0.00577916, -0.01166, h[2])/3 + 1.05) * hmul / 2); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + cheesemodel(string a, string b) : model(a,b) {} + }; + +cheesemodel cheese("rogueviz/models/", "cheese.obj"); + +struct coffeemodel : public model { + int cid; + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h[0] += 0.00077; + h[1] += 0.011; + h[0] *= 200; h[1] *= 200; + if(cid == 1) h[0] += 0.3; + if(cid == 2) h[1] += 0.5; + h[2] = lerp(cgi.FLOOR, cgi.WALL, (ilerp(-0.0083, -0.0089, h[2])) * 1.2 / 10 + .51); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + coffeemodel(string a, string b, int _id) : model(a,b), cid(_id) {} + }; + +/* need different file names */ +coffeemodel coffee1("rogueviz/models/", "coffee.obj", 1), coffee2("rogueviz/models/", "./coffee.obj", 2); + +struct lilymodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h[0] += 0.67; h[1] -= 0.36; + h[0] *= 5; + h[1] *= 5; + /* h[0] *= 400; + h[1] *= 400; + h[0] -= 0.1*2; h[1] += 0.36*2; */ + h[2] = lerp(cgi.LAKE, cgi.FLOOR, ilerp(0.018, -0.0496, h[2]) * hmul); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + lilymodel(string a, string b) : model(a,b) {} + }; + +lilymodel lily("rogueviz/models/", "lily.obj"); + +struct duckmodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h[0] += 3.8; h[1] -= 2; + /* h[0] *= 400; + h[1] *= 400; + h[0] -= 0.1*2; h[1] += 0.36*2; */ + h[2] = lerp(cgi.LAKE, cgi.FLOOR, ilerp(0.056, -0.408, h[2]) * hmul * 1.5); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + duckmodel(string a, string b) : model(a,b) {} + }; + +duckmodel duck("rogueviz/models/", "duck.obj"); + +struct ratmodel : public model { + hyperpoint transform(hyperpoint h) override { + h = cspin90(1, 2) * h; + h[0] *= 100; + h[1] *= 100; + h[2] *= 100; + h[0] /= 3 * 3; + h[1] /= 3 * 3; + h[2] /= 3 * 3; + h = cspin(0, 1, 135._deg) * h; + + if(h[2] < minz) minz = h[2]; + if(h[2] > maxz) maxz = h[2]; + if(h[0] < minx) minx = h[0]; + if(h[0] > maxx) maxx = h[0]; + if(h[1] < miny) miny = h[1]; + if(h[1] > maxy) maxy = h[1]; + + h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(1/9., 1/9. - 1.2, h[2]) * hmul); + if(GDIM == 3) h = cgi.emb->logical_to_actual(h); + else h[2] = 1; + return h; + } + ratmodel(string a, string b) : model(a,b) {} + }; + +ratmodel rat("rogueviz/models/", "spinning-rat.obj"); + +bool hedge_constructed = false; + +const int hx = 7; +array hedge_visited; +array hdirs = {1, hx, hx*hx, -1, -hx, -hx*hx}; + +array, hx*hx*hx> hedge_dirs; + +int hstart; + +void construct_hedge() { + for(int x=0; x inorder = {hstart}; + for(int i=0; i 0 && co == hx-1) continue; + if(hedge_visited[at+hdirs[dir]]) continue; + hedge_visited[at+hdirs[dir]] = true; + hedge_dirs[at].push_back(dir); + inorder.push_back(at+hdirs[dir]); + } + } + /* + int qty = hx*hx*hx-1; + while(qty > 0) { + int at = hrand(hx*hx*hx); + if(!hedge_visited[at]) continue; + int dir = hrand(6); + int co = (at / abs(hdirs[dir])) % hx; + if(hdirs[dir] < 0 && co == 0) continue; + if(hdirs[dir] > 0 && co == hx-1) continue; + if(hedge_visited[at+hdirs[dir]]) continue; + hedge_visited[at+hdirs[dir]] = true; + hedge_dirs[at].push_back(dir); + qty--; + } */ + } + +void add_oct(transmatrix T, int idx, int face, ld len) { + array p; + for(int i=0; i<3; i++) { p[i] = C03; p[i][i] = ((face>>i)&1) ? len/2 : -len/2; p[i] = cgi.emb->logical_scaled_to_intermediate * p[i]; } + hyperpoint c = (p[0] + p[1] + p[2]) / 3; + for(int f=0; f<3; f++) { + hyperpoint a = p[f] - c; + hyperpoint b = p[(f+1)%3] - c; + texture_order([&] (ld x, ld y) { + hyperpoint h = c + a * x + b * y; + hyperpoint t = T * cpush(0, h[0]) * cpush(1, h[1]) * cpush(2, h[2]) * C0; + cgi.hpcpush(t); + }); + } + if(true) for(auto d: hedge_dirs[idx]) { + hyperpoint h = C0; + h[d%3] = (d<3 ? -len: len); + h = cgi.emb->logical_scaled_to_intermediate * h; + transmatrix T1 = T; + for(int i=0; i<3; i++) if(h[i]) T1 = T1 * cpush(i, h[i]); + add_oct(T1, idx + hdirs[d], face, len); + } + } + +void create_hedge(model_data& md) { + if(!hedge_constructed) construct_hedge(); + hyperpoint start = cgi.emb->logical_to_actual(point31(0, 0, cgi.FLOOR)); + hyperpoint npt = cgi.emb->logical_to_actual(point31(0.01, 0, cgi.FLOOR)); + transmatrix S = cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point31(0, 0, cgi.emb->center_z() + cgi.FLOOR)); + ld len = hdist(start, npt) * 100 / 7; + len *= 3; + if(vid.wall_height < 0) len = -len; + md.objs.resize(8); + for(int i=0; i<8; i++) { + md.objs[i] = make_shared (); + auto& obj = *md.objs[i]; + obj.color = 0xFF00FF; + if(i & 1) obj.color ^= 0x200000; + if(i & 2) obj.color ^= 0x20000000; + if(i & 4) obj.color ^= 0x2000; + cgi.bshape(obj.sh, PPR::FLOOR_DRAGON); + cgi.last->flags |= POLY_TRIANGLES; + cgi.last->texture_offset = 0; + cgi.last->tinf = &obj.tv; + obj.tv.texture_id = floor_textures->renderedTexture; + add_oct(S * lzpush(-len/2), hstart, i, len); + cgi.finishshape(); + bind_floor_texture(obj.sh, cgi.shFeatherFloor.id); + } + cgi.extra_vertices(); + } + +void draw_hedge(const shiftmatrix& V) { + auto& md = (unique_ptr&) cgi.ext["hedge"]; + if(!md) { + md = std::make_unique(); + create_hedge(*md); + } + md->render(V); + } + +hyperpoint inverse_exp_newton(hyperpoint h, int iter) { + auto approx = inverse_exp(shiftless(h)); + for(int i=0; i g(geometry, gCubeTiling); + p = xpush(i * length / MAX_X) * cspin(1, 2, alpha) * ypush0(width*z); + p = lT * p; + } + p = direct_exp(p); + cgi.hpcpush(p); + #if CAP_GL + if(floor_textures) utt.tvertices.push_back(glhr::makevertex(0, true ? 0.549 - s * 0.45 * sin(alpha) : 0.999, 0)); + #endif + }; + for(int i=0; iflags |= POLY_TRIANGLES | POLY_PRINTABLE; + cgi.finishshape(); + cgi.extra_vertices(); + return pipe; + } + +void fat_line(const shiftmatrix& V1, const hyperpoint h1, const shiftmatrix& V2, const hyperpoint h2, color_t col, int prec, ld lw) { + if(nonisotropic) { + auto nV1 = V1 * rgpushxto0(h1); + hyperpoint U2 = inverse_shift(nV1, V2*rgpushxto0(h2)) * C0; + auto& p = get_noniso_pipe(U2, lw, ePipeEnd::ball); + queuepoly(nV1, p, col); + return; + } + + ld d = hdist(V1.T*h1, V2.T*h2); + + shiftmatrix T = V1 * rgpushxto0(h1); + transmatrix S = rspintox(inverse_shift(T, V2) * h2); + transmatrix U = rspintoc(inverse_shift(T*S, shiftless(C0)), 2, 1); + auto& p = queuepoly(T * S * U, cgi.generate_pipe(d, lw, ePipeEnd::ball), col); + p.intester = xpush0(d/2); + } + +int scaffoldx = 0, scaffoldy = 0, scaffoldb = 0, scaffoldx_move = 0, scaffoldy_move; + +template void draw_map54(const shiftmatrix& S, const T& f, color_t col) { + for(auto p: map54_nodes) queuepoly(S * rgpushxto0(f(p)), cgi.shSnowball, 0xFFFFFFFF); + for(auto& p: map54_edges) fat_line(S, f(p.first), S, f(p.second), (abs(p.first[1])<1e-3 && abs(p.second[1])<1e-3 && scaffoldx && scaffoldy) ? 0xFFFFFFFF : col, 2, 0.01); + } + +void draw_scaffold(const shiftmatrix& V) { + ld levz = log(2); + if(nih) levz = 1; + ld levx = 1; + if(hyperbolic) levx = exp(-cgi.FLOOR); + levx *= 5; + + if(scaffoldx == 1) + for(int z=-5; z<=5; z++) + for(int s=-20; s<=20; s++) { + shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(s*levx,0,0)); + queuepoly(S, cgi.shSnowball, 0xFFFFFFFF); + fat_line(S, C0, S, lzpush(-levz) * C0, (s == 0 && scaffoldy) ? 0xFFFFFFFF : 0xFF0000FF, 2, 0.01); + for(int s=0; s<8; s++) + fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+0)/8.,0,0)) * C0, + S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+1)/8.,0,0)) * C0, + 0x8000FFFF, 2, 0.01); + } + + if(scaffoldx == 2) { + if(hyperbolic) { + draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(h[1],0,0)) * zpush(h[0]) * C0; }, 0xFFD500FF); + } + if(sol) { + draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(h[1],0,0)) * zpush(-h[0]) * C0; }, 0xFFD500FF); + } + if(nih) { + draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(-h[1]/log(2),0,0)) * zpush(h[0]/log(2)) * C0; }, 0xFFD500FF); + } + } + + ld levy = 5; + if(scaffoldy == 1) + for(int z=-5; z<=5; z++) + for(int s=-20; s<=20; s++) { + shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,s*levy,0)); + queuepoly(S, cgi.shSnowball, 0xFFFFFFFF); + fat_line(S, C0, S, lzpush(sol ? levz : -levz) * C0, (s == 0 && scaffoldx) ? 0xFFFFFFFF : 0x0000FFFF, 2, 0.01); + for(int s=0; s<8; s++) + fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0, levy*(s+0)/8.,0)) * C0, + S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0, levy*(s+1)/8.,0)) * C0, + 0x0080FF, 2, 0.01); + } + + if(scaffoldy == 2) { + if(hyperbolic) { + draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1],0)) * zpush(h[0]) * C0; }, 0x80D500FF); + } + if(sol) { + draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1],0)) * zpush(h[0]) * C0; }, 0x80D500FF); + } + if(nih) { + draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1]/log(3),0)) * zpush(h[0]/log(3)) * C0; }, 0x80D500FF); + } + } + + if(scaffoldb == 1) + for(int z=-5; z<=5; z++) + for(int sx=-5; sx<=5; sx++) + for(int sy=-5; sy<=5; sy++) { + shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(sx*levx,sy*levy,0)); + queuepoly(S, cgi.shSnowball, 0xFFFFFFFF); + fat_line(S, C0, S, lzpush(-levz) * C0, 0xFF0000FF, 2, 0.01); + for(int s=0; s<8; s++) { + fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+0)/8.,0,0)) * C0, + S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+1)/8.,0,0)) * C0, + 0xFF8000FF, 2, 0.01); + fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,levy*(s+0)/8.,0)) * C0, + S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,levy*(s+1)/8.,0)) * C0, + 0xFF8000FF, 2, 0.01); + } + } + + if(scaffoldb == 2 && hyperbolic) { + for(auto h: map534_nodes) queuepoly(V * rgpushxto0(h), cgi.shSnowball, 0xFFFFFFFF); + for(auto h: map534_edges) fat_line(V, h.first, V, h.second, 0xFFFFFFFF, 2, 0.01); + } + } + +/* + static bool first = true; + if(first) println(hlog, tie(minx, maxx), tie(miny, maxy), tie(minz, maxz)); + first = false; +*/ + +string losowo = "1100002102001211"; + +void draw_shape(const shiftmatrix& V, vector tab, color_t col, ld mul = 1) { + int n = isize(tab); + for(int i=0; iitem == itHyperstone) c->item = itNone; + if(false) { + if(c == cwt.at) chess.render(V); + } + else { + auto co = euc::full_coords2(c); + char& chr = xmap[gmod(co.second, 20)][gmod(co.first, 20)]; + char ch = chr; + if(no_floor && ch != '^') ch = '<'; + + // if(co.first == 0 && co.second == 0) bunny.render(V); + switch(ch) { + case 'r': + if(GDIM == 3 && with_models) { + rat.render(V); + static bool first = true; + if(first) println(hlog, tie(minx, maxx), tie(miny, maxy), tie(minz, maxz)); + first = false; + } + else { + drawMonsterType(moMouse, c, V * spin(-135._deg), 0x804000, 0, 0x804000); + } + break; + case '<': + c->wall = waChasm; + domek1.erase(c); domek2.erase(c); + fat_line(V, cgi.emb->logical_to_actual(point31(0.5, 0.5, 0)), V, cgi.emb->logical_to_actual(point31(0.5, -0.5, 0)), 0xFFFFFFFF, 2, 0.001); + fat_line(V, cgi.emb->logical_to_actual(point31(0.5, 0.5, 0)), V, cgi.emb->logical_to_actual(point31(-0.5, 0.5, 0)), 0xFFFFFFFF, 2, 0.001); + break; + case 'u': { + if(GDIM == 3 && with_models) { + lily.render(V); + c->item = itNone; + } + else c->item = itWet; + break; + } + case 'v': { + if(GDIM == 3 && with_models) duck.render(V); + else { + draw_shape(V, {-0.164988, 0.0033671, -0.114197, 0.0638159, 0.0401905, 0.063635, 0.10735, 0.0268375, 0.10735, -0.0268375, 0.0401905, -0.063635, -0.114197, -0.0638159, -0.164988, -0.0033671, }, 0xC0C0C0FF, 2); + draw_shape(V, {-0.0753584, 0.00669852, -0.111558, 0.0184533, -0.0812589, 0.0326711, -0.161669, 0.0479953, -0.10074, 0.0780737, -0.0184331, 0.0896519, 0.0830064, 0.065399, 0.113269, 0.0335611, 0.117466, 0.0151028, 0.117466, -0.0151028, 0.113269, -0.0335611, 0.0830064, -0.065399, -0.0184331, -0.0896519, -0.10074, -0.0780737, -0.161669, -0.0479953, -0.0812589, -0.0326711, -0.111558, -0.0184533, -0.0753584, -0.00669852, }, 0x806010FF, 2); + draw_shape(V, {0.164139, 0.0109426, 0.200142, 0.0185786, 0.239985, 0.00848005, 0.239985, -0.00848005, 0.200142, -0.0185786, 0.164139, -0.0109426, }, 0xE0E000FF, 2); + draw_shape(V, {0.0820785, 0.00670028, 0.0963908, 0.0243072, 0.121722, 0.0352575, 0.159071, 0.0361908, 0.183838, 0.028672, 0.199268, 0.00844354, 0.199268, -0.00844354, 0.183838, -0.028672, 0.159071, -0.0361908, 0.121722, -0.0352575, 0.0963908, -0.0243072, 0.0820785, -0.00670}, 0x106010FF, 2); + } + break; + } + case 'B': + if(GDIM == 3 && with_models) bunny.render(V); + else { + auto V1 = V * spin270(); + draw_shape(V1, {-0.272437, 0.00681093, -0.247911, 0.0339604, -0.199391, 0.0506926, -0.165034, 0.0336804, -0.151363, 0.0100908, -0.151363, -0.0100908, -0.165034, -0.0336804, -0.199391, -0.0506926, -0.247911, -0.0339604, -0.272437, -0.00681093, }, 0xFFFFFFFF, 2); + draw_shape(V1, {-0.209613, 0.00676172, -0.161797, 0.0741567, -0.107602, 0.100877, 0.0033535, 0.103959, 0.100724, 0.0738645, 0.134426, 0.0369672, 0.14796, 0.00672545, 0.14796, -0.00672545, 0.134426, -0.0369672, 0.100724, -0.0738645, 0.0033535, -0.103959, -0.107602, -0.100877, -0.161797, -0.0741567, -0.209613, -0.00676172, }, 0xC0C0C0FF, 2); + draw_shape(V1, {0.0502023, 0.0167341, 0.0737312, 0.0536227, 0.151647, 0.0876183, 0.240969, 0.0441211, 0.272441, 0.0102165, 0.272441, -0.0102165, 0.240969, -0.0441211, 0.151647, -0.0876183, 0.0737312, -0.0536227, 0.0502023, -0.0167341, }, 0xD0D0D0FF, 2); + draw_shape(V1, {0.103977, 0.0268328, 0.0267753, 0.0468568, -0.0536042, 0.063655, -0.00335237, 0.0972189, 0.094003, 0.080574, 0.144678, 0.0571982, 0.154836, 0.0437579, 0.134405, 0.0268809, }, 0xC0C0C0FF, 2); + draw_shape(V1 * MirrorY, {0.103977, 0.0268328, 0.0267753, 0.0468568, -0.0536042, 0.063655, -0.00335237, 0.0972189, 0.094003, 0.080574, 0.144678, 0.0571982, 0.154836, 0.0437579, 0.134405, 0.0268809, }, 0xC0C0C0FF, 2); + draw_shape(V1, {0.168425, 0.0235794, 0.178774, 0.0505965, 0.188982, 0.0269974, }, 0xC00000FF, 2); + draw_shape(V1 * MirrorY, {0.168425, 0.0235794, 0.178774, 0.0505965, 0.188982, 0.0269974, }, 0xC00000FF, 2); + } + break; + case 't': + if(GDIM == 2) c->wall = waRoundTable; else if(with_models && !light_models) { + c->wall = waNone; + table.render(V); + cheese.render(V); + coffee1.render(V); + coffee2.render(V); + } + break; + case 'C': + if(GDIM == 3 && with_models) maxwellcat.render(V); + else { + dynamicval b(mapeditor::drawplayer, true); + drawPlayer(moPlayer, c, V * spin90(), 0xFFFFFFFF, 0); + } + if(move_cat) { + move_cat = false; + mapeditor::drawplayer = true; + chr = '.'; + cwt.at = c; + vid.sspeed = -5; + cwt.spin = 1; + vid.axes = 0; + } + break; + case 'e': + if(GDIM == 3 && draw_digger == 2) digger.render(V); + break; + case 'K': { + int a = gmod(co.first + co.second, 3); + if(GDIM == 3 && with_models) { + auto gtulip = [&] (int a, int b) -> tulipmodel& { char ch = losowo[5*a+b]; if(ch == '0') return tulip; if(ch == '1') return tulip1; if(ch == '2') return tulip2; return tulip2; }; + gtulip(a, 0).render(V); + gtulip(a, 1).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(1/3., 1/3., 0))); + gtulip(a, 2).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(1/3., -1/3., 0))); + gtulip(a, 3).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(-1/3., 1/3., 0))); + gtulip(a, 4).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(-1/3., -1/3., 0))); + } + else { + vector tcols = {0xFFFF80FF, 0xFF1010FF, 0xC000C0FF}; + draw_shape(V*spin90(), {-0.202738, 0.0236527, -0.145213, 0.135082, -0.0438177, 0.1719, 0.0708783, 0.178883, 0.220846, 0.125712, 0.120989, 0.0705769, 0.219991, 0.00338448, 0.219991, -0.00338448, 0.120989, -0.0705769, 0.220846, -0.125712, 0.0708783, -0.178883, -0.0438177, -0.1719, -0.145213, -0.135082, -0.202738, -0.0236527}, tcols[a], 2); + } + break; + } + case 'H': + if(GDIM == 3) draw_hedge(V); + else queuepoly(V, cgi.shGem[0], 0xFF00FF); + break; + case '^': { + c->wall = no_floor ? waChasm : waNone; + auto ax = co.first - scaffoldx_move * 20; + auto ay = co.second - scaffoldy_move * 20; + if(ax >= 0 && ay >= 0 && ax < 20 && ay < 20) + draw_scaffold(V); + break; + } + case '>': + c->wall = draw_digger ? waChasm : waNone; + break; + } + if(with_chess) chess.get_split().render(V, gmod(co.first, 20), gmod(co.second, 20)); + } + return false; + } + +ld fov, otanfov; + +void switch_fpp_fixed() { + auto& cd = current_display; + transmatrix tView; + ld ys; + + tView = View; + otanfov = (cd->xsize/2) / cd->radius * 2; + auto d = vid.depth; + + if(GDIM == 3) invoke_embed(geom3::seNone); + else { + invoke_embed(geom3::seDefault); + activate(edefault); + } + if(GDIM == 3) { + // pconf.camera_angle = 90; + + ld tfov = vid.fov * degree / 2; + cd->tanfov = tan(tfov); + // tanfov * z + depth = fov + // z = (fov - depth) / tanfov + ld yshift = (otanfov - vid.depth) / cd->tanfov; + // drawthemap(); + // centerpc(INF); + // shift_view(zpush0(yshift)); + println(hlog, "yshift = ", yshift, " from ", vid.yshift); + // playermoved = false; + // vid.fov = fov; + // vid.yshift = yshift; + View = Id; + for(int a=0; a<2; a++) + for(int b=0; b<2; b++) + View[a][b] = tView[a][b]; + for(int a=0; a<2; a++) + View[a][3] = tView[a][2]; + println(hlog, tie(tView[2][0], tView[2][1])); + // rotate_view(cspin90(2, 1)); + shift_view(zpush0(yshift)); + playermoved = false; + } + else { + pconf.camera_angle = 0; + vid.yshift = 0; + ys = tView[2][3]; + println(hlog, "ys = ", ys, " from ", tView); + otanfov = ys * cd->tanfov + d; + cd->radius = cd->xsize / otanfov; + pconf.scale = cd->radius / cd->scrsize; + } + if(GDIM == 2) { + View = spin90() * View; + View[0][2] = tView[0][3]; + View[1][2] = tView[1][3]; + } + } + +void load_anim(string fname) { + fhstream f(fname, "r"); + mapstream::cellbyid = ac; + while(isize(mapstream::cellbyid) < 400 * 400) for(auto c: ac) mapstream::cellbyid.push_back(c); + smoothcam::enable(); + smoothcam::load_animation(f); + } + +void append_anim(string fname) { + smoothcam::backup(); + load_anim(fname); + smoothcam::append_backup(); + } + +void save_anim(string fname) { + fhstream f(fname, "w"); + for(int i=0; ic); + if(co == gp::loc{0, 0}) + draw_star(cw->V, cgi.shSun, 0xFFFF00FF); + if(domek2.count(cw->c)) { + color_t col = (domcol << 8) | 0xFF; + color_t wcol1 = (gradient(0, domcol, 0, .9, 1) << 8) | 0xFF; + color_t wcol2 = (gradient(0, domcol, 0, .8, 1) << 8) | 0xFF; + if(domek1.count(cw->c)) forCellIdEx(c2, i, cw->c) if(!domek1.count(c2)) { + placeSidewall(cw->c, i, SIDE_HIGH, cw->V, (i&1)?wcol1:wcol2); + placeSidewall(cw->c, i, SIDE_HIGH2, cw->V, (i&1)?wcol1:wcol2); + } + forCellIdEx(c2, i, cw->c) if(!domek2.count(c2)) { + placeSidewall(cw->c, i, SIDE_HIGH2, cw->V, (i&1)?wcol1:wcol2); + } + if(domek1.count(cw->c) != domek2.count(cw->c)) + draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE_HIGH], col, PPR::REDWALL); + if(domek2.count(cw->c)) + draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE_HIGH2], (domroof << 8) | 0xFF, PPR::REDWALL); + + auto co = euc::full_coords2(cw->c); + int x = gmod(co.first, 20); + int y = gmod(co.second, 20); + char ch = xmap[y][x]; + + if(ch == 'O') { + placeSidewall(cw->c, 1, SIDE_HIGH, cw->V, 0xC0E0FFC0); + ((dqi_poly&)(*ptds.back())).tinf = nullptr; + } + } + + color_t skycol = our_skycolor(cw->c); + g_add_to_sky(cw->c, cw->V, skycol, skycol); + return true; + } + +int cells_drawn = 50, split_qty = 1; + +void build_map() { + for(cell *c: bac) { + c->land = laCanvas; + c->wall = waNone; // Chasm; // waNone; + c->item = itNone; + c->monst = moNone; + c->mpdist = 0; + c->landparam = 0x205020; + auto co = euc::full_coords2(c); + int x = gmod(co.first, 20); + int y = gmod(co.second, 20); + ac[x + 20*y + gmod(gdiv(co.first, 20), periods) * 400 + gmod(gdiv(co.second, 20), periods) * 400 * periods] = c; + char ch = xmap[y][x]; + switch(ch) { + case 'x': + c->landparam = ((x+y) & 1) ? 0x807020 : 0xFFE080; + break; + case '1': + c->wall = waRed3; + domek2.insert(c); + c->landparam = domcol; + break; + case '2': + c->wall = waRed2; + break; + case '3': + c->wall = waRed3; + break; + case '#': + c->wall = waBarrier; + break; + case 'T': + c->wall = waCTree; + break; + case 'D': + c->wall = waWaxWall; + domek1.insert(c); + domek2.insert(c); + c->landparam = domcol; + break; + case 't': + case 'r': + case 'd': + c->wall = waNone; + domek2.insert(c); + c->landparam = domcolf; + break; + case '+': + c->wall = waNone; + domek2.insert(c); + c->landparam = domcol; + break; + case 'O': + c->wall = waWaxWall; + domek2.insert(c); + c->landparam = domcol; + break; + case 'u': + case 'v': + case '~': + c->wall = waShallow; + break; + case 'p': + c->land = laCrossroads; + floorcolors[laCrossroads] = 0x808080; + break; + // c->landparam = 0xC0C080; + case '>': + if(draw_digger) c->wall = waChasm; + break; + } + } + } + +void enable() { + arg::shift(); hmul = arg::argf(); + + stop_game(); + never_invert = true; + vid.wallmode = 3; + vid.monmode = 2; + + geometry = gArchimedean; + variation = eVariation::pure; + arcm::current.parse("4^5"); + start_game(); + resetview(); + View = spin(45._deg); + if(1) { + dynamicval d(min_cells_drawn, cells_drawn); + // vid.cells_generated_limit = 9999; + // vid.cells_drawn_limit = 9999; + // vid.use_smart_range = 2; + drawthemap(); + } + auto f = [] (hyperpoint h) { return deparabolic13(h); }; + + + set seen; + for(auto c: dcal) if(gmatrix.count(c)) { + map54_nodes.push_back(f(unshift(gmatrix[c]*C0))); + seen.insert(c); + } + for(auto c: dcal) if(seen.count(c)) forCellEx(c1, c) if(seen.count(c1)) if(c1 hs(qty+1); + hs[0] = h; hs[qty] = h1; + for(int a=qty/2; a; a/=2) for(int i=0; i dg(geometry, gSol); + dynamicval dr(nisot::rk_steps, 500); + ld x = coord; + start = C0; + middle = point31(0, x, 0); + auto bmiddle = point31(x, 0, 0); + target = point31(x, x, 0); + nlh = inverse_exp_newton(target, 200); + nlh[2] *= -1; + println(hlog, "best newton: ", hypot_d(3, nlh), " via ", nlh, " result ", nisot::numerical_exp(nlh)); + nlh1 = inverse_exp(shiftless(middle)); + nlh2 = inverse_exp(shiftless(bmiddle)); + println(hlog, "intermediate: ", hypot_d(3, nlh1) * 2, " via ", nlh1); + println(hlog, "Pythagoras: ", x * sqrt(2)); + } + + add_stat(mode, [id, coord] { + cmode |= sm::SIDE; + calcparam(); + + vid.cells_drawn_limit = 0; + drawthemap(); + + // flat_model_enabler fme; + initquickqueue(); + + solv_grapher g(MirrorZ * ypush(5 * angle / 90._deg) * cspin(1, 2, .9 * angle / 90._deg) * spin(angle/2) * xyzscale(lerp(1, 0.8, angle / 90._deg))); + + ld maxtime = 10 * sqrt(2) + 5; + auto frac_of = [&] (ld t, ld z) { return t - z * floor(t/z); }; + + ld t = inHighQual ? geodesic_t : frac_of((ticks - geo_zero) / 500, maxtime); + + auto draw_path = [&] (auto f, color_t col) { + vid.linewidth *= 10; + for(ld t=0; t<=maxtime; t+=1/16.) curvepoint(f(t)); + queuecurve(g.T, col, 0, PPR::LINE); + + auto be_shadow = [&] (hyperpoint& h) { + // ld part = 1 - angle / 90._deg; + // h[0] += h[2] * part / 10; + h[2] = 0; + }; + + for(ld t=0; t<=25; t+=1/16.) { + hyperpoint h = f(t); + be_shadow(h); + curvepoint(h); + } + queuecurve(g.T, col & 0xFFFFFF40, 0, PPR::LINE); + vid.linewidth /= 10; + + hyperpoint eaglepos = f(t); + hyperpoint next_eaglepos = f(t + 1e-2); + + auto z = eaglepos[2]; + + // queuepolyat(g.pos(x+z * .1,y,1.5) * spin(s), cgi.shEagle, 0x40, PPR::MONSTER_SHADOW).outline = 0; + drawMonsterType(moEagle, nullptr, g.T * eupush(eaglepos) * solvscale(z) * rspintox(next_eaglepos - eaglepos) * xyzscale(2), col >> 8, t, 0); + + be_shadow(eaglepos); + be_shadow(next_eaglepos); + + auto& bp = cgi.shEagle; + + if(bp.she > bp.shs && bp.she < bp.shs + 1000) { + auto& p = queuepolyat(g.T * eupush(eaglepos) * solvscale(z) * rspintox(next_eaglepos - eaglepos) * xyzscale(2), bp, 0x18, PPR::TRANSPARENT_SHADOW); + p.outline = 0; + p.subprio = -100; + p.offset = bp.shs; + p.cnt = bp.she - bp.shs; + p.flags &=~ POLY_TRIANGLES; + p.tinf = NULL; + return; + } + }; + + color_t pythagoras = 0xcd7f32FF; + color_t hyperb = 0xaaa9adFF; + color_t solv = 0xFFD500FF; + + write_in_space(g.T * rgpushxto0(point31(-.5, -.5, 1)) * MirrorY * zpush(-1), 72, 1, "A", 0xFF); + write_in_space(g.T * rgpushxto0(point31(coord+.5, coord+.5, 1)) * MirrorY * zpush(-1), 72, 1, "B", 0xFF); + if(id >= 1) write_in_space(g.T * rgpushxto0(point31(0, coord+.5, 1)) * MirrorY * zpush(-1), 72, 1, "C", 0xFF); + + if(id >= 0) + draw_path([&] (ld t) { return t < coord * sqrt(2) ? point31(t/sqrt(2), t/sqrt(2), 0) : target; }, pythagoras); + + if(id >= 1) + draw_path([&] (ld t) { + ld len = hypot_d(3, nlh1); + dynamicval g(geometry, gSol); + if(t < len) + return nisot::numerical_exp(nlh1 * t / len); + else if(t < len*2) + return rgpushxto0(middle) * nisot::numerical_exp(nlh2 * (t-len) / len); + else return target; + }, hyperb); + + if(id >= 2) + draw_path([&] (ld t) { + ld len = hypot_d(3, nlh); + dynamicval g(geometry, gSol); + if(t < len) + return nisot::numerical_exp(nlh * t / len); + else + return target; + }, solv); + + auto cat = [] (PPR x) { + if(x == PPR::MONSTER_SHADOW) return 1; + else if(x == PPR::MONSTER_BODY) return 2; + else return 0; + }; + + for(int i=1; iprio) < cat(ptds[i-1]->prio)) { + swap(ptds[i], ptds[i-1]); + i--; + } + else i++; + + quickqueue(); + + dialog::init(); + dialog_may_latex("\\textsf{from $(0,0,0)$ to $(10,10,0)$}", "from (0,0,0) to (10,10,0)", forecolor, 150); + + dialog::addBreak(100); + dialog_may_latex("\\textsf{XY plane}", "XY plane", pythagoras >> 8); + dialog_may_latex("\\textsf{$"+fts(coord)+"\\sqrt{2}$ (Pythagoras)}", fts(coord) + "√2 (Pythagoras)", pythagoras >> 8); + ld len = coord * sqrt(2); + dialog_may_latex("\\textsf{$" + fts(len) + "$}", fts(len), pythagoras >> 8); + + if(id >= 1) { + dialog::addBreak(100); + dialog_may_latex("\\textsf{YZ + XZ}", "YZ + XZ", hyperb >> 8); + dialog_may_latex("\\textsf{hyperbolic geodesics}", "hyperbolic geodesics", hyperb >> 8); + ld len = 2 * hypot_d(3, nlh1); + dialog_may_latex("\\textsf{$" + fts(len) + "$}", fts(len), hyperb >> 8); + } + else dialog::addBreak(300); + + if(id >= 2) { + dialog::addBreak(100); + dialog_may_latex("\\textsf{optimal}", "optimal", solv >> 8); + dialog_may_latex("\\textsf{no sharp bends}", "no sharp bends", solv >> 8); + ld len = hypot_d(3, nlh); + dialog_may_latex("\\textsf{$"+fts(len)+"$}", fts(len), solv >> 8); + } + else dialog::addBreak(300); + + dialog::display(); + + return false; + }); + } + +ld square_diagram_size = 10; + +void enable_square_diagram() { + param_f(square_diagram_size, "square_diagram_size"); + rogueviz::rv_hook(hooks_frame, 100, [] { + auto p = [] (ld x, ld y) { return hpxy(x, y); }; + for(int i=0; i<4; i++) { + ld si = square_diagram_size; + ld big = 100; + curvepoint(p(si, big)); + curvepoint(p(si, -big)); + curvepoint(p(big, -big)); + curvepoint(p(big, big)); + curvepoint(p(si, big)); + queuecurve(shiftless(Id) * cspin(0, 1, i*90._deg), 0, 0xFF, PPR::CIRCLE).flags |= POLY_ALWAYS_IN; + } + }); + } + +using namespace rogueviz::pres; + +string defs = + "\\def\\map{m}" + "\\def\\VofH{V}" + "\\def\\dist{\\delta}" + "\\def\\ra{\\rightarrow}" + "\\def\\bbH{\\mathbb{H}}" + "\\def\\bbE{\\mathbb{E}}" + "\\renewcommand{\\rmdefault}{\\sfdefault}\\sf" + ; + +slide solv_slides[] = { + {"from A to B in Solv 1", 999, LEGAL::NONE | QUICKGEO | NOTITLE, + "not written" + , + [] (presmode mode) { + println(hlog, "A mode ", int(mode)); + empty_screen(mode); + geodesic_screen(mode, 0); + no_other_hud(mode); + } + }, + {"from A to B in Solv 2", 999, LEGAL::NONE | QUICKGEO | NOTITLE, + "not written" + , + [] (presmode mode) { + println(hlog, "B mode ", int(mode)); + empty_screen(mode); + geodesic_screen(mode, 1); + no_other_hud(mode); + } + }, + {"from A to B in Solv 3", 999, LEGAL::NONE | QUICKGEO | NOTITLE, + "not written" + , + [] (presmode mode) { + println(hlog, "C mode ", int(mode)); + empty_screen(mode); + geodesic_screen(mode, 2); + no_other_hud(mode); + } + }, + + {"Euler's polyhedron formula", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, + "-show the formula", + [] (presmode mode) { + latex_slide(mode, defs+R"=( + {\color{remph}Euler's polyhedron formula: } + \begin{itemize} + \item $F+V-E = 2$ + \item $F$ -- the number of {\color{remph}faces} (square grid: the number of squares $n$) + \item $V$ -- the number of {\color{remph}vertices} (square grid: also $n$) + \item $E$ -- the number of {\color{remph}edges} (square grid: $2n$) + \item $F + V - E = n + n - 2n = 0 = 2$ + \end{itemize} + )=", sm::NOSCR, 150); + }}, + + {"final slide", 123, LEGAL::ANY | NOTITLE | QUICKSKIP | FINALSLIDE, + "FINAL SLIDE", + + [] (presmode mode) { + empty_screen(mode); + add_stat(mode, [] { + dialog::init(); + color_t d = dialog::dialogcolor; + + dialog::addTitle("Thanks for your attention!", 0xC00000, 200); + + dialog::addBreak(100); + + dialog::addTitle("twitter.com/zenorogue/", d, 150); + + dialog::display(); + return true; + }); + no_other_hud(mode); + } + }, + }; + +auto embchess_ah = + arg::add3("-embchess", enable) ++ arg::add3("-embperiods", [] { arg::shift(); periods = arg::argi(); }) ++ arg::add3("-emb-noceil", [] { + rogueviz::rv_hook(hooks_ceiling, 100, [] (celldrawer*) { return true; }); + }) ++ arg::add3("-chessmul", [] { arg::shift(); hmul = arg::argf(); }) ++ arg::add3("-embset", [] { + arg::shift(); string ss = arg::args(); + for(auto& e: embsets) if(appears(e.name, ss)) activate(e); + }) ++ arg::add3("-embscaffold", [] { + arg::shift(); scaffoldx = arg::argi(); + arg::shift(); scaffoldy = arg::argi(); + arg::shift(); scaffoldb = arg::argi(); + }) ++ arg::add3("-embscaffold-move", [] { + arg::shift(); scaffoldx_move = arg::argi(); + arg::shift(); scaffoldy_move = arg::argi(); + }) ++ arg::add3("-embwchess", [] { with_chess = !with_chess; }) ++ arg::add3("-embfix", [] { arg::shift(); fix_chess = arg::argf(); }) ++ arg::add3("-embwmodel", [] { with_models = !with_models; }) ++ arg::add3("-embwmlight", [] { with_models = true; light_models = true; }) ++ arg::add3("-embwdig", [] { arg::shift(); draw_digger = arg::argi(); }) ++ arg::add3("-embload", [] { arg::shift(); load_anim(arg::args()); }) ++ arg::add3("-embappend", [] { arg::shift(); append_anim(arg::args()); }) ++ arg::add3("-embsave", [] { arg::shift(); save_anim(arg::args()); }) ++ arg::add3("-embt0", [] { smoothcam::animate_on = false; smoothcam::handle_animation(0); playermoved = false; }) ++ arg::add3("-embt1", [] { smoothcam::animate_on = false; smoothcam::handle_animation(1-1e-7); playermoved = false; }) ++ arg::add3("-embmin", [] { arg::shift(); cells_drawn = arg::argi(); }) ++ arg::add3("-emb-chess-moves", [] { arg::shift(); chess_moves = arg::argi(); }) ++ arg::add3("-emb-sqd", enable_square_diagram) ++ arg::add3("-embtrans-test", [] { arg::shift(); transition_test(arg::argf()); }) ++ arg::add3("-emb-no-floor", [] { no_floor = true; }) ++ arg::add3("-embtrans", [] { + arg::shift(); anims::videofile = arg::args(); + arg::shift(); ld a = arg::argf(); + arg::shift(); ld b = arg::argf(); + arg::shift(); int t = arg::argi(); + transition(a, b, t); + }) ++ arg::add3("-avp", [] { semidirect_rendering = true; vid.consider_shader_projection = false; }) ++ arg::add3("-embforward", [] { + arg::shift(); int t = arg::argi(); + arg::shift(); anims::videofile = arg::args(); + arg::shift(); ld d = arg::argf(); + animate_forward(d, t); + }) ++ arg::add3("-emb-goforward", [] { + arg::shift(); ld d = arg::argf(); + for(int i=0; i<1000; i++) { + shift_view(ztangent(-d / 1000.)); + optimizeview(); + spinEdge(100); + } + }); + ; + +auto embchess_show = + addHook_slideshows(100, [] (tour::ss::slideshow_callback cb) { + cb(XLAT("Solv geodesics"), &solv_slides[0], 'S'); + }); +}}