mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 05:52:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1823 lines
		
	
	
		
			63 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1823 lines
		
	
	
		
			63 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "rogueviz.h"
 | |
| 
 | |
| // for this video: https://youtu.be/Rhjv_PazzZE
 | |
| 
 | |
| namespace hr {
 | |
| 
 | |
| namespace embchess {
 | |
| 
 | |
| namespace smoothcam { using namespace rogueviz::smoothcam; }
 | |
| 
 | |
| /** 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;
 | |
| 
 | |
| vector<pair<hyperpoint, hyperpoint>> map54_edges;
 | |
| vector<hyperpoint> map54_nodes;
 | |
| 
 | |
| vector<pair<hyperpoint, hyperpoint>> map534_edges;
 | |
| vector<hyperpoint> map534_nodes;
 | |
| 
 | |
| struct embset {
 | |
|   string name;
 | |
|   geom3::eSpatialEmbedding se;
 | |
|   ld walls, scale, depth, eye, sun, sky, star;
 | |
|   embset(const string& n, geom3::eSpatialEmbedding se, ld walls, ld scale, ld depth, ld eye, ld sun, ld sky, ld star) :
 | |
|     name(n), se(se), walls(walls), scale(scale), depth(depth), eye(eye), sun(sun), sky(sky), star(star) {}
 | |
|   embset() {}
 | |
|   };
 | |
| 
 | |
| 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();
 | |
|   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();
 | |
|   pmodel = default_model();
 | |
|   };
 | |
| 
 | |
| embset emb_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("default", geom3::seDefault, 1.2, 0, 0, 1.5, 0.333333, 10, 9);
 | |
| embset edefaulti = embset("default", geom3::seDefault, -1.2, 0, 0, 1.5, 0.333333, 10, 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("in cylinder E", geom3::seCylinderE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset eoutcyl = embset("out cylinder E", geom3::seCylinderE, -1.2, M_PI/10, 0, 1.5, 0.3, 10, 9);
 | |
| embset eouthoro = embset("out horosphere", geom3::seLowerCurvature, 1.2, 0.1, 0, 1.5, 0.25, 8, 7.5);
 | |
| embset einhoro = embset("in horosphere", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 12, 11);
 | |
| embset einhoro_small = embset("in horosphere (small sky)", geom3::seLowerCurvature, -1.2, 0.1, 0, 1.5, 0.25, 18, 17);
 | |
| embset esolv = embset("solv", geom3::seSol, 1.2, 0.1, 0, 1.5, 0.25, 12, 11);
 | |
| embset einnih = embset("in NIH", geom3::seNIH, -1.2, 0.1, 0, 1.5, 0.25, 12, 11);
 | |
| embset eoutnih = embset("out NIH", geom3::seNIH, 1.2, 0.1, 0, 1.5, 0.25, 8, 7.5);
 | |
| embset eclifford = embset("Clifford", geom3::seCliffordTorus, 1.2, M_PI/10, -0.0561826, 1.5, 0.25, 2.55, 2.3);
 | |
| embset enil = embset("Nil flat", geom3::seNil, 1.2, 0.1, 0, 1.5, 0.25, 12, 11);
 | |
| embset esl2 = embset("SL(2,R) flat", geom3::seSL2, 1.2, 0.1, 0, 1.5, 0.25, 12, 11);
 | |
| embset eincylh = embset("in cylinderH", geom3::seCylinderH, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset eincylhe = embset("in cylinderHE", geom3::seCylinderHE, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset eincylnil = embset("in cylinder Nil", geom3::seCylinderNil, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset eincylsl = embset("in cylinder SL(2,R)", geom3::seCylinderSL2, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset einhorocyl = embset("in horocylinder", geom3::seCylinderHoro, -1.2, M_PI/10, 0, 1.5, 0.10472, 8, 7.5);
 | |
| embset eouthorocyl = embset("out horocylinder", geom3::seCylinderHoro, 1.2, M_PI/10, 0, 1.5, 0.10472, 4, 3.5);
 | |
| embset eprodh_flat = embset("hyperbolic product (flat)", geom3::seProductH, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset eprodh_concave = embset("hyperbolic product (concave)", geom3::seProductH, 1.2, M_PI/10, 1, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset eprods_flat = embset("spherical product (flat)", geom3::seProductS, 1.2, M_PI/10, 0, 1.5, 0.10472, 2.6, 2.4);
 | |
| embset eprods_concave = embset("spherical product (concave)", geom3::seProductS, 1.2, M_PI/10, 0.8333, 1.5, 0.10472, 2.6, 2.4);
 | |
| 
 | |
| embset& edok() { return vid.wall_height > 0 ? edefault : edefaulti; }
 | |
| 
 | |
| vector<embset> 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<string> 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#"},
 | |
|   };
 | |
| 
 | |
| void build_map();
 | |
| 
 | |
| ld hmul = 1;
 | |
| 
 | |
| set<cell*> house1, house2;
 | |
| 
 | |
| vector<cell*> 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<pair<int, int>, vector<shared_ptr<object>>> objs_at;
 | |
|   void render(const shiftmatrix& V, int x, int y);
 | |
|   };
 | |
| 
 | |
| struct chessmodel : public model {
 | |
| 
 | |
|   void process_triangle(vector<hyperpoint>& hys, vector<hyperpoint>& 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<parts; a++)
 | |
|     for(int b=0; b<parts-a; b++) {
 | |
|       tri(a, b);
 | |
|       tri(a+1, b);
 | |
|       tri(a, b+1);
 | |
|       if(a+b < parts-1) {
 | |
|         tri(a, b+1);
 | |
|         tri(a+1, b);
 | |
|         tri(a+1, b+1);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   chessmodel(string a, string b) : model(a,b) {}
 | |
| 
 | |
|   void split(model_data& md, split_model_data& smd);
 | |
| 
 | |
|   split_model_data& get_split() {
 | |
|     auto& md = (unique_ptr<split_model_data>&) cgi.ext[fname + "-SPLIT"];
 | |
|   
 | |
|     if(!md) {
 | |
|       md = std::make_unique<split_model_data>();
 | |
|       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<pair<int, int>, map<color_t, vector<pair<hyperpoint, glvertex>>>> mm;
 | |
|   for(auto& obj: md.objs) {
 | |
|     for(int i=obj->sh.s; i<obj->sh.e; i+=3) {
 | |
|       hyperpoint ctr = Hypc;
 | |
|       array<hyperpoint, 3> 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<object>());
 | |
|     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<hyperpoint> hs;
 | |
|       for(int i=obj->sh.s; i<obj->sh.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");
 | |
| 
 | |
| 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[2] = lerp(cgi.WATERLEVEL, 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[2] = lerp(cgi.WATERLEVEL, 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;
 | |
| 
 | |
|     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<char, hx*hx*hx> hedge_visited;
 | |
| array<int, 6> hdirs = {1, hx, hx*hx, -1, -hx, -hx*hx};
 | |
| 
 | |
| array<vector<int>, hx*hx*hx> hedge_dirs;
 | |
| 
 | |
| int hstart;
 | |
| 
 | |
| void construct_hedge() {
 | |
|   for(int x=0; x<hx*hx*hx; x++) hedge_visited[x] = false;
 | |
|   hstart = (hx/2)+(hx/2)*hx;
 | |
|   hedge_visited[hstart] = true;
 | |
|   vector<int> inorder = {hstart};
 | |
|   for(int i=0; i<hx*hx*hx; i++) {
 | |
|     int at = inorder[i];
 | |
|     for(int dir: {0, 1, 3, 4, 2, 5}) {
 | |
|       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);
 | |
|       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<hyperpoint, 3> 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<object> ();
 | |
|     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<model_data>&) cgi.ext["hedge"];
 | |
|   if(!md) {
 | |
|     md = std::make_unique<model_data>();
 | |
|     create_hedge(*md);
 | |
|     }
 | |
|   md->render(V);  
 | |
|   }
 | |
| 
 | |
| void fat_line(const shiftmatrix& V1, const hyperpoint h1, const shiftmatrix& V2, const hyperpoint h2, color_t col, int prec, ld lw) {
 | |
|   dynamicval<bool> df(fat_edges, true);
 | |
|   dynamicval<ld> dlw(vid.linewidth, lw);
 | |
|   gridline(V1, h1, V2, h2, col, prec);
 | |
|   }
 | |
| 
 | |
| int scaffoldx = 0, scaffoldy = 0, scaffoldb = 0, scaffoldx_move = 0, scaffoldy_move;
 | |
| 
 | |
| template<class T> 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);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| string fixed_random_digits = "1100002102001211";
 | |
| 
 | |
| void draw_shape(const shiftmatrix& V, vector<ld> tab, color_t col, ld mul = 1) {
 | |
|   int n = isize(tab);
 | |
|   for(int i=0; i<n; i+=2) curvepoint(hpxy(tab[i]*mul, tab[i+1]*mul));
 | |
|   curvepoint(hpxy(tab[0]*mul, tab[1]*mul));
 | |
|   queuecurve(V, 0xFF, col, PPR::MONSTER_LEG);
 | |
|   }
 | |
| 
 | |
| bool draw_chess_at(cell *c, const shiftmatrix& V) {
 | |
|   if(c->item ==	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);
 | |
|           }
 | |
|         else {
 | |
|           drawMonsterType(moMouse, c, V * spin(-135._deg), 0x804000, 0, 0x804000);
 | |
|           }
 | |
|         break;
 | |
|       case '<':
 | |
|         c->wall = waChasm;
 | |
|         house1.erase(c); house2.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(!cgtrader_models) break;
 | |
|         if(GDIM == 3 && with_models) {
 | |
|           lily.render(V);
 | |
|           c->item = itNone;
 | |
|           }
 | |
|         else c->item = itWet;
 | |
|         break;
 | |
|         }
 | |
|       case 'v': {
 | |
|         if(!cgtrader_models) break;
 | |
|         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(!cgtrader_models) break;
 | |
|         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<bool> 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(!cgtrader_models) break;
 | |
|         if(GDIM == 3 && draw_digger == 2) digger.render(V);
 | |
|         break;
 | |
|       case 'K': {
 | |
|         if(!cgtrader_models) break;
 | |
|         int a = gmod(co.first + co.second, 3);
 | |
|         if(GDIM == 3 && with_models) {
 | |
|           auto gtulip = [&] (int a, int b) -> tulipmodel& { char ch = fixed_random_digits[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<color_t> 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) {
 | |
|     ld tfov = vid.fov * degree / 2;
 | |
|     cd->tanfov = tan(tfov);
 | |
|     ld yshift = (otanfov - vid.depth) / cd->tanfov;
 | |
|     println(hlog, "yshift = ", yshift, " from ", vid.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]));
 | |
|     shift_view(zpush0(yshift)); 
 | |
|     playermoved = false;
 | |
|     }
 | |
|   else {
 | |
|     pconf.cam() = Id;
 | |
|     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; i<isize(ac); i++) mapstream::cellids[ac[i]] = i;
 | |
|   smoothcam::save_animation(f);
 | |
|   }
 | |
| 
 | |
| #if CAP_VIDEO
 | |
| void transition(ld a, ld b, int frames) {
 | |
|   anims::noframes = frames;
 | |
| 
 | |
|   auto _edok = edok();
 | |
|   auto cu = current();
 | |
|   auto vn = glhr::vnear_default;
 | |
|   auto vf = glhr::vfar_default;
 | |
| 
 | |
|   int lev = addHook(anims::hooks_anim, 100, [&] {
 | |
|     ld t = ticks / anims::period;
 | |
|     println(hlog, "transition, t = ", t);
 | |
|     indenter ind(2);
 | |
|     t = t * t * (3 - 2 * t);
 | |
|     t = lerp(a, b, t);
 | |
|     sightranges[geometry] = 50 * t;
 | |
|     glhr::vnear_default = vn * t;
 | |
|     glhr::vfar_default = vf * t;
 | |
|     activate(emb_lerp(_edok, cu, t));
 | |
|     });
 | |
|   anims::record_video();
 | |
|   delHook(anims::hooks_anim, lev);
 | |
|   activate(cu);
 | |
|   sightranges[geometry] = 50;
 | |
|   glhr::vnear_default = vn;
 | |
|   glhr::vfar_default = vf;
 | |
|   }
 | |
| 
 | |
| void animate_forward(ld d, int frames) {
 | |
|   anims::noframes = frames;
 | |
| 
 | |
|   ld lastt = 0;
 | |
| 
 | |
|   int lev = addHook(anims::hooks_anim, 100, [&] {
 | |
|     println(hlog, "centerover is ", centerover);
 | |
|     ld t = ticks / anims::period;
 | |
|     t = t * t * (3 - 2 * t);
 | |
|     shift_view(ztangent(-(t - lastt) * d));
 | |
|     lastt = t;
 | |
|     spinEdge(100);
 | |
|     anims::moved();
 | |
|     });
 | |
|   anims::record_video();
 | |
|   delHook(anims::hooks_anim, lev);
 | |
|   }
 | |
| 
 | |
| void transition_test(ld t) {
 | |
| 
 | |
|   auto _edok = edok();
 | |
|   auto cu = current();
 | |
|   auto vn = glhr::vnear_default;
 | |
|   auto vf = glhr::vfar_default;
 | |
| 
 | |
|   sightranges[geometry] = 50 * t;
 | |
|   glhr::vnear_default = vn * t;
 | |
|   glhr::vfar_default = vf * t;
 | |
|   activate(emb_lerp(_edok, cu, t));
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| bool adjust_to_period;
 | |
| 
 | |
| embset rescaled(const embset& e, ld p) {
 | |
|   auto e1 = e;
 | |
|   e1.scale /= p;
 | |
|   e1.sky *= p;
 | |
|   e1.star *= p;
 | |
|   return e1;
 | |
|   }
 | |
| 
 | |
| void embset_list() {
 | |
|   cmode = sm::SIDE | sm::MAYDARK;
 | |
|   gamescreen();
 | |
|   dialog::init(XLAT("embset list"), 0xFFFFFFFF, 150, 0);
 | |
|   dialog::start_list(900, 900, '1');
 | |
|   for(auto& e: embsets) {
 | |
|     dialog::addItem(e.name, dialog::list_fake_key++);
 | |
|     dialog::add_action([&e] {
 | |
|       activate(rescaled(e, periods));
 | |
|       });
 | |
|     }
 | |
|   dialog::end_list();
 | |
|   dialog::addBack();
 | |
|   dialog::display();  
 | |
|   }
 | |
| 
 | |
| void look_downwards() {
 | |
|   transmatrix T = View;
 | |
|   if(GDIM == 3) {
 | |
|     for(int i=0; i<3; i++) T[i][3] = T[3][i] = 0;
 | |
|     rotate_view(inverse(T));
 | |
|     ld x = T[3][0], y = T[3][1];
 | |
|     shift_view(point31(x+.5, y+.5, 0));
 | |
|     }
 | |
|   else {
 | |
|     for(int i=0; i<2; i++) T[i][2] = T[2][i] = 0;
 | |
|     rotate_view(inverse(T));
 | |
|     }
 | |
|   }
 | |
| 
 | |
| color_t domcol = 0xf8dba0;
 | |
| color_t domcolf = 0x785b20;
 | |
| color_t domroof = 0x802020;
 | |
| 
 | |
| color_t our_skycolor(cell *c) {
 | |
|   auto co = euc::full_coords2(c);
 | |
|   ld x = co.first * TAU / 20;
 | |
|   ld y = co.second * TAU / 20;
 | |
|   ld p = sin(x+2*y) + cos(3*x-y) + sin(x);
 | |
|   return gradient(0x4040FF, 0xFFFFFF, -3, p, 3);
 | |
|   }
 | |
| 
 | |
| bool chess_ceiling(celldrawer *cw) {
 | |
|   auto co = euc::full_coords2(cw->c);
 | |
|   if(co == gp::loc{0, 0}) 
 | |
|     draw_star(cw->V, cgi.shSun, 0xFFFF00FF);
 | |
|   if(house2.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(house1.count(cw->c)) forCellIdEx(c2, i, cw->c) if(!house1.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(!house2.count(c2)) {
 | |
|       placeSidewall(cw->c, i, SIDE::HIGH2, cw->V, (i&1)?wcol1:wcol2);
 | |
|       }
 | |
|     if(house1.count(cw->c) != house2.count(cw->c))
 | |
|       draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE::HIGH], col, PPR::RED1_TOP);
 | |
|     if(house2.count(cw->c))
 | |
|       draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE::HIGH2], (domroof << 8) | 0xFF, PPR::RED1_TOP);
 | |
| 
 | |
|     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;
 | |
|         house2.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;
 | |
|         house1.insert(c);
 | |
|         house2.insert(c);
 | |
|         c->landparam = domcol;
 | |
|         break;
 | |
|       case 't':
 | |
|       case 'r':
 | |
|       case 'd':
 | |
|         c->wall = waNone;
 | |
|         house2.insert(c);
 | |
|         c->landparam = domcolf;
 | |
|         break;
 | |
|       case '+':
 | |
|         c->wall = waNone;
 | |
|         house2.insert(c);
 | |
|         c->landparam = domcol;
 | |
|         break;
 | |
|       case 'O':
 | |
|         c->wall = waWaxWall;
 | |
|         house2.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;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| ld square_diagram_size = 1000;
 | |
| 
 | |
| void enable_square_diagram() {
 | |
|   rogueviz::rv_hook(hooks_frame, 100, [] {
 | |
|     if(square_diagram_size >= 1000) return;
 | |
|     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;
 | |
|       }
 | |
|     });
 | |
|   }
 | |
| 
 | |
| bool activated = false;
 | |
| 
 | |
| void o_key(o_funcs& v);
 | |
| 
 | |
| void build() {
 | |
|    auto& T0 = euc::eu_input.user_axes;
 | |
|    T0[0][0] = 20 * periods;
 | |
|    T0[1][1] = 20 * periods;
 | |
|    euc::eu_input.twisted = 0;
 | |
|    T0[0][1] = 0;
 | |
|    T0[1][0] = 0;
 | |
|    euc::build_torus3();
 | |
|    geometry = gEuclidSquare;
 | |
|    variation = eVariation::pure;
 | |
|    start_game();
 | |
| 
 | |
|   bac = currentmap->allcells();
 | |
|   ac.resize(bac.size());
 | |
|   build_map();
 | |
|   }
 | |
| 
 | |
| void enable() {
 | |
| 
 | |
|   if(activated) return;
 | |
|   tour::slide_backup(activated, true);
 | |
| 
 | |
|   if(!params.count("square_diagram_size")) param_f(square_diagram_size, "square_diagram_size");
 | |
|   stop_game();
 | |
|   tour::slide_backup(never_invert, true);
 | |
|   tour::slide_backup(vid.wallmode, 3);
 | |
|   tour::slide_backup(vid.monmode, 2);
 | |
| 
 | |
|   geometry = gArchimedean;
 | |
|   variation = eVariation::pure;
 | |
|   arcm::current.parse("4^5");
 | |
|   start_game();
 | |
|   resetview();
 | |
|   View = spin(45._deg);
 | |
|   if(1) {
 | |
|     dynamicval<int> 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<cell*> 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<c) {
 | |
|     auto h = unshift(gmatrix[c]*C0);
 | |
|     auto h1 = unshift(gmatrix[c1]*C0);
 | |
|     int qty = split_qty;
 | |
|     vector<hyperpoint> hs(qty+1);
 | |
|     hs[0] = h; hs[qty] = h1;
 | |
|     for(int a=qty/2; a; a/=2) for(int i=0; i<qty; i+=a*2) hs[i+a] = mid(hs[i], hs[i+2*a]);
 | |
|     for(int i=0; i<=qty; i++) hs[i] = f(hs[i]);
 | |
|     for(int i=0; i<qty; i++) map54_edges.emplace_back(hs[i], hs[i+1]);
 | |
|     }
 | |
|   println(hlog, "map54: nodes = ", isize(map54_nodes), " edges = ", isize(map54_edges));
 | |
|   stop_game();
 | |
| 
 | |
|   geometry = gSpace435;
 | |
|   start_game();
 | |
|   resetview();
 | |
|   if(1) {
 | |
|     dynamicval<int> d(min_cells_drawn, 500);
 | |
|     drawthemap();
 | |
|     bfs();
 | |
|     println(hlog, "dcal size = ", isize(dcal), " size map = ", isize(gmatrix));
 | |
|     }
 | |
|   seen.clear();
 | |
|   for(auto c: dcal) if(gmatrix.count(c)) {
 | |
|     map534_nodes.push_back(unshift(gmatrix[c]*C0));
 | |
|     seen.insert(c);
 | |
|     }
 | |
|   for(auto c: dcal) if(seen.count(c)) forCellEx(c1, c) if(seen.count(c1)) if(c1<c) {
 | |
|     map534_edges.emplace_back(unshift(gmatrix[c])*C0, unshift(gmatrix[c1])*C0);
 | |
|     }
 | |
|   stop_game();
 | |
|   // vid.cells_drawn_limit = 400;
 | |
|   build();
 | |
| 
 | |
|   if(!floor_textures) make_floor_textures();
 | |
| 
 | |
|   rogueviz::rv_hook(hooks_drawcell, 100, draw_chess_at);
 | |
|   // rogueviz::rv_hook(hooks_frame, 100, [] { restart = true; });
 | |
|   rogueviz::rv_hook(hooks_ceiling, 100, chess_ceiling);
 | |
|   rogueviz::rv_hook(hooks_o_key, 80, o_key);
 | |
|   rogueviz::rv_hook(hooks_handleKey, 101, [] (int sym, int uni) {
 | |
|     if((cmode & sm::NORMAL) && uni == 't') {
 | |
|       vid.sspeed = 0;
 | |
|       playermoved = true;
 | |
|       fix_whichcopy(cwt.at);
 | |
|       // game_keys_scroll = true;
 | |
|       return true;
 | |
|       }
 | |
|     return false;
 | |
|     });
 | |
| 
 | |
|   tour::slide_backup(frustum_culling, false);
 | |
|   tour::slide_backup(game_keys_scroll, true);
 | |
|   tour::slide_backup(bright, true);
 | |
|   tour::slide_backup(draw_sky, skyAlways);
 | |
|   tour::slide_backup(vid.cells_generated_limit, 999999);
 | |
|   tour::slide_backup(noshadow, true);
 | |
|   tour::slide_backup(auto_remove_roofs, false);
 | |
|   tour::slide_backup(vid.lake_top, 0.2);
 | |
|   tour::slide_backup(simple_sky, true);
 | |
|   tour::slide_backup(sightranges[geometry], 50);
 | |
|   tour::slide_backup(backcolor, 0xA0C0FF);
 | |
|   tour::slide_backup(vid.cs, vid.cs);
 | |
| 
 | |
|   tour::slide_backup(vid.use_smart_range, 2);
 | |
| 
 | |
|   // vid.cells_generated_limit = 9999;
 | |
|   // vid.cells_drawn_limit = 9999;
 | |
|   // vid.use_smart_range = 2;
 | |
| 
 | |
|   set_char_by_name(vid.cs, "dodek");
 | |
|   }
 | |
| 
 | |
| void show_smoothcam() {
 | |
|   cmode = sm::SIDE | sm::MAYDARK;
 | |
|   gamescreen();
 | |
|   dialog::init(XLAT("smoothcam options"), 0xFFFFFFFF, 150, 0);
 | |
| 
 | |
|   dialog::addItem("create/edit", 'c');
 | |
|   dialog::add_action([] { smoothcam::enable_and_show(); });
 | |
|   dialog::addBoolItem("run", smoothcam::animate_on, 'r');
 | |
|   dialog::add_action([] {
 | |
|     smoothcam::animate_on = !smoothcam::animate_on;
 | |
|     smoothcam::last_time = HUGE_VAL;
 | |
|     });
 | |
|   dialog::addItem("move to the start", 'a');
 | |
|   dialog::add_action([] { smoothcam::animate_on = true; smoothcam::handle_animation(0); smoothcam::animate_on = false; });
 | |
|   dialog::addItem("move to the end", 'b');
 | |
|   dialog::add_action([] { smoothcam::animate_on = true; smoothcam::handle_animation(1-1e-7); smoothcam::animate_on = false; });
 | |
|   dialog::addItem("save", 's');
 | |
|   dialog::add_action([] { save_anim("emb/animation.sav"); });
 | |
|   dialog::addItem("load", 'l');
 | |
|   dialog::add_action([] { load_anim("emb/animation.sav"); });
 | |
|   dialog::addInfo("warning: saved animations need to be loaded in the same embedding");
 | |
|   dialog::addBack();
 | |
|   dialog::display();
 | |
|   }
 | |
| 
 | |
| void show_embeddings() {
 | |
|   cmode = sm::SIDE | sm::MAYDARK;
 | |
|   gamescreen();
 | |
|   dialog::init(XLAT("embeddings"), 0xFFFFFFFF, 150, 0);
 | |
| 
 | |
|   dialog::addItem("2D to 3D", 'a');
 | |
|   dialog::add_action(switch_fpp_fixed);
 | |
| 
 | |
|   dialog::addItem("choose form the list", 'e');
 | |
|   dialog::add_action_push(embset_list);
 | |
| 
 | |
|   dialog::addSelItem("invert walls", fts(vid.wall_height), 'i');
 | |
|   dialog::add_action([] { 
 | |
|     auto cur = current();
 | |
|     cur.walls = -cur.walls;
 | |
|     activate(cur);
 | |
|     });
 | |
| 
 | |
|   dialog::addSelItem("closer to default", fts(geom3::euclid_embed_scale), '[');
 | |
|   dialog::add_action([] { 
 | |
|     activate(emb_lerp(edok(), current(), .9));
 | |
|     });
 | |
|   dialog::addSelItem("further from default", fts(geom3::euclid_embed_scale), ']');
 | |
|   dialog::add_action([] { 
 | |
|     activate(emb_lerp(edok(), current(), 10/9.));
 | |
|     });
 | |
| 
 | |
|   dialog::addBack();
 | |
|   dialog::display();
 | |
|   }
 | |
| 
 | |
| void show_quality() {
 | |
|   cmode = sm::SIDE | sm::MAYDARK;
 | |
|   gamescreen();
 | |
|   dialog::init(XLAT("quality / elements"), 0xFFFFFFFF, 150, 0);
 | |
|   dialog::addInfo("hint: reduce range to improve performance");
 | |
| 
 | |
|   dialog::addBoolItem_action("with models", with_models, 'm');
 | |
|   dialog::addBoolItem_action("with chess", with_chess, 'h');
 | |
|   dialog::addSelItem("draw the hole", its(draw_digger), 'g');
 | |
|   dialog::add_action([] { draw_digger = (1 + draw_digger) % 3; });
 | |
|   dialog::addBreak(100);
 | |
| 
 | |
|   dialog::addItem("low range", '1');
 | |
|   dialog::add_action([] { vid.cells_drawn_limit = 400; delete_sky(); });
 | |
|   dialog::addItem("mid range", '2');
 | |
|   dialog::add_action([] { vid.cells_drawn_limit = 2000; delete_sky(); });
 | |
|   dialog::addItem("high range", '3');
 | |
|   dialog::add_action([] { vid.cells_drawn_limit = 20000; delete_sky(); });
 | |
|   dialog::addItem("extreme range", '4');
 | |
|   dialog::add_action([] { vid.cells_drawn_limit = 200000; delete_sky(); });
 | |
| 
 | |
|   dialog::addSelItem("scaffolding X", its(scaffoldx), 'X');
 | |
|   dialog::add_action([] { scaffoldx = (1 + scaffoldx) % 3; });
 | |
|   dialog::addSelItem("scaffolding Y", its(scaffoldy), 'Y');
 | |
|   dialog::add_action([] { scaffoldy = (1 + scaffoldy) % 3; });
 | |
|   dialog::addSelItem("scaffolding B", its(scaffoldb), 'B');
 | |
|   dialog::add_action([] { scaffoldb = (1 + scaffoldb) % 3; });
 | |
|   dialog::addSelItem("no floor", ONOFF(no_floor), '<');
 | |
|   dialog::add_action([] { no_floor = !no_floor; mapeditor::drawplayer = false; build_map(); });
 | |
| 
 | |
|   dialog::addSelItem("periods", its(periods), 'p');
 | |
|   dialog::add_action([] { periods++; stop_game(); build(); 
 | |
|     if(adjust_to_period) activate(rescaled(current(), periods / (periods-1.)));
 | |
|     });
 | |
|   dialog::addBoolItem_action("rescale by period", adjust_to_period, 'r');
 | |
| 
 | |
|   dialog::addInfo("hint: scaffolding needs periods to work");
 | |
| 
 | |
|   dialog::addBack();
 | |
|   dialog::display();
 | |
|   }
 | |
| 
 | |
| void show_technical() {
 | |
|   cmode = sm::SIDE | sm::MAYDARK;
 | |
|   gamescreen();
 | |
|   dialog::init(XLAT("technical"), 0xFFFFFFFF, 150, 0);
 | |
| 
 | |
|   dialog::addItem("look downwards", 'l');
 | |
|   dialog::add_action(look_downwards);
 | |
| 
 | |
|   dialog::addItem("print embedding", 'p');
 | |
|   dialog::add_action([] { 
 | |
|     embset e = current();
 | |
|     println(hlog, e);
 | |
|     });
 | |
| 
 | |
|   if(true) {
 | |
|     static ld dist = 0;
 | |
|     dialog::addSelItem("measure forward distance", fts(dist), 'f');
 | |
|     dialog::add_action([] { 
 | |
|       shift_view(ztangent(-0.2));
 | |
|       spinEdge(100);
 | |
|       dist += 0.2;
 | |
|       });
 | |
|     dialog::addSelItem("go backward", fts(dist), 'b');
 | |
|     dialog::add_action([] { 
 | |
|       shift_view(ztangent(+0.05));
 | |
|       spinEdge(100);
 | |
|       dist += -0.05;
 | |
|       });
 | |
|     }
 | |
| 
 | |
|   #if CAP_VIDEO
 | |
|   if(false) {
 | |
|     dialog::addItem("transition to", 'u');
 | |
|     dialog::add_action([] { anims::videofile = "transition_to.mp4"; transition(0.01, 1, 60); });
 | |
|     }
 | |
|   if(false) {
 | |
|     dialog::addItem("transition from", 'i');
 | |
|     dialog::add_action([] { anims::videofile = "transition_from.mp4"; transition(1, 0.01, 60); });
 | |
|     }
 | |
|   #endif
 | |
| 
 | |
|   dialog::addBack();
 | |
|   dialog::display();
 | |
|   }
 | |
| 
 | |
| void show() {
 | |
|   cmode = sm::SIDE | sm::MAYDARK;
 | |
|   gamescreen();
 | |
|   dialog::init(XLAT("Non-Euclidean 3D"), 0xFFFFFFFF, 150, 0);
 | |
| 
 | |
|   dialog::addItem("embedding options", 'e');
 | |
|   dialog::add_action_push(show_embeddings);
 | |
| 
 | |
|   dialog::addItem("quality and elements", 'q');
 | |
|   dialog::add_action_push(show_quality);
 | |
| 
 | |
|   dialog::addItem("smoothcam animation", 'a');
 | |
|   dialog::add_action_push(show_smoothcam);
 | |
|   
 | |
|   dialog::addItem("technical stuff", 't');
 | |
|   dialog::add_action_push(show_technical);
 | |
|   
 | |
|   dialog::addBoolItem("move the cat", mapeditor::drawplayer, 'd');
 | |
|   dialog::add_action([] {
 | |
|     move_cat = true;
 | |
|     game_keys_scroll = false;
 | |
|     });
 | |
| 
 | |
|   dialog::addBack();
 | |
|   dialog::display();    
 | |
|   }
 | |
| 
 | |
| void o_key(o_funcs& v) {
 | |
|   v.push_back(named_dialog("embedded-chess options", show));
 | |
|   }
 | |
| 
 | |
| struct solv_grapher : rogueviz::pres::grapher {
 | |
| 
 | |
|   solv_grapher(transmatrix U) : grapher(-2, -2, 12, 12) {
 | |
|     T = T * U;
 | |
|     using rogueviz::pres::p2;
 | |
|     
 | |
|     for(int x=-1; x<=11; x++) if(x) {
 | |
|       line(p2(x,-2), p2(x,12), 0x8080FFFF);
 | |
|       line(p2(-2,x), p2(12,x), 0x8080FFFF);
 | |
|       }
 | |
|     
 | |
|     vid.linewidth *= 2;
 | |
|     arrow(p2(0,-2), p2(0,12), .5);
 | |
|     arrow(p2(-2,0), p2(12,0), .5);
 | |
|     vid.linewidth /= 2;
 | |
|     }
 | |
|   };
 | |
| 
 | |
| ld geo_zero;
 | |
| 
 | |
| transmatrix xyzscale(ld x) {
 | |
|   transmatrix T = Id;
 | |
|   T[0][0] = T[1][1] = T[2][2] = x;
 | |
|   return T;
 | |
|   }
 | |
| 
 | |
| transmatrix solvscale(ld x) {
 | |
|   transmatrix T = Id;
 | |
|   T[0][0] *= exp(-x);
 | |
|   T[1][1] *= exp(x);
 | |
|   return T;
 | |
|   }
 | |
| 
 | |
| ld geodesic_t = 0;
 | |
| 
 | |
| void geodesic_screen(tour::presmode mode, int id) {
 | |
|   if(!params.count("geodesic_t")) param_f(geodesic_t, "geodesic_t");
 | |
|   using namespace rogueviz::pres;
 | |
|   if(mode == pmStart) geo_zero = ticks;
 | |
| 
 | |
|   use_angledir(mode, id == 0);
 | |
| 
 | |
|   static hyperpoint start, middle, target, nlh, nlh1, nlh2;
 | |
|   const ld coord = 10;
 | |
|   
 | |
|   setWhiteCanvas(mode);
 | |
|   if(mode == pmStart) {
 | |
|     slide_backup(pmodel);
 | |
|     slide_backup(pconf.clip_min);
 | |
|     slide_backup(pconf.clip_max);
 | |
|     slide_backup(vid.cells_drawn_limit);
 | |
|     stop_game(), pmodel = mdHorocyclic, geometry = gCubeTiling, variation = eVariation::pure, pconf.clip_min = -10000, pconf.clip_max = +100, start_game();
 | |
| 
 | |
|     dynamicval<eGeometry> dg(geometry, gSol);
 | |
|     dynamicval<int> 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<eGeometry> 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<eGeometry> 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; i<isize(ptds);)
 | |
|       if(i && cat(ptds[i]->prio) < 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;
 | |
|     });
 | |
|   }
 | |
| 
 | |
| 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"
 | |
|   ;
 | |
| 
 | |
| void act_or_config() {
 | |
|   if(activated) pushScreen(show);
 | |
|   else { enable(); popScreenAll(); mapeditor::drawplayer = false; }
 | |
|   }
 | |
| 
 | |
| slide embchess_slides[] = {
 | |
|   {"3D world", 999, LEGAL::NONE | QUICKGEO | QUICKSKIP | USE_SLIDE_NAME,
 | |
|    "This is the world from our YouTube video 'Non-Euclidean Third Dimension'. "
 | |
|    "You can activate it by pressing '5', and then press '5' again "
 | |
|    "to access various options. The next slides are slides from that video.\n\n",
 | |
| 
 | |
|   [] (presmode mode) {
 | |
|     setWhiteCanvas(mode);
 | |
|     slide_url(mode, 'y', "YouTube link", "https://youtu.be/Rhjv_PazzZE");
 | |
|     slide_action(mode, 'a', "activate / configure", act_or_config);
 | |
|     if(mode == pmKey) act_or_config();
 | |
|     }},
 | |
| 
 | |
|   {"Euler's polyhedron formula", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE, 
 | |
|     "This is a proof that a sphere cannot be tiled with squares.",
 | |
|     [] (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);
 | |
|       }},
 | |
| 
 | |
| 
 | |
|   {"from A to B in Solv 1", 999, LEGAL::NONE | QUICKGEO | NOTITLE, 
 | |
|     "How to get from A to B in Solv as quickly as possible? The first attempt is to do so without leaving the plane. Since the XY plane in Solv has Euclidean geometry, we can compute the length of such a path using the Pythagoras theorem."
 | |
|     "Press '5' to switch to the 3D view."
 | |
|     ,
 | |
|     [] (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, 
 | |
|     "But we can do it faster like this, using two hyperbolic geodesics. "
 | |
|     ,
 | |
|     [] (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, 
 | |
|     "And even faster, do it like this, avoiding sharp bends."
 | |
|     ,
 | |
|     [] (presmode mode) {
 | |
|       println(hlog, "C mode ", int(mode));
 | |
|       empty_screen(mode);
 | |
|       geodesic_screen(mode, 2);
 | |
|       no_other_hud(mode);
 | |
|       }
 | |
|     },
 | |
| 
 | |
|   {"final slide", 123, LEGAL::ANY | NOTITLE | QUICKSKIP | FINALSLIDE, 
 | |
|     "End of the presentation.",
 | |
|   
 | |
|     [] (presmode mode) { }
 | |
|     },
 | |
|   };
 | |
| 
 | |
| auto embchess_ah = 
 | |
|   /* enable this unit */
 | |
|   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)
 | |
| #if CAP_VIDEO
 | |
| + arg::add3("-embtrans-test", [] { arg::shift(); transition_test(arg::argf()); })
 | |
| #endif
 | |
| + arg::add3("-emb-no-floor", [] { no_floor = true; })
 | |
| #if CAP_VIDEO
 | |
| + 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);
 | |
|     })
 | |
| #endif
 | |
| + arg::add3("-avp", [] { semidirect_rendering = true; vid.consider_shader_projection = false; })
 | |
| #if CAP_VIDEO
 | |
| + 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);
 | |
|     })
 | |
| #endif
 | |
| + 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("non-Euclidean third dimension"), &embchess_slides[0], '3');
 | |
|     });
 | |
| 
 | |
| }
 | |
| }
 | 
