mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-16 02:04:48 +00:00
302 lines
7.2 KiB
C++
302 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", "");
|
|
dialog::reaction = make_routes;
|
|
});
|
|
|
|
dialog::addSelItem("over", fts(over), 'o');
|
|
dialog::add_action([]() {
|
|
dialog::editNumber(over, 0, 100, 1, 1, "over", "");
|
|
dialog::reaction = make_routes;
|
|
});
|
|
|
|
dialog::addSelItem("over2", fts(over2), 'p');
|
|
dialog::add_action([]() {
|
|
dialog::editNumber(over2, 0, 100, 1, 1, "over2", "");
|
|
dialog::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
|
|
}
|