hyperrogue/rogueviz/ascending-descending.cpp

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
}