1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-10-31 19:36:16 +00:00
hyperrogue/rogueviz/hyperbolic-analogs.cpp

425 lines
10 KiB
C++
Raw Normal View History

2021-03-31 17:39:31 +00:00
#include "rogueviz.h"
// used in: https://www.youtube.com/watch?v=H7NKhKTjHVE&feature=youtu.be
// run: -analogs
namespace hr {
namespace analogs {
patterns::ePattern wp;
flagtype wpf;
texture::texture_data earth;
bool loaded;
bool textured = true;
basic_textureinfo tv;
int earthpart;
string spherename = "A";
string hypername = "B";
vector<reaction_t> models_to_use = {
[] {
if(sphere) {
pmodel = mdDisk;
pconf.alpha = 1000;
pconf.scale *= pconf.alpha;
View = cspin(1, 2, 20 * degree) * View;
}
else {
pmodel = mdHyperboloid;
pconf.top_z = 4;
pconf.ballangle = -20;
pconf.scale = .75;
}
spherename = "Euclidean sphere";
hypername = "Minkowski hyperboloid";
},
[] {
pmodel = mdDisk;
pconf.alpha = 1;
pconf.scale = .9;
spherename = "stereographic projection";
if(sphere) pconf.scale *= .75;
hypername = "Poincaré disk model";
},
[] {
pmodel = mdDisk;
pconf.alpha = 0;
pconf.scale = sphere ? 0.25 : .9;
spherename = "gnomonic projection";
hypername = "Beltrami-Klein disk model";
},
[] {
pmodel = mdDisk;
pconf.alpha = 1000;
pconf.scale *= pconf.alpha;
if(hyperbolic) pconf.scale *= .25;
spherename = "orthographic projection";
hypername = "Gans model";
},
[] {
pmodel = mdEquidistant;
spherename = "azimuthal equidistant";
},
[] {
pmodel = mdEquiarea;
spherename = "azimuthal equi-area";
},
[] {
pmodel = mdBandEquidistant;
pconf.scale = .5;
if(sphere) pconf.scale *= 2;
spherename = "equirectangular projection";
hypername = "Lobachevsky coordinates";
},
[] {
pmodel = mdBand;
pconf.scale = .5;
if(sphere) pconf.scale *= 0.9;
spherename = "Mercator projection";
hypername = "band model";
},
[] {
pmodel = mdBandEquiarea;
pconf.scale = .5;
pconf.stretch = M_PI;
spherename = "cylindrical equal-area";
},
[] {
pmodel = mdCentralCyl;
pconf.scale = .5;
spherename = "central cylindrical";
},
[] {
pmodel = mdGallStereographic;
pconf.scale = .5;
pconf.scale *= 1.8;
spherename = "Gall stereographic";
},
[] {
pmodel = mdMiller;
pconf.scale = .5;
spherename = "Miller cylindrical";
},
[] {
pmodel = mdLoximuthal;
pconf.scale = .5;
if(sphere) pconf.scale *= 2;
spherename = "loximuthal projection";
pconf.loximuthal_parameter = 15 * degree;
},
[] {
pmodel = mdSinusoidal;
pconf.scale = .5;
if(sphere) pconf.scale *= 1.5;
spherename = "(co)sinusoidal projection";
},
[] {
pmodel = mdMollweide;
pconf.scale = .5;
if(sphere) pconf.scale *= 2;
spherename = "Mollweide projection";
},
[] {
pmodel = mdCollignon;
pconf.scale = .5;
if(sphere) pconf.scale *= 2;
spherename = "Collignon projection";
},
[] {
pmodel = mdTwoPoint;
pconf.scale = .5;
if(sphere) pconf.scale *= 2;
spherename = "two-point equidistant";
},
[] {
pmodel = mdSimulatedPerspective;
pconf.scale = .5;
spherename = "two-point azimuthal";
},
[] {
pmodel = mdAitoff;
pconf.scale = .5;
if(sphere) pconf.scale *= 2;
spherename = "Aitoff projection";
},
[] {
pmodel = mdHammer;
pconf.scale = .5;
if(sphere) pconf.scale *= 1.3;
spherename = "Hammer projection";
},
[] {
pmodel = mdWinkelTripel;
pconf.scale = .5;
if(sphere) pconf.scale *= 2;
spherename = "Winkel tripel projection";
},
[] {
pmodel = mdWerner;
pconf.scale = .3;
spherename = "Werner projection";
},
};
ld prec = 5;
void draw_earth() {
if(textured && !loaded) {
earth.twidth = earth.theight = 0; earth.stretched = true;
// earth.readtexture("extra/to-earth.png");
earth.readtexture(file_exists("textures/earth.png") ? "textures/earth.png" : "textures/earth320.png");
earth.loadTextureGL();
loaded = true;
}
auto tform = [] (hyperpoint euc) {
return xpush(euc[0] * degree) * ypush(euc[1] * degree) * C0;
};
if(sphere && textured) {
shiftmatrix S = ggmatrix(currentmap->gamestart());
tv.tvertices.clear();
if(prec < .5) prec = 1;
for(ld x=-180; x<180; x+=prec)
for(ld y=-90; y<90; y+=prec) {
vector<hyperpoint> bases = {
point31(x, y, 0),
point31(x+prec, y, 0),
point31(x, y+prec, 0),
point31(x+prec, y, 0),
point31(x, y+prec, 0),
point31(x+prec, y+prec, 0)
};
bool ok = true;
if(pmodel == mdSimulatedPerspective) for(hyperpoint base: bases) {
hyperpoint h = S.T * tform(base);
if(h[2] <= 0.1) ok = false;
}
if(among(pmodel, mdEquidistant, mdEquiarea)) for(hyperpoint base: bases) {
hyperpoint h = S.T * tform(base);
if(h[2] <= -0.999) ok = false;
}
if(ok) for(auto base: bases) {
hyperpoint h = base;
hyperpoint h1 = tform(h);
curvepoint(h1);
hyperpoint vi = point31((h[0] + 180) / 360., (h[1] + 90) / 180., 0);
tv.tvertices.push_back(glhr::pointtogl(vi));
color_t col = earth.get_texture_pixel(vi[0]*earth.twidth, vi[1]*earth.theight);
col &= 0xFFFFFF;
addaura(S*h1, col, 0);
}
}
if(isize(tv.tvertices)) {
color_t full = 0xFFFFFFFF;
part(full, 0) = earthpart;
auto& poly = queuecurve(ggmatrix(currentmap->gamestart()), 0, full, PPR::LINE);
poly.flags |= POLY_TRIANGLES;
poly.tinf = &tv;
poly.offset_texture = 0;
tv.texture_id = earth.textureid;
}
}
}
bool cycle_models = false;
bool animate = true;
EX void compare() {
if(!animate) return;
centerover = cwt.at;
spherename = "";
hypername = "";
ld t = ticks * 1. / anims::period;
t = frac(t);
if(cycle_models) {
int mtu = isize(models_to_use);
t *= mtu;
if(anims::period < 100) {
t = ticks % mtu;
println(hlog, "t = ", t);
}
int index = t;
t = frac(t);
pconf.alpha = 1;
pconf.scale = .9;
pconf.stretch = 1;
models_to_use[index]();
}
View = Id;
ld t4 = t * 5;
int at4 = t4;
t4 -= at4;
t4 = t4 * t4 * (3 - 2 * t4);
earthpart = 192;
if(at4 == 0)
earthpart = lerp(255, earthpart, t4);
else if(at4 == 1)
View = spin(t4 * 180 * degree) * View;
else if(at4 == 2)
View = xpush(t4 * M_PI) * spin(M_PI) * View;
else if(at4 == 3)
View = ypush(t4 * M_PI) * xpush(M_PI) * spin(M_PI) * View;
else if(at4 == 4) {
View = ypush(M_PI) * xpush(M_PI) * spin(M_PI) * View;
earthpart = lerp(255, earthpart, 1-t4);
}
anims::moved();
no_find_player = true;
vid.cells_drawn_limit = 20000;
pconf.twopoint_param = 0.5;
neon_nofill = true;
if(hyperbolic && pmodel == mdWerner)
neon_mode = eNeon::neon;
else
neon_mode = eNeon::none;
vid.smart_area_based = (pmodel != mdHyperboloid);
if(!inHighQual) {
vid.cells_drawn_limit = 1000;
}
}
EX bool ourStats() {
draw_centerover = false;
displayfr(10, 10 + 2 * vid.fsize, 2, vid.fsize * 2, spherename, 0xFFFFFF, 0);
displayfr(vid.xres - 10, vid.yres - (10 + 2 * vid.fsize), 2, vid.fsize * 2, hypername, 0xFFFFFF, 16);
nohelp = true;
nomenukey = true;
clearMessages();
glflush();
hide_hud = false;
return true;
}
bool restrict_cell(cell *c, const shiftmatrix& V) {
if(hyperbolic && zebra40(c) >= 40)
c->landparam = 0x0080C0;
if(hyperbolic && pmodel == mdWerner && hdist0(V.T * C0) > 3)
return true;
return false;
}
int current_index = -1;
void choose_projection() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen(0);
dialog::init(XLAT("choose projection"), 0xFFFFFFFF, 150, 0);
for(int i=0; i<isize(models_to_use); i++) {
hypername = "";
if(1) {
dynamicval<projection_configuration> vp(pconf, pconf);
dynamicval<transmatrix> v(View, View);
models_to_use[i]();
}
dialog::addBoolItem(hypername == "" ? spherename : spherename + " / " + hypername, i == current_index, 'a'+i);
dialog::add_action([i] {
current_index = i;
dual::switch_to(0);
models_to_use[i]();
dual::switch_to(1);
models_to_use[i]();
});
}
dialog::addBack();
dialog::display();
}
void show() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen(0);
dialog::init(XLAT("hyperbolic analogs"), 0xFFFFFFFF, 150, 0);
add_edit(prec);
dialog::addItem("choose a projection", 'p');
dialog::add_action_push(choose_projection);
add_edit(earthpart);
add_edit(textured);
add_edit(animate);
add_edit(cycle_models);
dialog::addBack();
dialog::display();
}
void enable() {
using rogueviz::rv_hook;
vid.linequality = 4;
firstland = specialland = laCanvas;
patterns::whichCanvas = 'F';
colortables['F'][0] = 0x80C080;
colortables['F'][1] = 0x80A080;
pconf.scale = .3;
vid.use_smart_range = 2;
vid.smart_range_detail = 2;
mapeditor::drawplayer = false;
showstartmenu = false;
dual::enable();
dual::switch_to(0);
set_geometry(gSphere);
set_variation(eVariation::pure);
firstland = specialland = laCanvas;
dual::switch_to(1);
set_geometry(gNormal);
set_variation(eVariation::pure);
firstland = specialland = laCanvas;
rv_hook(hooks_frame, 100, draw_earth);
rv_hook(hooks_drawcell, 100, restrict_cell);
rv_hook(anims::hooks_anim, 100, compare);
rv_hook(hooks_prestats, 100, ourStats);
rv_hook(hooks_o_key, 80, [] (o_funcs& v) { v.push_back(named_dialog("hyperbolic analogs", show)); });
}
auto msc = arg::add3("-analogs", enable)
+ addHook(hooks_configfile, 100, [] {
param_f(prec, "analogs_precision")
->editable(0, 30, .5, "precision", "larger values are less precise", 'p');
param_b(animate, "analogs_animate")
->editable("animate", 'a');
param_b(cycle_models, "analogs_cycle")
->editable("cycle models in the animation", 'm');
param_i(earthpart, "earthpart")
->editable(0, 255, 15, "Earth transparency", "", 't');
param_b(textured, "analogs_texture")
->editable("draw Earth", 'T');
});
}
}