mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-11-04 07:43:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			299 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "rogueviz.h"
 | 
						|
 | 
						|
namespace hr {
 | 
						|
 | 
						|
#if CAP_MODELS
 | 
						|
namespace ply {
 | 
						|
 | 
						|
using namespace rogueviz::objmodels;
 | 
						|
 | 
						|
bool animated;
 | 
						|
 | 
						|
hyperpoint A = point31(9.7, -38.1, 10.116);
 | 
						|
hyperpoint B = point31(17.3, -38.1, 10.95);
 | 
						|
hyperpoint C = point31(17.3, -46.1, 11.75);
 | 
						|
hyperpoint D = point31(12.95, -46.08, 12.28);
 | 
						|
hyperpoint E = point31(12.86, -44.53, 12.4);
 | 
						|
 | 
						|
ld radius = (12.86 - 11.11) / 2;
 | 
						|
 | 
						|
transmatrix nilform;
 | 
						|
 | 
						|
map<hyperpoint, pair<int, hyperpoint> > cache;
 | 
						|
 | 
						|
bool debugnil = false;
 | 
						|
bool usecache = true;
 | 
						|
 | 
						|
pair<int, hyperpoint> nilize(hyperpoint h) {
 | 
						|
  
 | 
						|
  if(euclid) return {0, h - A + C0};
 | 
						|
 | 
						|
  hyperpoint hc = h;
 | 
						|
  for(int i=0; i<4; i++) hc[i] = floor(h[i] * 1000 + .5);
 | 
						|
  if(usecache && cache.count(hc)) return cache[hc];
 | 
						|
  
 | 
						|
  hyperpoint at = A;
 | 
						|
  
 | 
						|
  hyperpoint result = C0;
 | 
						|
  
 | 
						|
  auto move_coord_full = [&] (hyperpoint tgt) {
 | 
						|
    for(int i=0; i<100; i++) {
 | 
						|
      result = nisot::translate(result) * nilform * ((tgt - at) / 100 + C0);
 | 
						|
      }
 | 
						|
    at = tgt;
 | 
						|
    };
 | 
						|
  
 | 
						|
  auto move_coord = [&] (int c, hyperpoint upto) {
 | 
						|
    ld part = (h[c] - at[c]) / (upto[c] - at[c]);
 | 
						|
    if(part > 1) part = 1;
 | 
						|
    move_coord_full(at + part * (upto-at));
 | 
						|
    };
 | 
						|
  
 | 
						|
  int cat = 0;
 | 
						|
  
 | 
						|
  if(h[1] > -39) {
 | 
						|
    move_coord(0, B);
 | 
						|
    cat = 1;
 | 
						|
    goto finish;
 | 
						|
    }
 | 
						|
  move_coord_full(B);
 | 
						|
  if(h[0] > 17.2) {
 | 
						|
    move_coord(1, C);
 | 
						|
    cat = 2;
 | 
						|
    goto finish;    
 | 
						|
    }
 | 
						|
  move_coord_full(C);
 | 
						|
  if(h[1] < -45.5) {
 | 
						|
    move_coord(0, D);
 | 
						|
    cat = 3;
 | 
						|
    goto finish;
 | 
						|
    }
 | 
						|
  cat = 4;
 | 
						|
  move_coord_full(D);
 | 
						|
  move_coord(1, E);
 | 
						|
  finish:
 | 
						|
  
 | 
						|
  move_coord_full(h);
 | 
						|
  return cache[hc] = {cat, result};
 | 
						|
  }
 | 
						|
 | 
						|
ld vperiod;
 | 
						|
 | 
						|
pair<hyperpoint, hyperpoint> trace_path(ld v) {
 | 
						|
 | 
						|
  ld vorig = v;
 | 
						|
  
 | 
						|
  hyperpoint lctr = A;
 | 
						|
  ld angle = 0;
 | 
						|
  
 | 
						|
  ld arclen = radius * 90._deg;
 | 
						|
  
 | 
						|
  auto change_angle = [&] (ld x) {
 | 
						|
    if(v == 0) return;
 | 
						|
    else if(v >= arclen) v -= arclen, angle += 1;
 | 
						|
    else angle += v / arclen, v = 0;
 | 
						|
    };
 | 
						|
 | 
						|
  auto shift_to = [&] (hyperpoint h, bool last = false) {
 | 
						|
    ld seglen = hypot_d(3, h - lctr);
 | 
						|
    if(v == 0) return;
 | 
						|
    else if(v >= seglen && !last) v -= seglen, lctr = h;
 | 
						|
    else lctr = lerp(lctr, h, v / seglen), v = 0;
 | 
						|
    };
 | 
						|
  
 | 
						|
  change_angle(1);
 | 
						|
  shift_to(B);
 | 
						|
  change_angle(2);
 | 
						|
  shift_to(C);
 | 
						|
  change_angle(3);
 | 
						|
  shift_to(D);
 | 
						|
  change_angle(4);
 | 
						|
  shift_to(E, true);
 | 
						|
  
 | 
						|
  angle *= 90._deg;
 | 
						|
  
 | 
						|
  if(v > 0) vperiod = vorig - v;
 | 
						|
  
 | 
						|
  return { lctr + point3(radius * -cos(angle), radius * sin(angle), 0), point3(-sin(angle), -cos(angle), 0) };  
 | 
						|
  }
 | 
						|
 | 
						|
transmatrix scaleby(ld x) {
 | 
						|
  transmatrix res = Id;
 | 
						|
  for(int i=0; i<LDIM; i++)
 | 
						|
    res[i][i] = x;
 | 
						|
  return res;
 | 
						|
  }
 | 
						|
 | 
						|
vector<hyperpoint> route(1000), forwards(1000), overroute(1000);
 | 
						|
 | 
						|
hyperpoint interpolate_at(vector<hyperpoint>& v, ld x) {
 | 
						|
  while(x > 1000) x -= 1000;
 | 
						|
  return lerp(v[x], v[(int(x)+1) % 1000], frac(x));
 | 
						|
  }
 | 
						|
 | 
						|
ld advance = 2;
 | 
						|
ld over = 1.5;
 | 
						|
ld over2 = 1;
 | 
						|
 | 
						|
void make_routes() {
 | 
						|
  for(int i=0; i<1000; i++) {
 | 
						|
    ld v = vperiod * i / 1000;
 | 
						|
    route[i] = nilize(trace_path(v).first + point3(0,0,over)).second;
 | 
						|
    ld vb = v + advance;
 | 
						|
    if(vb > vperiod) vb -= vperiod;
 | 
						|
    forwards[i] = nilize(trace_path(vb).first).second;
 | 
						|
    overroute[i] = nilize(trace_path(v).first + point3(0,0,over+over2)).second;
 | 
						|
    }
 | 
						|
  
 | 
						|
  auto smoothen = [&] (vector<hyperpoint>& v) {
 | 
						|
    for(int it=0; it<100; it++) {
 | 
						|
      vector<hyperpoint> smoother;
 | 
						|
      for(int i=0; i<1000; i++) {
 | 
						|
        hyperpoint& a = v[i];
 | 
						|
        hyperpoint& b = v[(i+1) % 1000];
 | 
						|
        hyperpoint& c = v[(i+2) % 1000];
 | 
						|
        smoother.push_back((a + b + c) / 3);
 | 
						|
        }
 | 
						|
      v = smoother;
 | 
						|
      }
 | 
						|
    };
 | 
						|
  
 | 
						|
  smoothen(route);
 | 
						|
  smoothen(forwards);
 | 
						|
  smoothen(overroute);
 | 
						|
  }
 | 
						|
 | 
						|
bool prepared;
 | 
						|
 | 
						|
void prepare_nilform() {
 | 
						|
  if(prepared) return;
 | 
						|
  prepared = true;
 | 
						|
  hyperpoint axis = (E - A);
 | 
						|
  transmatrix rotator = Id;
 | 
						|
  rotator[2] = axis;
 | 
						|
  println(hlog, " = ", (rotator[2] | rotator[2]));
 | 
						|
  rotator[2] /= sqrt(rotator[2] | rotator[2]);
 | 
						|
  rotator[1] -= (rotator[1] | rotator[2]) * rotator[2];
 | 
						|
  rotator[1] /= sqrt(rotator[1] | rotator[1]);
 | 
						|
  rotator[0] -= (rotator[0] | rotator[2]) * rotator[2];
 | 
						|
  rotator[0] -= (rotator[0] | rotator[1]) * rotator[1];
 | 
						|
  rotator[0] /= sqrt(rotator[0] | rotator[0]);
 | 
						|
  println(hlog, "rotator = ", kz(rotator));
 | 
						|
  rotator = inverse(transpose(rotator));
 | 
						|
  println(hlog, "rotator = ", kz(rotator));    
 | 
						|
  
 | 
						|
  ld minscale = 0.5; // positive
 | 
						|
  ld maxscale = 1.5; // negative
 | 
						|
  ld scale;
 | 
						|
  
 | 
						|
  for(int it=0; it<100; it++) {  
 | 
						|
    scale = (minscale + maxscale) / 2;
 | 
						|
    nilform = rotator * scaleby(scale);
 | 
						|
    cache.clear();
 | 
						|
    hyperpoint nE = nilize(E).second;
 | 
						|
    if(nE[2] < 0) maxscale = scale;
 | 
						|
    else minscale = scale;
 | 
						|
    }
 | 
						|
  
 | 
						|
  println(hlog, "scale = ", scale);
 | 
						|
  println(hlog, nilize(E).second);  
 | 
						|
  
 | 
						|
  vperiod = radius * TAU + hypot_d(3, B-A) + hypot_d(3, C-B) + hypot_d(3, D-C) + hypot_d(3, E-D);
 | 
						|
  println(hlog, "vperiod = ", vperiod);
 | 
						|
  
 | 
						|
  make_routes();
 | 
						|
  }
 | 
						|
 | 
						|
struct nilmodel : model {
 | 
						|
  hyperpoint transform(hyperpoint h) override { return nilize(h).second; }
 | 
						|
  void process_triangle(vector<hyperpoint>& hys, vector<hyperpoint>& tot, bool textured, object *co) override {
 | 
						|
    auto n0 = nilize(hys[0]).first;
 | 
						|
    auto n1 = nilize(hys[1]).first;
 | 
						|
    auto n2 = nilize(hys[2]).first;
 | 
						|
    auto mi = min(n0, min(n1, n2));
 | 
						|
    auto ma = max(n0, max(n1, n2));
 | 
						|
    if(ma - mi > 1) return;
 | 
						|
    model::process_triangle(hys, tot, textured, co);
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
nilmodel staircase;
 | 
						|
 | 
						|
bool draw_ply() {
 | 
						|
 | 
						|
  if(nil) prepare_nilform();
 | 
						|
 | 
						|
  staircase.render(ggmatrix(currentmap->gamestart()));
 | 
						|
  
 | 
						|
  return false;
 | 
						|
  }
 | 
						|
 | 
						|
void show() {
 | 
						|
  cmode = sm::SIDE | sm::MAYDARK;
 | 
						|
  gamescreen();
 | 
						|
  dialog::init(XLAT("Ascending & Descending"), 0xFFFFFFFF, 150, 0);
 | 
						|
 | 
						|
  dialog::addSelItem("advance", fts(advance), 'a');
 | 
						|
  dialog::add_action([]() {
 | 
						|
    dialog::editNumber(advance, 0, 100, 1, 1, "advance", "").reaction = make_routes;
 | 
						|
    });
 | 
						|
 | 
						|
  dialog::addSelItem("over", fts(over), 'o');
 | 
						|
  dialog::add_action([]() {
 | 
						|
    dialog::editNumber(over, 0, 100, 1, 1, "over", "").reaction = make_routes;
 | 
						|
    });
 | 
						|
 | 
						|
  dialog::addSelItem("over2", fts(over2), 'p');
 | 
						|
  dialog::add_action([]() {
 | 
						|
    dialog::editNumber(over2, 0, 100, 1, 1, "over2", "").reaction = make_routes;
 | 
						|
    });
 | 
						|
 | 
						|
  dialog::addBoolItem_action("animated", animated, 'a');
 | 
						|
 | 
						|
  add_edit(prec);
 | 
						|
 | 
						|
  dialog::addBack();
 | 
						|
  dialog::display();    
 | 
						|
  }
 | 
						|
 | 
						|
void o_key(o_funcs& v) {
 | 
						|
  v.push_back(named_dialog("Ascending & Descending", show));
 | 
						|
  }
 | 
						|
 | 
						|
void enable() {
 | 
						|
  rogueviz::rv_hook(hooks_frame, 100, draw_ply);
 | 
						|
  rogueviz::rv_hook(hooks_o_key, 80, o_key);
 | 
						|
  rogueviz::rv_hook(anims::hooks_anim, 100, [] { 
 | 
						|
    if(!animated) return;
 | 
						|
    usecache = false;
 | 
						|
    ld t = ticks * 1. / anims::period;
 | 
						|
    t = t - floor(t);
 | 
						|
    t *= 1000;
 | 
						|
    
 | 
						|
    centerover = currentmap->gamestart();
 | 
						|
 | 
						|
    #if CAP_VR
 | 
						|
    if(vrhr::active())
 | 
						|
      View = gpushxto0(interpolate_at(route, t));
 | 
						|
    else
 | 
						|
    #endif
 | 
						|
    set_view(
 | 
						|
      interpolate_at(route, t),
 | 
						|
      interpolate_at(forwards, t),
 | 
						|
      interpolate_at(overroute, t)
 | 
						|
      );
 | 
						|
    
 | 
						|
    anims::moved();
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
auto plyhook = 
 | 
						|
  arg::add3("-asd", enable) + 
 | 
						|
  addHook(hooks_configfile, 100, [] {
 | 
						|
    param_b(animated, "ad_animated");
 | 
						|
    });
 | 
						|
 | 
						|
}
 | 
						|
#endif
 | 
						|
}
 |