2018-05-18 15:34:12 +00:00
|
|
|
// Hyperbolic Rogue: staircase simulation in RogueViz
|
|
|
|
// Copyright (C) 2011-2018 Zeno and Tehora Rogue, see 'hyper.cpp' for details
|
2021-04-02 12:37:55 +00:00
|
|
|
// see: https://www.youtube.com/watch?v=HZNRo6mr5pk
|
2018-05-18 15:34:12 +00:00
|
|
|
|
2020-03-29 14:03:31 +00:00
|
|
|
#include "rogueviz.h"
|
|
|
|
|
2018-06-11 16:00:40 +00:00
|
|
|
namespace rogueviz { namespace staircase {
|
2018-05-18 15:34:12 +00:00
|
|
|
|
|
|
|
ld scurvature = 0;
|
|
|
|
ld acurvature = 0;
|
|
|
|
|
|
|
|
ld global_r;
|
|
|
|
|
|
|
|
ld szoom = 5;
|
|
|
|
|
|
|
|
ld progress = 0;
|
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
basic_textureinfo tinf;
|
2018-05-18 15:34:12 +00:00
|
|
|
|
|
|
|
hyperpoint spcoord(hyperpoint h) {
|
|
|
|
ld phi = h[0], y = h[1], z = h[2], r = global_r;
|
|
|
|
ld aphi = (r+phi + floor(progress))*M_PI/6;
|
2021-04-02 12:37:55 +00:00
|
|
|
return zpush(acurvature*(y + r - frac(progress))/szoom) * xspinpush0(aphi, acurvature * z);
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
using tv = glhr::textured_vertex;
|
|
|
|
|
|
|
|
tv pt(hyperpoint h, hyperpoint c) {
|
|
|
|
tv result;
|
|
|
|
h = spcoord(h);
|
|
|
|
result.coords[0] = h[0];
|
|
|
|
result.coords[1] = h[1];
|
|
|
|
result.coords[2] = h[2];
|
|
|
|
result.coords[3] = h[3];
|
|
|
|
result.texture[0] = c[0];
|
|
|
|
result.texture[1] = c[1];
|
|
|
|
result.texture[2] = c[2];
|
|
|
|
return result;
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
vector<glvertex> vertices;
|
|
|
|
|
|
|
|
void add_pt(tv tv) {
|
|
|
|
vertices.push_back(tv.coords);
|
|
|
|
glvertex t;
|
|
|
|
for(int i=0; i<3; i++) t[i] = tv.texture[i];
|
|
|
|
tinf.tvertices.push_back(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tri(tv a, tv b, tv c) { add_pt(a); add_pt(b); add_pt(c); }
|
|
|
|
|
2018-05-18 15:34:12 +00:00
|
|
|
void addRect(hyperpoint h, hyperpoint hx, hyperpoint hy, hyperpoint v, hyperpoint vx, hyperpoint vy, int ix, int iy) {
|
2021-04-02 12:37:55 +00:00
|
|
|
vector<vector<tv> > rps(iy+1, vector<tv> (ix+1));
|
2018-05-18 15:34:12 +00:00
|
|
|
for(int y=0; y<=iy; y++)
|
|
|
|
for(int x=0; x<=ix; x++) {
|
|
|
|
rps[y][x] = pt(h+hx*x/ix+hy*y/iy, v+vx*x/ix+vy*y/iy);
|
|
|
|
}
|
|
|
|
for(int y=0; y<iy; y++)
|
2021-04-02 12:37:55 +00:00
|
|
|
for(int x=0; x<ix; x++) {
|
|
|
|
tri(rps[y][x], rps[y+1][x], rps[y][x+1]),
|
|
|
|
tri(rps[y+1][x+1], rps[y][x+1], rps[y+1][x]);
|
|
|
|
}
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void addTri(hyperpoint h, hyperpoint hx, hyperpoint hy, hyperpoint v, hyperpoint vx, hyperpoint vy, int i) {
|
2021-04-02 12:37:55 +00:00
|
|
|
vector<vector<tv> > rps(i+1, vector<tv> (i+1));
|
2018-05-18 15:34:12 +00:00
|
|
|
for(int y=0; y<=i; y++)
|
|
|
|
for(int x=0; x<=i; x++) {
|
|
|
|
if(x+y <= i)
|
|
|
|
rps[y][x] = pt(h+hx*x/i+hy*y/i, v+vx*x/i+vy*y/i);
|
|
|
|
}
|
|
|
|
for(int y=0; y<i; y++)
|
|
|
|
for(int x=0; x<i; x++) {
|
|
|
|
if(x+y < i)
|
2021-04-02 12:37:55 +00:00
|
|
|
tri(rps[y][x], rps[y+1][x], rps[y][x+1]);
|
2018-05-18 15:34:12 +00:00
|
|
|
if(x+y+2 <= i)
|
2021-04-02 12:37:55 +00:00
|
|
|
tri(rps[y+1][x+1], rps[y][x+1], rps[y+1][x]);
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool need_texture = true;
|
|
|
|
|
2018-05-22 20:08:24 +00:00
|
|
|
#if CAP_TEXTURE
|
2018-05-18 15:34:12 +00:00
|
|
|
texture::texture_data tdata; // = texture::config.data;
|
2018-05-22 20:08:24 +00:00
|
|
|
#endif
|
2018-05-18 15:34:12 +00:00
|
|
|
|
|
|
|
void make_texture() {
|
2018-05-22 20:08:24 +00:00
|
|
|
#if CAP_TEXTURE
|
2021-04-02 12:37:55 +00:00
|
|
|
if(!need_texture) return;
|
2018-05-18 15:34:12 +00:00
|
|
|
printf("make texture\n");
|
|
|
|
need_texture = false;
|
|
|
|
tdata.whitetexture();
|
|
|
|
int tw = tdata.twidth;
|
|
|
|
printf("tw = %d\n", tw);
|
|
|
|
int fw = tw / 4;
|
|
|
|
auto pix = [&] (int k, int x, int y) -> unsigned& {
|
|
|
|
return tdata.texture_pixels[y * tw + x + (k&3) * fw + (k>>2) * fw * tw];
|
|
|
|
};
|
|
|
|
for(int y=0; y<tw; y++)
|
|
|
|
for(int x=0; x<tw; x++)
|
|
|
|
pix(0,x,y) = rand();
|
|
|
|
for(int y=0; y<=fw; y++)
|
|
|
|
for(int x=0; x<=fw; x++) {
|
|
|
|
typedef long long ll;
|
|
|
|
pix(0,x,y) = 0xFF000000 + 0x10101 * ((x*ll(fw-x)*y*(fw-y)*255)/ll(fw/2)/(fw/2)/(fw-fw/2)/(fw-fw/2));
|
|
|
|
pix(2,x,y) = 0xFF400000 + 0x10000 * (y * 63 / fw);
|
|
|
|
pix(8,x,y) = 0xFF101010;
|
|
|
|
pix(10,x,y) = 0xFF000000 + gradient(0, 0xFFD500, 0, x*(fw-x), fw*fw/4);
|
|
|
|
pix(5,x,y) = 0xFF000000 + gradient(0, 0x804000, -1, sin(2*M_PI*8*y/fw), 1);
|
|
|
|
pix(7,x,y) = 0xFF000000 + gradient(0, 0x808080, 0, x*ll(fw-x)*y*(fw-y), ll(fw/2)*(fw/2)*(fw-fw/2)*(fw-fw/2));
|
|
|
|
}
|
|
|
|
|
|
|
|
tdata.loadTextureGL();
|
2018-05-22 20:08:24 +00:00
|
|
|
#endif
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int savetex;
|
|
|
|
|
2018-09-05 22:48:33 +00:00
|
|
|
#if ISWEB
|
|
|
|
int prec = 1;
|
|
|
|
int maxr = 100;
|
|
|
|
#else
|
2018-05-18 15:34:12 +00:00
|
|
|
int prec = 4;
|
|
|
|
int maxr = 1000;
|
2018-09-05 22:48:33 +00:00
|
|
|
#endif
|
2018-05-18 15:34:12 +00:00
|
|
|
|
|
|
|
bool on;
|
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
void enable_hooks();
|
|
|
|
|
|
|
|
void reset_geom(eGeometry g) {
|
|
|
|
set_geometry(g);
|
|
|
|
start_game();
|
|
|
|
View = Id;
|
|
|
|
enable_hooks();
|
|
|
|
}
|
|
|
|
|
2018-05-18 15:34:12 +00:00
|
|
|
void make_staircase() {
|
|
|
|
|
2018-11-17 18:24:02 +00:00
|
|
|
// vid.stereo_mode = current_display->sODS;
|
2018-05-18 15:34:12 +00:00
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
println(hlog, "scurvature = ", scurvature, " progress = ", progress);
|
2018-05-18 15:34:12 +00:00
|
|
|
if(scurvature > -1e-6 && scurvature < 1e-6) {
|
2021-04-02 12:37:55 +00:00
|
|
|
if(WDIM == 2 || !euclid) reset_geom(gCubeTiling);
|
2018-05-18 15:34:12 +00:00
|
|
|
acurvature = 1;
|
|
|
|
}
|
|
|
|
else if(scurvature < 0) {
|
2021-04-02 12:37:55 +00:00
|
|
|
if(WDIM == 2 || !hyperbolic) reset_geom(gSpace534);
|
2018-05-18 15:34:12 +00:00
|
|
|
acurvature = -scurvature;
|
|
|
|
}
|
|
|
|
else {
|
2021-04-02 12:37:55 +00:00
|
|
|
if(WDIM == 2 || !sphere) reset_geom(gCell120);
|
2018-05-18 15:34:12 +00:00
|
|
|
acurvature = scurvature;
|
|
|
|
}
|
2021-04-02 12:37:55 +00:00
|
|
|
|
|
|
|
// rug::ruggospeed = acurvature;
|
2018-11-17 18:24:02 +00:00
|
|
|
vid.ipd = 0.15 * acurvature;
|
2021-04-02 12:37:55 +00:00
|
|
|
staircase::on = true;
|
2018-05-18 15:34:12 +00:00
|
|
|
if(need_texture) {
|
|
|
|
make_texture();
|
|
|
|
}
|
2021-04-02 12:37:55 +00:00
|
|
|
vertices.clear();
|
|
|
|
tinf.tvertices.clear();
|
2018-05-18 15:34:12 +00:00
|
|
|
printf("compute\n");
|
|
|
|
for(int r=-maxr; r<maxr; r++) {
|
|
|
|
if(scurvature < -1e-6 && abs(r * acurvature) > 7*12) continue;
|
|
|
|
if(scurvature > 1e-6 && abs(acurvature*r/szoom) > M_PI) continue;
|
|
|
|
global_r = r;
|
|
|
|
// step
|
2021-04-02 12:37:55 +00:00
|
|
|
addRect(point31(0,0,1), point30(0,0,1), point30(1,0,0), hpxy(0,0), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
// step connection
|
2021-04-02 12:37:55 +00:00
|
|
|
addRect(point31(1,0,1), point30(0,0,1), point30(0,1,0), hpxy(0.75,0.25), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
// triangle inner side
|
2021-04-02 12:37:55 +00:00
|
|
|
addTri(point31(1,0,1), point30(0,1,0), point30(-1,0,0), hpxy(.5,0), hpxy(.125,.125), hpxy(0,.125), prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
// rectangle under triangle
|
2021-04-02 12:37:55 +00:00
|
|
|
addRect(point31(0,0,1), point30(1,1,0), point30(0,1,0), hpxy(.5,.125), hpxy(.125,0), hpxy(0,.125), prec, prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
// barrier post
|
2021-04-02 12:37:55 +00:00
|
|
|
addRect(point31(.45,0,1.1), point30(.1,.1,0), point30(0,-3,0), hpxy(0,.5), hpxy(.25,0), hpxy(0,.25), 2, prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
// barrier
|
2021-04-02 12:37:55 +00:00
|
|
|
addRect(point31(.45,-3,1), point30(0,0,.2), point30(1,1,0), hpxy(.5,.5), hpxy(.25,0), hpxy(0,.25), 1, prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
// outer wall
|
2021-04-02 12:37:55 +00:00
|
|
|
addRect(point31(0,0,2), point30(1,1,0), point30(0,12,0), hpxy(.25,.25), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
// lower wall
|
2021-04-02 12:37:55 +00:00
|
|
|
addRect(point31(0,1,1), point30(1,1,0), point30(0,0,1), hpxy(.5,0), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
printf("push\n");
|
2021-04-02 12:37:55 +00:00
|
|
|
printf("done (%d points)\n", isize(tinf.tvertices));
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// -0.50 .. 0.16
|
|
|
|
|
|
|
|
void showMenu() {
|
2018-12-13 16:02:10 +00:00
|
|
|
cmode = sm::SIDE | sm::MAYDARK;
|
2018-05-18 15:34:12 +00:00
|
|
|
gamescreen(0);
|
|
|
|
dialog::init(XLAT("Spiral Staircase"), iinf[itPalace].color, 150, 0);
|
2021-04-02 12:37:55 +00:00
|
|
|
|
|
|
|
add_edit(scurvature);
|
|
|
|
add_edit(prec);
|
|
|
|
add_edit(maxr);
|
2018-05-18 15:34:12 +00:00
|
|
|
|
|
|
|
dialog::addBreak(100);
|
|
|
|
dialog::addBoolItem(XLAT("low quality"), prec == 1, '1');
|
2021-04-02 12:37:55 +00:00
|
|
|
dialog::add_action([] { prec = 1; maxr = 100; make_staircase(); });
|
2018-05-18 15:34:12 +00:00
|
|
|
dialog::addBoolItem(XLAT("medium quality"), prec == 2, '2');
|
2018-09-05 22:48:33 +00:00
|
|
|
#if !ISWEB
|
2018-05-18 15:34:12 +00:00
|
|
|
dialog::addBoolItem(XLAT("high quality"), prec == 4, '3');
|
2018-09-05 22:48:33 +00:00
|
|
|
#endif
|
2018-05-18 15:34:12 +00:00
|
|
|
dialog::addItem(XLAT("take me back"), 'q');
|
|
|
|
|
|
|
|
dialog::display();
|
|
|
|
}
|
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
void draw_staircase() {
|
|
|
|
shiftmatrix Zero = ggmatrix(cwt.at);
|
|
|
|
auto &p = queuepoly(Zero, cgi.shGem[0], 0xFFFFFFFF);
|
|
|
|
p.tab = &vertices;
|
|
|
|
p.cnt = isize(vertices);
|
|
|
|
p.flags |= POLY_TRIANGLES;
|
|
|
|
p.offset = 0;
|
|
|
|
p.offset_texture = 0;
|
|
|
|
p.tinf = &tinf;
|
|
|
|
tinf.texture_id = tdata.textureid;
|
2020-03-29 11:09:10 +00:00
|
|
|
}
|
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
void enable_hooks() {
|
|
|
|
rv_hook(hooks_o_key, 80, [] (o_funcs& v) { v.push_back(named_dialog("staircase", showMenu)); });
|
|
|
|
rv_hook(hooks_frame, 100, draw_staircase);
|
|
|
|
}
|
2020-03-29 11:09:10 +00:00
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
void enable() {
|
|
|
|
enable_hooks();
|
|
|
|
make_staircase();
|
|
|
|
make_texture();
|
2018-05-18 15:34:12 +00:00
|
|
|
}
|
|
|
|
|
2021-04-02 12:37:55 +00:00
|
|
|
int phooks = arg::add3("-stair", enable)
|
2021-06-25 11:53:23 +00:00
|
|
|
+ addHook_rvslides(141, [] (string s, vector<tour::slide>& v) {
|
2021-03-30 19:48:04 +00:00
|
|
|
if(s != "mixed") return;
|
2020-03-29 11:52:10 +00:00
|
|
|
using namespace tour;
|
|
|
|
v.push_back(
|
2021-03-30 19:48:04 +00:00
|
|
|
tour::slide{"Spiral Staircase", 62, LEGAL::NONE | QUICKGEO,
|
2021-04-02 12:37:55 +00:00
|
|
|
"Spiral Staircase Demo.\n\n"
|
|
|
|
"In Euclidean geometry, when we look at a spiral staircase from above, "
|
|
|
|
"we see a hyperbolic spiral -- not a logarithmic spiral, as some people claim. "
|
|
|
|
"However, in hyperbolic geometry, we would see a (roughly) logarithmic spiral.\n\n"
|
|
|
|
"Press '5' to change the curvature or other parameters.",
|
2020-03-29 11:52:10 +00:00
|
|
|
|
|
|
|
[] (presmode mode) {
|
2021-04-02 12:37:55 +00:00
|
|
|
setCanvas(mode, '0');
|
|
|
|
if(mode == pmStart) staircase::make_staircase();
|
2020-03-29 11:52:10 +00:00
|
|
|
slidecommand = "staircase menu";
|
2021-04-02 12:37:55 +00:00
|
|
|
if(mode == pmKey) pushScreen(staircase::showMenu);
|
2021-04-02 22:57:37 +00:00
|
|
|
slide_url(mode, 'y', "YouTube link", "https://www.youtube.com/watch?v=HZNRo6mr5pk");
|
2020-03-29 11:52:10 +00:00
|
|
|
}}
|
|
|
|
);
|
2021-04-02 12:37:55 +00:00
|
|
|
})
|
|
|
|
+ addHook(hooks_configfile, 100, [] {
|
|
|
|
param_f(scurvature, "stair_curvature")
|
|
|
|
->editable(-1, 1, .05, XLAT("curvature of the space"), "", 'c')
|
|
|
|
->set_reaction(make_staircase)
|
|
|
|
->set_extra([] {
|
|
|
|
dialog::addItem("golden spiral", 'G');
|
|
|
|
dialog::add_action([] {
|
|
|
|
scurvature = -4 * log((sqrt(5)+1)/2) / 2.4;
|
|
|
|
make_staircase();
|
|
|
|
popScreen();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
param_i(prec, "stair_precision")
|
|
|
|
->editable(1, 8, 1, XLAT("higher value = better"), "staircase precision", 'p')
|
|
|
|
->set_sets([] { dialog::bound_low(1); })
|
|
|
|
->set_reaction(make_staircase);
|
|
|
|
param_i(maxr, "stair_maxr")
|
|
|
|
->editable(1, 5000, 100, XLAT("higher value = more levels"), "staircase max", 'm')
|
|
|
|
->set_sets([] { dialog::bound_low(1); })
|
|
|
|
->set_reaction(make_staircase);
|
2020-03-29 11:52:10 +00:00
|
|
|
});
|
2018-05-18 15:34:12 +00:00
|
|
|
|
2018-06-11 16:00:40 +00:00
|
|
|
}}
|