mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-10-22 09:27:40 +00:00
fake curvature
This commit is contained in:
385
fake.cpp
Normal file
385
fake.cpp
Normal file
@@ -0,0 +1,385 @@
|
||||
#include "hyper.h"
|
||||
|
||||
// Fake non-Euclidean
|
||||
|
||||
namespace hr {
|
||||
|
||||
EX namespace fake {
|
||||
|
||||
EX ld scale;
|
||||
|
||||
EX eGeometry underlying;
|
||||
EX geometry_information *underlying_cgip;
|
||||
EX hrmap *pmap;
|
||||
EX geometry_information *pcgip;
|
||||
EX eGeometry actual_geometry;
|
||||
|
||||
EX bool in() { return geometry == gFake; }
|
||||
|
||||
// a dummy map that does nothing
|
||||
struct hrmap_fake : hrmap {
|
||||
hrmap *underlying_map;
|
||||
|
||||
template<class T> auto in_underlying(const T& t) -> decltype(t()) {
|
||||
pcgip = cgip;
|
||||
dynamicval<hrmap*> gpm(pmap, this);
|
||||
dynamicval<eGeometry> gag(actual_geometry, geometry);
|
||||
dynamicval<eGeometry> g(geometry, underlying);
|
||||
dynamicval<geometry_information*> gc(cgip, underlying_cgip);
|
||||
dynamicval<hrmap*> gu(currentmap, underlying_map);
|
||||
return t();
|
||||
}
|
||||
|
||||
heptagon *getOrigin() override { return in_underlying([this] { return underlying_map->getOrigin(); }); }
|
||||
|
||||
cell* gamestart() override { return in_underlying([this] { return underlying_map->gamestart(); }); }
|
||||
|
||||
hrmap_fake() {
|
||||
in_underlying([this] { initcells(); underlying_map = currentmap; });
|
||||
for(hrmap*& m: allmaps) if(m == underlying_map) m = NULL;
|
||||
}
|
||||
|
||||
heptagon *create_step(heptagon *parent, int d) override {
|
||||
parent->c.connect(d, parent, d, false);
|
||||
return parent;
|
||||
}
|
||||
|
||||
transmatrix adj(cell *c, int d) override {
|
||||
transmatrix S1, S2;
|
||||
ld dist;
|
||||
in_underlying([c, d, &S1, &S2, &dist] {
|
||||
transmatrix T = currentmap->adj(c, d);
|
||||
S1 = rspintox(tC0(T));
|
||||
transmatrix T1 = spintox(tC0(T)) * T;
|
||||
dist = hdist0(tC0(T1));
|
||||
S2 = xpush(-dist) * T1;
|
||||
});
|
||||
|
||||
if(WDIM == 2) {
|
||||
|
||||
hyperpoint a1, a2, b1, b2;
|
||||
|
||||
in_underlying([c, d, &a1, &a2, &b1, &b2] {
|
||||
a1 = get_corner_position(c, d);
|
||||
a2 = get_corner_position(c, (d+1) % c->type);
|
||||
|
||||
auto c1 = c->move(d);
|
||||
auto d1 = c->c.spin(d);
|
||||
b1 = get_corner_position(c1, d1);
|
||||
b2 = get_corner_position(c1, (d1+1) % c1->type);
|
||||
});
|
||||
|
||||
cgi.adjcheck = hdist0(mid(befake(a1), befake(a2))) + hdist0(mid(befake(b1), befake(b2)));
|
||||
}
|
||||
|
||||
return S1 * xpush(cgi.adjcheck) * S2;
|
||||
}
|
||||
|
||||
void draw_recursive(cell *c, const transmatrix& V, ld a0, ld a1, cell *parent, int depth) {
|
||||
band_shift = 0;
|
||||
if(!do_draw(c, V)) return;
|
||||
drawcell(c, V);
|
||||
|
||||
if(depth >= 15) return;
|
||||
|
||||
// queuestr(V, .2, fts(a0)+":"+fts(a1), 0xFFFFFFFF, 1);
|
||||
|
||||
ld d = hdist0(tC0(V));
|
||||
|
||||
if(false) {
|
||||
curvepoint(spin(-a0) * xpush0(d));
|
||||
curvepoint(spin(-a0) * xpush0(d+.2));
|
||||
curvepoint(spin(-a1) * xpush0(d+.2));
|
||||
curvepoint(spin(-a1) * xpush0(d));
|
||||
curvepoint(spin(-a0) * xpush0(d));
|
||||
queuecurve(0xFF0000FF, 0, PPR::LINE);
|
||||
}
|
||||
|
||||
|
||||
indenter id(2);
|
||||
for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i) != parent) {
|
||||
auto h0 = V * befake(FPIU(get_corner_position(c, i)));
|
||||
auto h1 = V * befake(FPIU(get_corner_position(c, (i+1) % c->type)));
|
||||
ld b0 = atan2(h0);
|
||||
ld b1 = atan2(h1);
|
||||
while(b1 < b0) b1 += 2 * M_PI;
|
||||
if(a0 == -1) {
|
||||
draw_recursive(c->move(i), V * adj(c, i), b0, b1, c, depth+1);
|
||||
}
|
||||
else {
|
||||
if(b1 - b0 > M_PI) continue;
|
||||
|
||||
if(b0 < a0 - M_PI) b0 += 2 * M_PI;
|
||||
if(b0 > a0 + M_PI) b0 -= 2 * M_PI;
|
||||
if(b0 < a0) b0 = a0;
|
||||
|
||||
if(b1 > a1 + M_PI) b1 -= 2 * M_PI;
|
||||
if(b1 < a1 - M_PI) b1 += 2 * M_PI;
|
||||
if(b1 > a1) b1 = a1;
|
||||
|
||||
if(b0 > b1) continue;
|
||||
|
||||
draw_recursive(c->move(i), V * adj(c, i), b0, b1, c, depth+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transmatrix relative_matrix(cell *h2, cell *h1, const hyperpoint& hint) override {
|
||||
if(h1 == h2) return Id;
|
||||
|
||||
for(int a=0; a<h1->type; a++) if(h1->move(a) == h2)
|
||||
return adj(h1, a);
|
||||
|
||||
return Id;
|
||||
}
|
||||
|
||||
transmatrix relative_matrix(heptagon *h2, heptagon *h1, const hyperpoint& hint) override {
|
||||
return relative_matrix(h2->c7, h1->c7, hint);
|
||||
}
|
||||
|
||||
void draw() override {
|
||||
sphereflip = Id;
|
||||
|
||||
// for(int i=0; i<S6; i++) queuepoly(ggmatrix(cwt.at), shWall3D[i], 0xFF0000FF);
|
||||
|
||||
if(pmodel == mdDisk && WDIM == 2) {
|
||||
draw_recursive(centerover, cview(), -1, -1, nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
bool bymatrix = true;
|
||||
|
||||
dq::visited_c.clear();
|
||||
dq::visited_by_matrix.clear();
|
||||
auto enqueue = (bymatrix ? dq::enqueue_by_matrix_c : dq::enqueue_c);
|
||||
enqueue(centerover, cview());
|
||||
|
||||
while(!dq::drawqueue_c.empty()) {
|
||||
auto& p = dq::drawqueue_c.front();
|
||||
cell *c = get<0>(p);
|
||||
transmatrix V = get<1>(p);
|
||||
dynamicval<ld> b(band_shift, get<2>(p));
|
||||
bandfixer bf(V);
|
||||
dq::drawqueue_c.pop();
|
||||
|
||||
if(!do_draw(c, V)) continue;
|
||||
drawcell(c, V);
|
||||
if(in_wallopt() && isWall3(c) && isize(dq::drawqueue_c) > 1000) continue;
|
||||
|
||||
for(int i=0; i<S7; i++) if(c->move(i)) {
|
||||
enqueue(c->move(i), V * adj(c, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EX hrmap* new_map() { return new hrmap_fake; };
|
||||
|
||||
EX hrmap* get_umap() { if(!dynamic_cast<hrmap_fake*>(currentmap)) return nullptr; else return ((hrmap_fake*)currentmap)->underlying_map; }
|
||||
|
||||
#if HDR
|
||||
template<class T> auto in_underlying_geometry(const T& f) -> decltype(f()) {
|
||||
if(!fake::in()) return f();
|
||||
dynamicval<eGeometry> g(geometry, underlying);
|
||||
dynamicval<eGeometry> gag(actual_geometry, geometry);
|
||||
dynamicval<geometry_information*> gc(cgip, underlying_cgip);
|
||||
dynamicval<hrmap*> gpm(pmap, currentmap);
|
||||
dynamicval<hrmap*> gm(currentmap, get_umap());
|
||||
return f();
|
||||
}
|
||||
|
||||
#define FPIU(x) hr::fake::in_underlying_geometry([&] { return (x); })
|
||||
#endif
|
||||
|
||||
EX hyperpoint befake(hyperpoint h) {
|
||||
auto h1 = h / h[WDIM] * scale;
|
||||
h1[WDIM] = 1;
|
||||
if(material(h1) > 1e-3)
|
||||
h1 = normalize(h1);
|
||||
return h1;
|
||||
}
|
||||
|
||||
EX vector<hyperpoint> befake(const vector<hyperpoint>& v) {
|
||||
vector<hyperpoint> res;
|
||||
for(auto& h: v) res.push_back(befake(h));
|
||||
return res;
|
||||
}
|
||||
|
||||
EX ld compute_around(bool setup) {
|
||||
auto &ucgi = *underlying_cgip;
|
||||
|
||||
auto fcs = befake(ucgi.cellshape);
|
||||
|
||||
if(setup) {
|
||||
cgi.cellshape = fcs;
|
||||
cgi.vertices_only = befake(ucgi.vertices_only);
|
||||
}
|
||||
|
||||
hyperpoint h = Hypc;
|
||||
for(int i=0; i<ucgi.face; i++) h += fcs[i];
|
||||
if(material(h) > 0)
|
||||
h = normalize(h);
|
||||
|
||||
if(setup)
|
||||
cgi.adjcheck = 2 * hdist0(h);
|
||||
|
||||
hyperpoint u = Hypc;
|
||||
u += fcs[0];
|
||||
u += fcs[1];
|
||||
|
||||
if(material(u) <= 0)
|
||||
return HUGE_VAL;
|
||||
|
||||
u = normalize(u);
|
||||
hyperpoint h2 = rspintox(h) * xpush0(2 * hdist0(h));
|
||||
|
||||
h2 = spintox(u) * h2;
|
||||
u = spintox(u) * u;
|
||||
|
||||
h2 = gpushxto0(u) * h2;
|
||||
u = gpushxto0(u) * u;
|
||||
|
||||
println(hlog, "h = ", hdist0(h), " ucgi = ", format("%p", &ucgi), " @ ", hyperbolic, " / ", sphere, " h2 = ", h2);
|
||||
|
||||
ld x = hypot(h2[1], h2[2]);
|
||||
ld y = h2[0];
|
||||
return 360 / (90 + atan(y/x) / degree);
|
||||
}
|
||||
|
||||
EX void generate() {
|
||||
println(hlog, "Generating fake");
|
||||
FPIU( cgi.require_basics() );
|
||||
auto &ucgi = *underlying_cgip;
|
||||
|
||||
cgi.loop = ucgi.loop;
|
||||
cgi.face = ucgi.face;
|
||||
|
||||
for(int a=0; a<16; a++)
|
||||
for(int b=0; b<16; b++) {
|
||||
cgi.dirs_adjacent[a][b] = ucgi.dirs_adjacent[a][b];
|
||||
cgi.next_dir[a][b] = ucgi.next_dir[a][b];
|
||||
}
|
||||
|
||||
for(int b=0; b<12; b++)
|
||||
cgi.spins[b] = ucgi.spins[b];
|
||||
|
||||
compute_around(true);
|
||||
}
|
||||
|
||||
int get_middle() {
|
||||
if(S7 == 20) return 5;
|
||||
if(S7 == 8) return 4;
|
||||
return 3;
|
||||
}
|
||||
|
||||
EX ld around;
|
||||
|
||||
EX void compute_scale() {
|
||||
|
||||
int middle = get_middle();
|
||||
|
||||
// the value of 'around' which makes the tiling Euclidean
|
||||
ld good = M_PI / asin(cos(M_PI/middle) / sin(M_PI/underlying_cgip->face));
|
||||
|
||||
println(hlog, "good = ", good);
|
||||
|
||||
if(abs(good - around) < 1e-6) good = around;
|
||||
|
||||
if(around == good) {
|
||||
ginf[gFake].g = WDIM == 3 ? giEuclid3 : giEuclid2;
|
||||
}
|
||||
|
||||
if(around > good) {
|
||||
ginf[gFake].g = WDIM == 3 ? giHyperb3 : giHyperb2;
|
||||
}
|
||||
|
||||
if(around < good) {
|
||||
ginf[gFake].g = WDIM == 3 ? giSphere3 : giSphere2;
|
||||
}
|
||||
|
||||
ld around_ideal = 1/(1/2. - 1./get_middle());
|
||||
println(hlog, "around_ideal = ", around_ideal);
|
||||
|
||||
if(euclid) scale = 1;
|
||||
else if(abs(around_ideal - around) < 1e-6) {
|
||||
hyperpoint h0 = underlying_cgip->cellshape[0];
|
||||
auto s = kleinize(h0);
|
||||
ld d = hypot_d(LDIM, s);
|
||||
scale = 1/d;
|
||||
|
||||
hyperpoint h = h0;
|
||||
auto h1 = h / h[WDIM] * scale;
|
||||
h1[WDIM] = 1;
|
||||
|
||||
println(hlog, "material = ", material(h1));
|
||||
}
|
||||
else {
|
||||
ld minscale = 0, maxscale = 10;
|
||||
for(int it=0; it<100; it++) {
|
||||
scale = (minscale + maxscale) / 2;
|
||||
ld ar = compute_around(false);
|
||||
println(hlog, "scale = ", scale, " ar = ", ar);
|
||||
if(sphere) {
|
||||
if(ar < around) maxscale = scale;
|
||||
else minscale = scale;
|
||||
}
|
||||
else {
|
||||
if(ar > around) maxscale = scale;
|
||||
else minscale = scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
sightranges[gFake] = sightranges[underlying] * scale;
|
||||
}
|
||||
|
||||
void set_gfake(int c, ld _around) {
|
||||
stop_game();
|
||||
cgi.require_basics();
|
||||
fake::scale = scale;
|
||||
underlying = geometry;
|
||||
underlying_cgip = cgip;
|
||||
ginf[gFake] = ginf[underlying];
|
||||
|
||||
set_geometry(gFake);
|
||||
|
||||
around = _around;
|
||||
|
||||
compute_scale();
|
||||
check_cgi();
|
||||
|
||||
compute_scale();
|
||||
check_cgi();
|
||||
}
|
||||
|
||||
EX void change_around() {
|
||||
if(around > 2) {
|
||||
ld t = sightranges[gFake] / (sightranges[underlying] * scale);
|
||||
compute_scale();
|
||||
ray::reset_raycaster();
|
||||
sightranges[gFake] *= t;
|
||||
}
|
||||
};
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-gfake")) {
|
||||
if(fake::in()) shift_arg_formula(around, change_around);
|
||||
else {
|
||||
shift(); int c = argi();
|
||||
ld around;
|
||||
shift_arg_formula(around);
|
||||
set_gfake(c, around);
|
||||
}
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto fundamentalhook = addHook(hooks_args, 100, readArgs);
|
||||
|
||||
EX }
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user