mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-11 09:50:34 +00:00
Merge branch 'master' into hooks-naming
This commit is contained in:
commit
6f6586b3f2
@ -623,16 +623,16 @@ void geometry_information::slimetriangle(hyperpoint a, hyperpoint b, hyperpoint
|
||||
texture_order([&] (ld x, ld y) {
|
||||
ld z = 1-x-y;
|
||||
ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8) * (hybri ? .5 : 1);
|
||||
hyperpoint h = direct_exp(tangent_length(a*x+b*y+c*z, r), 10);
|
||||
hyperpoint h = direct_exp(tangent_length(a*x+b*y+c*z, r));
|
||||
hpcpush(h);
|
||||
});
|
||||
}
|
||||
|
||||
void geometry_information::balltriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev) {
|
||||
if(lev == 0) {
|
||||
hpcpush(direct_exp(a, 10));
|
||||
hpcpush(direct_exp(b, 10));
|
||||
hpcpush(direct_exp(c, 10));
|
||||
hpcpush(direct_exp(a));
|
||||
hpcpush(direct_exp(b));
|
||||
hpcpush(direct_exp(c));
|
||||
}
|
||||
else {
|
||||
auto midpoint = [&] (hyperpoint h1, hyperpoint h2) {
|
||||
@ -1254,7 +1254,16 @@ hpcshape& geometry_information::generate_pipe(ld length, ld width) {
|
||||
}
|
||||
}
|
||||
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
for(int a=0; a<MAX_R; a++) {
|
||||
hpcpush(at(MAX_X, a));
|
||||
hpcpush(at(MAX_X, a+1));
|
||||
hpcpush(xpush0(length));
|
||||
hpcpush(at(MAX_X, a+1));
|
||||
hpcpush(at(MAX_X, a));
|
||||
hpcpush(C0);
|
||||
}
|
||||
|
||||
last->flags |= POLY_TRIANGLES | POLY_PRINTABLE;
|
||||
add_texture(*last);
|
||||
finishshape();
|
||||
extra_vertices();
|
||||
|
@ -78,7 +78,7 @@ void shape::build_from_angles_edges() {
|
||||
bool correct_index(int index, int size) { return index >= 0 && index < size; }
|
||||
template<class T> bool correct_index(int index, const T& v) { return correct_index(index, isize(v)); }
|
||||
|
||||
template<class T> void verify_index(int index, const T& v) { if(!correct_index(index, v)) throw hr_parse_exception("bad index"); }
|
||||
template<class T> void verify_index(int index, const T& v, exp_parser& ep) { if(!correct_index(index, v)) throw hr_parse_exception("bad index: " + its(index) + " at " + ep.where()); }
|
||||
|
||||
string unnamed = "unnamed";
|
||||
|
||||
@ -102,7 +102,7 @@ EX void load(const string& fname) {
|
||||
int ai;
|
||||
if(ep.next() == ')') ai = isize(c.shapes)-1;
|
||||
else ai = ep.iparse();
|
||||
verify_index(ai, c.shapes);
|
||||
verify_index(ai, c.shapes, ep);
|
||||
c.shapes[ai].flags |= f;
|
||||
ep.force_eat(")");
|
||||
};
|
||||
@ -171,7 +171,12 @@ EX void load(const string& fname) {
|
||||
else if(ep.eat(")")) break;
|
||||
else throw hr_parse_exception("expecting , or )");
|
||||
}
|
||||
cc.build_from_angles_edges();
|
||||
try {
|
||||
cc.build_from_angles_edges();
|
||||
}
|
||||
catch(hr_parse_exception& ex) {
|
||||
throw hr_parse_exception(ex.s + ep.where());
|
||||
}
|
||||
cc.connections.resize(cc.size());
|
||||
for(int i=0; i<isize(cc.connections); i++)
|
||||
cc.connections[i] = make_tuple(cc.id, i, false);
|
||||
@ -191,8 +196,15 @@ EX void load(const string& fname) {
|
||||
else if(ep.eat(")")) break;
|
||||
else throw hr_parse_exception("expecting , or )");
|
||||
}
|
||||
cc.build_from_angles_edges();
|
||||
try {
|
||||
cc.build_from_angles_edges();
|
||||
}
|
||||
catch(hr_parse_exception& ex) {
|
||||
throw hr_parse_exception(ex.s + ep.where());
|
||||
}
|
||||
cc.connections.resize(cc.size());
|
||||
for(int i=0; i<isize(cc.connections); i++)
|
||||
cc.connections[i] = make_tuple(cc.id, i, false);
|
||||
}
|
||||
else if(ep.eat("conway(\"")) {
|
||||
string s = "";
|
||||
@ -201,7 +213,7 @@ EX void load(const string& fname) {
|
||||
if(ep.eat("(")) m = 0;
|
||||
else if(ep.eat("[")) m = 1;
|
||||
else if(ep.eat("\"")) break;
|
||||
else throw hr_parse_exception("cannot parse Conway notation");
|
||||
else throw hr_parse_exception("cannot parse Conway notation, " + ep.where());
|
||||
|
||||
int ai = 0;
|
||||
int as = ep.iparse();
|
||||
@ -221,18 +233,18 @@ EX void load(const string& fname) {
|
||||
ep.force_eat(")");
|
||||
}
|
||||
else if(ep.eat("c(")) {
|
||||
int ai = ep.iparse(); verify_index(ai, c.shapes); ep.force_eat(",");
|
||||
int as = ep.iparse(); verify_index(as, c.shapes[ai]); ep.force_eat(",");
|
||||
int bi = ep.iparse(); verify_index(bi, c.shapes); ep.force_eat(",");
|
||||
int bs = ep.iparse(); verify_index(bs, c.shapes[bi]); ep.force_eat(",");
|
||||
int ai = ep.iparse(); verify_index(ai, c.shapes, ep); ep.force_eat(",");
|
||||
int as = ep.iparse(); verify_index(as, c.shapes[ai], ep); ep.force_eat(",");
|
||||
int bi = ep.iparse(); verify_index(bi, c.shapes, ep); ep.force_eat(",");
|
||||
int bs = ep.iparse(); verify_index(bs, c.shapes[bi], ep); ep.force_eat(",");
|
||||
int m = ep.iparse(); ep.force_eat(")");
|
||||
c.shapes[ai].connections[as] = make_tuple(bi, bs, m);
|
||||
c.shapes[bi].connections[bs] = make_tuple(ai, as, m);
|
||||
}
|
||||
else if(ep.eat("subline(")) {
|
||||
int ai = ep.iparse(); verify_index(ai, c.shapes); ep.force_eat(",");
|
||||
int as = ep.iparse(); verify_index(as, c.shapes[ai]); ep.force_eat(",");
|
||||
int bs = ep.iparse(); verify_index(bs, c.shapes[ai]); ep.force_eat(")");
|
||||
int ai = ep.iparse(); verify_index(ai, c.shapes, ep); ep.force_eat(",");
|
||||
int as = ep.iparse(); verify_index(as, c.shapes[ai], ep); ep.force_eat(",");
|
||||
int bs = ep.iparse(); verify_index(bs, c.shapes[ai], ep); ep.force_eat(")");
|
||||
c.shapes[ai].sublines.emplace_back(as, bs);
|
||||
}
|
||||
else if(ep.eat("sublines(")) {
|
||||
@ -252,7 +264,7 @@ EX void load(const string& fname) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else throw hr_parse_exception("expecting command");
|
||||
else throw hr_parse_exception("expecting command, " + ep.where());
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,6 +532,8 @@ EX void choose() {
|
||||
catch(hr_parse_exception& ex) {
|
||||
println(hlog, "failed: ", ex.s);
|
||||
set_geometry(gNormal);
|
||||
start_game();
|
||||
addMessage("failed: " + ex.s);
|
||||
}
|
||||
start_game();
|
||||
return true;
|
||||
|
@ -492,8 +492,6 @@ int gl_width(int size, const char *s) {
|
||||
return x;
|
||||
}
|
||||
|
||||
vector<glhr::textured_vertex> tver;
|
||||
|
||||
glhr::textured_vertex charvertex(int x1, int y1, ld tx, ld ty) {
|
||||
glhr::textured_vertex res;
|
||||
res.coords[0] = x1;
|
||||
@ -842,12 +840,12 @@ EX ld realradius() {
|
||||
ld vradius = current_display->radius;
|
||||
if(sphere) {
|
||||
if(sphereflipped())
|
||||
vradius /= sqrt(vid.alpha*vid.alpha - 1);
|
||||
vradius /= sqrt(pconf.alpha*pconf.alpha - 1);
|
||||
else
|
||||
vradius = 1e12; // use the following
|
||||
}
|
||||
if(euclid)
|
||||
vradius = current_display->radius * get_sightrange() / (1 + vid.alpha) / 2.5;
|
||||
vradius = current_display->radius * get_sightrange() / (1 + pconf.alpha) / 2.5;
|
||||
vradius = min<ld>(vradius, min(vid.xres, vid.yres) / 2);
|
||||
return vradius;
|
||||
}
|
||||
@ -857,14 +855,14 @@ EX void drawmessage(const string& s, int& y, color_t col) {
|
||||
int space;
|
||||
if(dual::state)
|
||||
space = vid.xres;
|
||||
else if(y > current_display->ycenter + rrad * vid.stretch)
|
||||
else if(y > current_display->ycenter + rrad * pconf.stretch)
|
||||
space = vid.xres;
|
||||
else if(y > current_display->ycenter)
|
||||
space = current_display->xcenter - rhypot(rrad, (y-current_display->ycenter) / vid.stretch);
|
||||
space = current_display->xcenter - rhypot(rrad, (y-current_display->ycenter) / pconf.stretch);
|
||||
else if(y > current_display->ycenter - vid.fsize)
|
||||
space = current_display->xcenter - rrad;
|
||||
else if(y > current_display->ycenter - vid.fsize - rrad * vid.stretch)
|
||||
space = current_display->xcenter - rhypot(rrad, (current_display->ycenter-vid.fsize-y) / vid.stretch);
|
||||
else if(y > current_display->ycenter - vid.fsize - rrad * pconf.stretch)
|
||||
space = current_display->xcenter - rhypot(rrad, (current_display->ycenter-vid.fsize-y) / pconf.stretch);
|
||||
else
|
||||
space = vid.xres;
|
||||
|
||||
@ -949,7 +947,7 @@ EX void drawCircle(int x, int y, int size, color_t color, color_t fillcolor IS(0
|
||||
if(ISMOBILE && pts > 72) pts = 72;
|
||||
for(int r=0; r<pts; r++) {
|
||||
float rr = (M_PI * 2 * r) / pts;
|
||||
glcoords.push_back(glhr::makevertex(x + size * sin(rr), y + size * vid.stretch * cos(rr), 0));
|
||||
glcoords.push_back(glhr::makevertex(x + size * sin(rr), y + size * pconf.stretch * cos(rr), 0));
|
||||
}
|
||||
current_display->set_all(0);
|
||||
glhr::vertices(glcoords);
|
||||
@ -969,13 +967,13 @@ EX void drawCircle(int x, int y, int size, color_t color, color_t fillcolor IS(0
|
||||
#if CAP_XGD
|
||||
gdpush(4); gdpush(color); gdpush(x); gdpush(y); gdpush(size);
|
||||
#elif CAP_SDLGFX
|
||||
if(vid.stretch == 1) {
|
||||
if(pconf.stretch == 1) {
|
||||
if(fillcolor) filledCircleColor(s, x, y, size, fillcolor);
|
||||
if(color) ((vid.antialias && AA_NOGL)?aacircleColor:circleColor) (s, x, y, size, color);
|
||||
}
|
||||
else {
|
||||
if(fillcolor) filledEllipseColor(s, x, y, size, size * vid.stretch, fillcolor);
|
||||
if(color) ((vid.antialias && AA_NOGL)?aaellipseColor:ellipseColor) (s, x, y, size, size * vid.stretch, color);
|
||||
if(fillcolor) filledEllipseColor(s, x, y, size, size * pconf.stretch, fillcolor);
|
||||
if(color) ((vid.antialias && AA_NOGL)?aaellipseColor:ellipseColor) (s, x, y, size, size * pconf.stretch, color);
|
||||
}
|
||||
#elif CAP_SDL
|
||||
int pts = size * 4;
|
||||
@ -1022,7 +1020,7 @@ EX void displayColorButton(int x, int y, const string& name, int key, int align,
|
||||
}
|
||||
|
||||
ld textscale() {
|
||||
return vid.fsize / (current_display->radius * cgi.crossf) * (1+vid.alpha) * 2;
|
||||
return vid.fsize / (current_display->radius * cgi.crossf) * (1+pconf.alpha) * 2;
|
||||
}
|
||||
|
||||
EX bool setfsize = true;
|
||||
|
@ -143,12 +143,22 @@ void celldrawer::setcolors() {
|
||||
case laCrossroads2: case laCrossroads3: case laCrossroads4: case laCrossroads5:
|
||||
case laRose: case laPower: case laWildWest: case laHalloween: case laRedRock:
|
||||
case laDragon: case laStorms: case laTerracotta: case laMercuryRiver:
|
||||
case laDesert: case laKraken: case laDocks: case laCA:
|
||||
case laDesert: case laKraken: case laDocks:
|
||||
case laMotion: case laGraveyard: case laWineyard: case laLivefjord:
|
||||
case laRlyeh: case laHell: case laCrossroads: case laJungle:
|
||||
case laAlchemist: case laFrog:
|
||||
fcol = floorcolors[c->land]; break;
|
||||
|
||||
case laCA:
|
||||
fcol = floorcolors[c->land];
|
||||
if(geosupport_chessboard()) {
|
||||
if(chessvalue(c)) fcol += 0x202020;
|
||||
}
|
||||
else if(geosupport_threecolor()) {
|
||||
fcol += 0x202020 * pattern_threecolor(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case laWet:
|
||||
fcol = 0x40FF40; break;
|
||||
|
||||
@ -1580,6 +1590,10 @@ void celldrawer::draw_features_and_walls_3d() {
|
||||
if(c->move(a) && (among(pmodel, mdPerspective, mdGeodesic) || gmatrix0.count(c->move(a))))
|
||||
b = (patterns::innerwalls && (tC0(V)[2] < tC0(V * currentmap->adj(c, a))[2])) || !isWall3(c->move(a), dummy);
|
||||
if(b) {
|
||||
#if CAP_WRL
|
||||
/* always render */
|
||||
if(wrl::in && wrl::print) ; else
|
||||
#endif
|
||||
if(pmodel == mdPerspective && !sphere && !quotient && !kite::in() && !nonisotropic && !hybri && !experimental && !nih) {
|
||||
if(a < 4 && among(geometry, gHoroTris, gBinary3) && celldistAlt(c) >= celldistAlt(centerover)) continue;
|
||||
else if(a < 2 && among(geometry, gHoroRec) && celldistAlt(c) >= celldistAlt(centerover)) continue;
|
||||
|
@ -3904,3 +3904,14 @@ Geometries:
|
||||
- reverse FPP mode on iOS should be fixed
|
||||
- fixed the missing message when PC could not stay in place
|
||||
- fixed a potential rare crash
|
||||
|
||||
2020-04-17 21:00 Update 11.3j:
|
||||
- the Hypersian Rug mode now uses HyperRogue's 3D engine. As a result, its controls are consistent with HyperRogue 3D (which has received shift-strafe for this consistency), you can now view it in all models, and embed in Solv and Nil geometries.
|
||||
- a drawing tool (see creative mode). Contrary to Vector Graphics Editor (now called Shape Editor) and texture editor, this simulates on using a huge non-Euclidean blackboard (unless played in Euclidean geometry or in a quotient space, of course).
|
||||
- WRL export (export e.g. your Hypersian Rug or a hyperbolic honeycomb in ball model to a 3D modelling tool or a 3D printer)
|
||||
- fixed some issues with 'vertical stretch' (acted inconsistently, stretched text)
|
||||
- fixed central inversion in 3D models
|
||||
- better error information when trying to read an illegal tes file
|
||||
- CA mode now automatically awards Orb of Aether (so you can step space) and is simulated on every step in animation mode
|
||||
- more accurate Solv rendering (using RK4 method instead of buggy midpoint)
|
||||
- when giving values, you can use "..|" (animate with sharp changes); "../" can be also used for spline interpolation
|
||||
|
29
complex.cpp
29
complex.cpp
@ -3347,6 +3347,14 @@ EX namespace ca {
|
||||
|
||||
EX eWall wlive = waFloorA;
|
||||
|
||||
EX unordered_set<cell*> changed;
|
||||
|
||||
EX void list_adj(cell *c) {
|
||||
changed.insert(c);
|
||||
for(cell* c1: adj_minefield_cells(c))
|
||||
changed.insert(c1);
|
||||
}
|
||||
|
||||
// you can also do -mineadj
|
||||
|
||||
EX string fillup(string s) {
|
||||
@ -3372,6 +3380,12 @@ EX namespace ca {
|
||||
shift(); wlive = eWall(argi());
|
||||
return 0;
|
||||
}
|
||||
if(argis("-carun")) {
|
||||
shift(); int iter = argi();
|
||||
start_game();
|
||||
for(int i=0; i<iter; i++) simulate();
|
||||
return 0;
|
||||
}
|
||||
if(args()[0] != '-') return 1;
|
||||
if(args()[1] != 'c') return 1;
|
||||
int livedead = args()[2] - '0';
|
||||
@ -3395,13 +3409,16 @@ EX namespace ca {
|
||||
|
||||
EX void simulate() {
|
||||
if(cwt.at->land != laCA) return;
|
||||
vector<cell*>& allcells = currentmap->allcells();
|
||||
if(items[itOrbAether] < 2) items[itOrbAether] = 2;
|
||||
vector<cell*> allcells;
|
||||
for(cell *c: changed) allcells.push_back(c);
|
||||
changed.clear();
|
||||
int dcs = isize(allcells);
|
||||
std::vector<bool> willlive(dcs);
|
||||
int old = 0, xold = 0;
|
||||
for(int i=0; i<dcs; i++) {
|
||||
cell *c = allcells[i];
|
||||
if(c->land != laCA) return;
|
||||
if(c->land != laCA) continue;
|
||||
int nei = 0, live = 0;
|
||||
for(cell *c2: adj_minefield_cells(c)) {
|
||||
nei++; if(c2->wall == wlive) live++;
|
||||
@ -3412,9 +3429,15 @@ EX namespace ca {
|
||||
}
|
||||
for(int i=0; i<dcs; i++) {
|
||||
cell *c = allcells[i];
|
||||
auto last = c->wall;
|
||||
c->wall = willlive[i] ? wlive : waNone;
|
||||
if(c->wall != last) {
|
||||
dynamicval<ld> d(prob, 0);
|
||||
setdist(c, 7, nullptr);
|
||||
list_adj(c);
|
||||
}
|
||||
}
|
||||
println(hlog, tie(dcs, old, xold));
|
||||
println(hlog, make_tuple(dcs, old, xold, isize(changed)));
|
||||
}
|
||||
EX }
|
||||
|
||||
|
10
complex2.cpp
10
complex2.cpp
@ -559,10 +559,14 @@ EX hookset<bool(cell*)> hooks_mark;
|
||||
EX void performMarkCommand(cell *c) {
|
||||
if(!c) return;
|
||||
if(callhandlers(false, hooks_mark, c)) return;
|
||||
if(c->land == laCA && c->wall == waNone)
|
||||
c->wall = waFloorA;
|
||||
else if(c->land == laCA && c->wall == waFloorA)
|
||||
if(c->land == laCA && c->wall == waNone) {
|
||||
c->wall = ca::wlive;
|
||||
ca::list_adj(c);
|
||||
}
|
||||
else if(c->land == laCA && c->wall == ca::wlive) {
|
||||
c->wall = waNone;
|
||||
ca::list_adj(c);
|
||||
}
|
||||
if(c->land != laMinefield) return;
|
||||
if(c->item) return;
|
||||
if(!mightBeMine(c)) return;
|
||||
|
157
config.cpp
157
config.cpp
@ -305,10 +305,10 @@ EX void initConfig() {
|
||||
addsaver(precise_width, "precisewidth", .5);
|
||||
addsaver(linepatterns::width, "pattern-linewidth", 1);
|
||||
addsaver(fat_edges, "fat-edges");
|
||||
addsaver(vid.scale, "scale", 1);
|
||||
addsaver(vid.xposition, "xposition", 0);
|
||||
addsaver(vid.yposition, "yposition", 0);
|
||||
addsaver(vid.alpha, "projection", 1);
|
||||
addsaver(pconf.scale, "scale", 1);
|
||||
addsaver(pconf.xposition, "xposition", 0);
|
||||
addsaver(pconf.yposition, "yposition", 0);
|
||||
addsaver(pconf.alpha, "projection", 1);
|
||||
addsaver(vid.sspeed, "scrollingspeed", 0);
|
||||
addsaver(vid.mspeed, "movement speed", 1);
|
||||
addsaver(vid.full, "fullscreen", false);
|
||||
@ -329,14 +329,14 @@ EX void initConfig() {
|
||||
|
||||
// special graphics
|
||||
|
||||
addsaver(vid.ballangle, "ball angle", 20);
|
||||
addsaver(pconf.ballangle, "ball angle", 20);
|
||||
addsaver(vid.yshift, "Y shift", 0);
|
||||
addsaver(vid.use_wall_radar, "wallradar", true);
|
||||
addsaver(vid.fixed_facing, "fixed facing", 0);
|
||||
addsaver(vid.fixed_facing_dir, "fixed facing dir", 90);
|
||||
addsaver(vid.fixed_yz, "fixed YZ", true);
|
||||
addsaver(vid.camera_angle, "camera angle", 0);
|
||||
addsaver(vid.ballproj, "ballproj", 1);
|
||||
addsaver(pconf.camera_angle, "camera angle", 0);
|
||||
addsaver(pconf.ballproj, "ballproj", 1);
|
||||
addsaver(vid.monmode, "monster display mode", DEFAULT_MONMODE);
|
||||
addsaver(vid.wallmode, "wall display mode", DEFAULT_WALLMODE);
|
||||
|
||||
@ -362,6 +362,20 @@ EX void initConfig() {
|
||||
addsaver(reserve_limit, "memory_reserve", 128);
|
||||
addsaver(show_memory_warning, "show_memory_warning");
|
||||
|
||||
auto& rconf = vid.rug_config;
|
||||
addsaverenum(rconf.model, "rug-projection", mdEquidistant);
|
||||
addsaver(rconf.scale, "rug-projection-scale", 1);
|
||||
addsaver(rconf.alpha, "rug-projection-alpha", 1);
|
||||
addsaver(rconf.clip_min, "rug-projection-clip-min", -100);
|
||||
addsaver(rconf.clip_max, "rug-projection-clip-max", +10);
|
||||
addsaver(rconf.stretch, "rug-projection-stretch", 1);
|
||||
addsaver(rconf.halfplane_scale, "rug-projection-halfplane scale", 1);
|
||||
addsaver(rconf.collignon_parameter, "rug-collignon-parameter", 1);
|
||||
addsaver(rconf.collignon_reflected, "rug-collignon-reflect", false);
|
||||
addsaver(rconf.euclid_to_sphere, "rug-euclid to sphere projection", 1.5);
|
||||
addsaver(rconf.twopoint_param, "rug-twopoint parameter", 1);
|
||||
addsaver(rconf.fisheye_param, "rug-fisheye parameter", 1);
|
||||
addsaver(rconf.model_transition, "rug-model transition", 1);
|
||||
addsaver(rug::renderonce, "rug-renderonce");
|
||||
addsaver(rug::rendernogl, "rug-rendernogl");
|
||||
addsaver(rug::texturesize, "rug-texturesize");
|
||||
@ -389,16 +403,16 @@ EX void initConfig() {
|
||||
addsaver(models::rotation_xz, "conformal rotation_xz");
|
||||
addsaver(models::rotation_xy2, "conformal rotation_2");
|
||||
addsaver(models::do_rotate, "conformal rotation mode", 1);
|
||||
addsaver(models::model_orientation, "model orientation", 0);
|
||||
addsaver(models::model_orientation_yz, "model orientation-yz", 0);
|
||||
addsaver(models::top_z, "topz", 5);
|
||||
addsaver(models::model_transition, "model transition", 1);
|
||||
addsaver(models::halfplane_scale, "halfplane scale", 1);
|
||||
addsaver(pconf.model_orientation, "model orientation", 0);
|
||||
addsaver(pconf.model_orientation_yz, "model orientation-yz", 0);
|
||||
addsaver(pconf.top_z, "topz", 5);
|
||||
addsaver(pconf.model_transition, "model transition", 1);
|
||||
addsaver(pconf.halfplane_scale, "halfplane scale", 1);
|
||||
addsaver(history::autoband, "automatic band");
|
||||
addsaver(history::autobandhistory, "automatic band history");
|
||||
addsaver(history::dospiral, "do spiral");
|
||||
addsaver(models::clip_min, "clip-min", -1);
|
||||
addsaver(models::clip_max, "clip-max", +1);
|
||||
addsaver(pconf.clip_min, "clip-min", -1);
|
||||
addsaver(pconf.clip_max, "clip-max", +1);
|
||||
|
||||
addsaver(vid.backeffects, "background particle effects", (ISMOBILE || ISPANDORA) ? false : true);
|
||||
// control
|
||||
@ -468,13 +482,13 @@ EX void initConfig() {
|
||||
addsaver(vid.fov, "field-of-vision", 90);
|
||||
addsaver(vid.desaturate, "desaturate", 0);
|
||||
addsaverenum(vid.stereo_mode, "stereo-mode");
|
||||
addsaver(vid.euclid_to_sphere, "euclid to sphere projection", 1.5);
|
||||
addsaver(vid.twopoint_param, "twopoint parameter", 1);
|
||||
addsaver(vid.fisheye_param, "fisheye parameter", 1);
|
||||
addsaver(vid.stretch, "stretch", 1);
|
||||
addsaver(pconf.euclid_to_sphere, "euclid to sphere projection", 1.5);
|
||||
addsaver(pconf.twopoint_param, "twopoint parameter", 1);
|
||||
addsaver(pconf.fisheye_param, "fisheye parameter", 1);
|
||||
addsaver(pconf.stretch, "stretch", 1);
|
||||
addsaver(vid.binary_width, "binary-tiling-width", 1);
|
||||
addsaver(vid.collignon_parameter, "collignon-parameter", 1);
|
||||
addsaver(vid.collignon_reflected, "collignon-reflect", false);
|
||||
addsaver(pconf.collignon_parameter, "collignon-parameter", 1);
|
||||
addsaver(pconf.collignon_reflected, "collignon-reflect", false);
|
||||
|
||||
addsaver(vid.plevel_factor, "plevel_factor", 0.7);
|
||||
|
||||
@ -521,7 +535,7 @@ EX void initConfig() {
|
||||
#if CAP_SHOT
|
||||
addsaver(shot::shotx, "shotx");
|
||||
addsaver(shot::shoty, "shoty");
|
||||
addsaver(shot::make_svg, "shotsvg");
|
||||
addsaverenum(shot::format, "shotsvg");
|
||||
addsaver(shot::transparent, "shottransparent");
|
||||
addsaver(shot::gamma, "shotgamma");
|
||||
addsaver(shot::caption, "shotcaption");
|
||||
@ -545,11 +559,11 @@ EX void initConfig() {
|
||||
addsaver(slr::steps, "slr-steps");
|
||||
addsaver(slr::range_xy, "slr-range-xy");
|
||||
|
||||
addsaver(vid.skiprope, "mobius", 0);
|
||||
addsaver(pconf.skiprope, "mobius", 0);
|
||||
|
||||
addsaver(models::formula, "formula");
|
||||
addsaverenum(models::basic_model, "basic model");
|
||||
addsaver(models::use_atan, "use_atan");
|
||||
addsaver(pconf.formula, "formula");
|
||||
addsaverenum(pconf.basic_model, "basic model");
|
||||
addsaver(pconf.use_atan, "use_atan");
|
||||
|
||||
addsaver(arcm::current.symbol, "arcm-symbol", "4^5");
|
||||
addsaverenum(hybrid::underlying, "product-underlying");
|
||||
@ -670,7 +684,7 @@ EX bool inSpecialMode() {
|
||||
tour::on ||
|
||||
#endif
|
||||
yendor::on || tactic::on || randomPatternsMode ||
|
||||
geometry != gNormal || pmodel != mdDisk || vid.alpha != 1 || vid.scale != 1 ||
|
||||
geometry != gNormal || pmodel != mdDisk || pconf.alpha != 1 || pconf.scale != 1 ||
|
||||
rug::rugged || vid.monmode != DEFAULT_MONMODE ||
|
||||
vid.wallmode != DEFAULT_WALLMODE;
|
||||
}
|
||||
@ -697,7 +711,7 @@ EX bool have_current_settings() {
|
||||
}
|
||||
|
||||
EX bool have_current_graph_settings() {
|
||||
if(vid.xposition || vid.yposition || vid.alpha != 1 || vid.scale != 1)
|
||||
if(pconf.xposition || pconf.yposition || pconf.alpha != 1 || pconf.scale != 1)
|
||||
return true;
|
||||
if(pmodel != mdDisk || vid.monmode != DEFAULT_MONMODE || vid.wallmode != DEFAULT_WALLMODE)
|
||||
return true;
|
||||
@ -708,8 +722,8 @@ EX bool have_current_graph_settings() {
|
||||
}
|
||||
|
||||
EX void reset_graph_settings() {
|
||||
pmodel = mdDisk; vid.alpha = 1; vid.scale = 1;
|
||||
vid.xposition = vid.yposition = 0;
|
||||
pmodel = mdDisk; pconf.alpha = 1; pconf.scale = 1;
|
||||
pconf.xposition = pconf.yposition = 0;
|
||||
#if CAP_RUG
|
||||
if(rug::rugged) rug::close();
|
||||
#endif
|
||||
@ -893,6 +907,7 @@ string solhelp() {
|
||||
}
|
||||
|
||||
EX void edit_sightrange() {
|
||||
USING_NATIVE_GEOMETRY_IN_RUG;
|
||||
if(vid.use_smart_range) {
|
||||
ld& det = WDIM == 2 ? vid.smart_range_detail : vid.smart_range_detail_3;
|
||||
dialog::editNumber(det, 1, 50, 1, WDIM == 2 ? 8 : 30, XLAT("minimum visible cell in pixels"), "");
|
||||
@ -1431,7 +1446,7 @@ EX void showJoyConfig() {
|
||||
|
||||
EX void projectionDialog() {
|
||||
vid.tc_alpha = ticks;
|
||||
dialog::editNumber(vid.alpha, -5, 5, .1, 1,
|
||||
dialog::editNumber(vpconf.alpha, -5, 5, .1, 1,
|
||||
XLAT("projection"),
|
||||
XLAT("HyperRogue uses the Minkowski hyperboloid model internally. "
|
||||
"Klein and Poincaré models can be obtained by perspective, "
|
||||
@ -1449,17 +1464,17 @@ EX void projectionDialog() {
|
||||
"tanh(g)/tanh(c) units below the center. This in turn corresponds to "
|
||||
"the Poincaré model for g=c, and Klein-Beltrami model for g=0."));
|
||||
dialog::addSelItem(sphere ? "stereographic" : "Poincaré model", "1", 'P');
|
||||
dialog::add_action([] () { *dialog::ne.editwhat = 1; vid.scale = 1; dialog::ne.s = "1"; });
|
||||
dialog::add_action([] () { *dialog::ne.editwhat = 1; vpconf.scale = 1; dialog::ne.s = "1"; });
|
||||
dialog::addSelItem(sphere ? "gnomonic" : "Klein model", "0", 'K');
|
||||
dialog::add_action([] () { *dialog::ne.editwhat = 0; vid.scale = 1; dialog::ne.s = "0"; });
|
||||
dialog::add_action([] () { *dialog::ne.editwhat = 0; vpconf.scale = 1; dialog::ne.s = "0"; });
|
||||
if(hyperbolic) {
|
||||
dialog::addSelItem("inverted Poincaré model", "-1", 'I');
|
||||
dialog::add_action([] () { *dialog::ne.editwhat = -1; vid.scale = 1; dialog::ne.s = "-1"; });
|
||||
dialog::add_action([] () { *dialog::ne.editwhat = -1; vpconf.scale = 1; dialog::ne.s = "-1"; });
|
||||
}
|
||||
dialog::addItem(sphere ? "orthographic" : "Gans model", 'O');
|
||||
dialog::add_action([] () { vid.alpha = vid.scale = 999; dialog::ne.s = dialog::disp(vid.alpha); });
|
||||
dialog::add_action([] () { vpconf.alpha = vpconf.scale = 999; dialog::ne.s = dialog::disp(vpconf.alpha); });
|
||||
dialog::addItem(sphere ? "towards orthographic" : "towards Gans model", 'T');
|
||||
dialog::add_action([] () { double d = 1.1; vid.alpha *= d; vid.scale *= d; dialog::ne.s = dialog::disp(vid.alpha); });
|
||||
dialog::add_action([] () { double d = 1.1; vpconf.alpha *= d; vpconf.scale *= d; dialog::ne.s = dialog::disp(vpconf.alpha); });
|
||||
};
|
||||
}
|
||||
|
||||
@ -1564,7 +1579,7 @@ EX void showStereo() {
|
||||
}
|
||||
|
||||
EX void config_camera_rotation() {
|
||||
dialog::editNumber(vid.ballangle, 0, 90, 5, 0, XLAT("camera rotation in 3D models"),
|
||||
dialog::editNumber(pconf.ballangle, 0, 90, 5, 0, XLAT("camera rotation in 3D models"),
|
||||
"Rotate the camera in 3D models (ball model, hyperboloid, and hemisphere). "
|
||||
"Note that hyperboloid and hemisphere models are also available in the "
|
||||
"Hypersian Rug surfaces menu, but they are rendered differently there -- "
|
||||
@ -1648,9 +1663,9 @@ EX void show3D() {
|
||||
|
||||
|
||||
if(GDIM == 2)
|
||||
dialog::addSelItem(XLAT("Projection at the ground level"), fts(vid.alpha), 'p');
|
||||
dialog::addSelItem(XLAT("Projection at the ground level"), fts(pconf.alpha), 'p');
|
||||
else if(!in_perspective())
|
||||
dialog::addSelItem(XLAT("Projection distance"), fts(vid.alpha), 'p');
|
||||
dialog::addSelItem(XLAT("Projection distance"), fts(pconf.alpha), 'p');
|
||||
|
||||
dialog::addBreak(50);
|
||||
dialog::addSelItem(XLAT("Height of walls"), fts(vid.wall_height), 'w');
|
||||
@ -1676,7 +1691,7 @@ EX void show3D() {
|
||||
dialog::editNumber(mouseaim_sensitivity, -1, 1, 0.002, 0.01, XLAT("mouse aiming sensitivity"), "set to 0 to disable");
|
||||
});
|
||||
}
|
||||
dialog::addSelItem(XLAT("camera rotation"), fts(vid.camera_angle), 's');
|
||||
dialog::addSelItem(XLAT("camera rotation"), fts(vpconf.camera_angle), 's');
|
||||
if(GDIM == 2) {
|
||||
dialog::addSelItem(XLAT("fixed facing"), vid.fixed_facing ? fts(vid.fixed_facing_dir) : XLAT("OFF"), 'f');
|
||||
dialog::add_action([] () { vid.fixed_facing = !vid.fixed_facing;
|
||||
@ -1730,7 +1745,7 @@ EX void show3D() {
|
||||
}
|
||||
#endif
|
||||
if(GDIM == 2) {
|
||||
dialog::addBoolItem(XLAT("configure TPP automatically"), pmodel == mdDisk && vid.camera_angle, 'T');
|
||||
dialog::addBoolItem(XLAT("configure TPP automatically"), pmodel == mdDisk && pconf.camera_angle, 'T');
|
||||
dialog::add_action(geom3::switch_tpp);
|
||||
}
|
||||
|
||||
@ -1902,7 +1917,7 @@ EX void show3D() {
|
||||
};
|
||||
}
|
||||
else if(uni == 's')
|
||||
dialog::editNumber(vid.camera_angle, -180, 180, 5, 0, XLAT("camera rotation"),
|
||||
dialog::editNumber(vpconf.camera_angle, -180, 180, 5, 0, XLAT("camera rotation"),
|
||||
XLAT("Rotate the camera. Can be used to obtain a first person perspective, "
|
||||
"or third person perspective when combined with Y shift.")
|
||||
);
|
||||
@ -1959,11 +1974,7 @@ EX void showCustomizeChar() {
|
||||
int firsty = dialog::items[0].position / 2;
|
||||
int scale = firsty - 2 * vid.fsize;
|
||||
|
||||
dynamicval<eModel> pm(pmodel, flat_model());
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
dynamicval<ld> va(vid.alpha, 1);
|
||||
dynamicval<ld> vs(vid.scale, 1);
|
||||
dynamicval<ld> vc(vid.camera_angle, 0);
|
||||
flat_model_enabler fme;
|
||||
|
||||
initquickqueue();
|
||||
transmatrix V = atscreenpos(vid.xres/2, firsty, scale);
|
||||
@ -2465,7 +2476,7 @@ EX int read_config_args() {
|
||||
else if(argis("-yca")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(vid.yshift);
|
||||
shift_arg_formula(vid.camera_angle);
|
||||
shift_arg_formula(pconf.camera_angle);
|
||||
}
|
||||
else if(argis("-pside")) {
|
||||
PHASEFROM(2);
|
||||
@ -2473,8 +2484,8 @@ EX int read_config_args() {
|
||||
}
|
||||
else if(argis("-xy")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(vid.xposition);
|
||||
shift_arg_formula(vid.yposition);
|
||||
shift_arg_formula(pconf.xposition);
|
||||
shift_arg_formula(pconf.yposition);
|
||||
}
|
||||
else if(argis("-fixdir")) {
|
||||
PHASEFROM(2);
|
||||
@ -2534,6 +2545,10 @@ EX int read_config_args() {
|
||||
PHASEFROM(2);
|
||||
shift(); neon_mode = eNeon(argi());
|
||||
}
|
||||
else if(argis("-smooths")) {
|
||||
PHASEFROM(2);
|
||||
shift(); smooth_scrolling = argi();
|
||||
}
|
||||
else if(argis("-neonnf")) {
|
||||
PHASEFROM(2);
|
||||
shift(); neon_nofill = argi();
|
||||
@ -2578,15 +2593,15 @@ auto ah_config = addHook(hooks_args, 0, read_config_args) + addHook(hooks_args,
|
||||
EX unordered_map<string, ld&> params = {
|
||||
{"linewidth", vid.linewidth},
|
||||
{"patternlinewidth", linepatterns::width},
|
||||
{"scale", vid.scale},
|
||||
{"xposition", vid.xposition},
|
||||
{"yposition", vid.yposition},
|
||||
{"projection", vid.alpha},
|
||||
{"scale", pconf.scale},
|
||||
{"xposition", pconf.xposition},
|
||||
{"yposition", pconf.yposition},
|
||||
{"projection", pconf.alpha},
|
||||
{"sspeed", vid.sspeed},
|
||||
{"mspeed", vid.mspeed},
|
||||
{"ballangle", vid.ballangle},
|
||||
{"ballangle", pconf.ballangle},
|
||||
{"yshift", vid.yshift},
|
||||
{"cameraangle", vid.camera_angle},
|
||||
{"cameraangle", pconf.camera_angle},
|
||||
{"eye", vid.eye},
|
||||
{"depth", vid.depth},
|
||||
{"camera", vid.camera},
|
||||
@ -2603,22 +2618,22 @@ EX unordered_map<string, ld&> params = {
|
||||
{"star", polygonal::STAR},
|
||||
{"lvspeed", history::lvspeed},
|
||||
{"rotation", models::rotation},
|
||||
{"mori", models::model_orientation},
|
||||
{"mori_yz", models::model_orientation_yz},
|
||||
{"clipmin", models::clip_min},
|
||||
{"clipmax", models::clip_max},
|
||||
{"topz", models::top_z},
|
||||
{"mtrans", models::model_transition},
|
||||
{"hp", models::halfplane_scale},
|
||||
{"mori", pconf.model_orientation},
|
||||
{"mori_yz", pconf.model_orientation_yz},
|
||||
{"clipmin", pconf.clip_min},
|
||||
{"clipmax", pconf.clip_max},
|
||||
{"topz", pconf.top_z},
|
||||
{"mtrans", pconf.model_transition},
|
||||
{"hp", pconf.halfplane_scale},
|
||||
{"back", backbrightness},
|
||||
{"ipd", vid.ipd},
|
||||
{"lr", vid.lr_eyewidth},
|
||||
{"anaglyph", vid.anaglyph_eyewidth},
|
||||
{"fov", vid.fov},
|
||||
{"ets", vid.euclid_to_sphere},
|
||||
{"stretch", vid.stretch},
|
||||
{"twopoint", vid.twopoint_param},
|
||||
{"fisheye", vid.fisheye_param},
|
||||
{"ets", pconf.euclid_to_sphere},
|
||||
{"stretch", pconf.stretch},
|
||||
{"twopoint", pconf.twopoint_param},
|
||||
{"fisheye", pconf.fisheye_param},
|
||||
{"bwidth", vid.binary_width},
|
||||
#if CAP_ANIMATIONS
|
||||
{"aperiod", anims::period},
|
||||
@ -2630,10 +2645,10 @@ EX unordered_map<string, ld&> params = {
|
||||
{"a", anims::a},
|
||||
{"b", anims::b},
|
||||
#endif
|
||||
{"mobius", vid.skiprope},
|
||||
{"sang", models::spiral_angle},
|
||||
{"spiralx", models::spiral_x},
|
||||
{"spiraly", models::spiral_y},
|
||||
{"mobius", pconf.skiprope},
|
||||
{"sang", pconf.spiral_angle},
|
||||
{"spiralx", pconf.spiral_x},
|
||||
{"spiraly", pconf.spiral_y},
|
||||
#if CAP_CRYSTAL
|
||||
{"cprob", crystal::compass_probability},
|
||||
#endif
|
||||
@ -2642,7 +2657,7 @@ EX unordered_map<string, ld&> params = {
|
||||
{"fade", shot::fade},
|
||||
{"mgrid", vid.multiplier_grid},
|
||||
{"mring", vid.multiplier_ring},
|
||||
{"collignon", vid.collignon_parameter},
|
||||
{"collignon", pconf.collignon_parameter},
|
||||
{"levellines", levellines},
|
||||
#endif
|
||||
};
|
||||
|
128
control.cpp
128
control.cpp
@ -76,7 +76,7 @@ EX movedir vectodir(hyperpoint P) {
|
||||
transmatrix U = ggmatrix(cwt.at);
|
||||
if(GDIM == 3 && WDIM == 2) U = radar_transform * U;
|
||||
|
||||
P = direct_exp(lp_iapply(P), 100);
|
||||
P = direct_exp(lp_iapply(P));
|
||||
|
||||
hyperpoint H = sphereflip * tC0(U);
|
||||
transmatrix Centered = sphereflip * rgpushxto0(H);
|
||||
@ -87,8 +87,8 @@ EX movedir vectodir(hyperpoint P) {
|
||||
|
||||
for(int i=0; i<cwt.at->type; i++) {
|
||||
transmatrix T = currentmap->adj(cwt.at, (cwt + i).spin);
|
||||
ld d1 = geo_dist(U * T * C0, Centered * P, iTable);
|
||||
ld d2 = geo_dist(U * T * C0, Centered * C0, iTable);
|
||||
ld d1 = geo_dist(U * T * C0, Centered * P);
|
||||
ld d2 = geo_dist(U * T * C0, Centered * C0);
|
||||
dirdist[i] = d1 - d2;
|
||||
//xspinpush0(-i * 2 * M_PI /cwt.at->type, .5), P);
|
||||
}
|
||||
@ -308,9 +308,7 @@ EX void handlePanning(int sym, int uni) {
|
||||
if(sym == PSEUDOKEY_WHEELDOWN) shift_view(ztangent(0.05*shiftmul)), didsomething = true, playermoved = false;
|
||||
}
|
||||
|
||||
if(rug::rugged || smooth_scrolling) {
|
||||
return;
|
||||
}
|
||||
rug::using_rugview urv;
|
||||
|
||||
#if !ISPANDORA
|
||||
if(sym == SDLK_END && GDIM == 3) {
|
||||
@ -319,60 +317,62 @@ EX void handlePanning(int sym, int uni) {
|
||||
if(sym == SDLK_HOME && GDIM == 3) {
|
||||
shift_view(ztangent(+0.2*shiftmul)), didsomething = true, playermoved = false;
|
||||
}
|
||||
if(sym == SDLK_RIGHT) {
|
||||
|
||||
auto roll = [&] (int dir, ld val) {
|
||||
if(GDIM == 3 && anyshiftclick)
|
||||
shift_view(ctangent(dir, -val)), didsomething = true, playermoved = false; /* -val because shift reverses */
|
||||
#if CAP_CRYSTAL
|
||||
else if(rug::rug_control() && rug::in_crystal())
|
||||
crystal::apply_rotation(cspin(dir, 2, val));
|
||||
#endif
|
||||
else if(GDIM == 3)
|
||||
rotate_view(cspin(dir, 2, val)), didsomething = true;
|
||||
else
|
||||
View = cpush(dir, val) * View, playermoved = false, didsomething = true;
|
||||
};
|
||||
|
||||
if(sym == SDLK_RIGHT) {
|
||||
if(history::on)
|
||||
history::lvspeed += 0.1 * shiftmul;
|
||||
else if(GDIM == 3)
|
||||
rotate_view(cspin(0, 2, -0.2*shiftmul)), didsomething = true;
|
||||
else
|
||||
View = xpush(-0.2*shiftmul) * View, playermoved = false, didsomething = true;
|
||||
else roll(0, -0.2*shiftmul);
|
||||
}
|
||||
if(sym == SDLK_LEFT) {
|
||||
if(history::on)
|
||||
history::lvspeed -= 0.1 * shiftmul;
|
||||
else if(GDIM == 3)
|
||||
rotate_view(cspin(0, 2, 0.2*shiftmul)), didsomething = true;
|
||||
else
|
||||
View = xpush(+0.2*shiftmul) * View, playermoved = false, didsomething = true;
|
||||
else roll(0, 0.2*shiftmul);
|
||||
}
|
||||
if(sym == SDLK_UP) {
|
||||
if(history::on)
|
||||
history::lvspeed += 0.1 * shiftmul;
|
||||
else if(GDIM == 3)
|
||||
rotate_view(cspin(1, 2, 0.2*shiftmul)), didsomething = true;
|
||||
else
|
||||
View = ypush(+0.2*shiftmul) * View, playermoved = false, didsomething = true;
|
||||
else roll(1, 0.2*shiftmul);
|
||||
}
|
||||
if(sym == SDLK_DOWN) {
|
||||
if(history::on)
|
||||
history::lvspeed -= 0.1 * shiftmul;
|
||||
else if(GDIM == 3)
|
||||
rotate_view(cspin(1, 2, -0.2*shiftmul)), didsomething = true;
|
||||
else
|
||||
View = ypush(-0.2*shiftmul) * View, playermoved = false, didsomething = true;
|
||||
else roll(1, -0.2*shiftmul);
|
||||
}
|
||||
#endif
|
||||
if(sym == SDLK_PAGEUP) {
|
||||
if(history::on)
|
||||
if(history::on && !rug::rug_control())
|
||||
models::rotation++;
|
||||
else
|
||||
rotate_view(spin(M_PI/cgi.S21/2*shiftmul)), didsomething = true;
|
||||
}
|
||||
if(sym == SDLK_PAGEDOWN) {
|
||||
if(history::on)
|
||||
if(history::on && !rug::rug_control())
|
||||
models::rotation++;
|
||||
else
|
||||
rotate_view(spin(-M_PI/cgi.S21/2*shiftmul)), didsomething = true;
|
||||
}
|
||||
|
||||
if(sym == SDLK_PAGEUP || sym == SDLK_PAGEDOWN)
|
||||
if(isGravityLand(cwt.at->land)) playermoved = false;
|
||||
if(isGravityLand(cwt.at->land) && !rug::rug_control()) playermoved = false;
|
||||
|
||||
if(sym == PSEUDOKEY_WHEELUP && GDIM == 2) {
|
||||
ld jx = (mousex - current_display->xcenter - .0) / current_display->radius / 10;
|
||||
ld jy = (mousey - current_display->ycenter - .0) / current_display->radius / 10;
|
||||
playermoved = false;
|
||||
View = gpushxto0(hpxy(jx, jy)) * View;
|
||||
rotate_view(gpushxto0(hpxy(jx, jy)));
|
||||
sym = 1;
|
||||
}
|
||||
}
|
||||
@ -493,8 +493,12 @@ EX void handleKeyNormal(int sym, int uni) {
|
||||
pushScreen(inv::show);
|
||||
#endif
|
||||
|
||||
if(((sym == SDLK_HOME && GDIM == 2) || sym == SDLK_F3 || sym == ' ') && DEFAULTNOR(sym))
|
||||
fullcenter();
|
||||
if(((sym == SDLK_HOME && GDIM == 2 && !rug::rugged) || sym == SDLK_F3 || sym == ' ') && DEFAULTNOR(sym)) {
|
||||
if(rug::rug_control())
|
||||
rug::reset_view();
|
||||
else
|
||||
fullcenter();
|
||||
}
|
||||
|
||||
if(sym == 'v' && DEFAULTNOR(sym))
|
||||
pushScreen(showMainMenu);
|
||||
@ -696,7 +700,8 @@ EX void mainloopiter() {
|
||||
#endif
|
||||
}
|
||||
|
||||
if(smooth_scrolling && !shmup::on && !rug::rugged) {
|
||||
if(smooth_scrolling && !shmup::on) {
|
||||
rug::using_rugview urv;
|
||||
static int lastticks;
|
||||
ld t = (ticks - lastticks) * shiftmul / 1000.;
|
||||
lastticks = ticks;
|
||||
@ -705,14 +710,23 @@ EX void mainloopiter() {
|
||||
shift_view(ctangent(2, -t)), didsomething = true, playermoved = false;
|
||||
if(keystate[SDLK_HOME] && GDIM == 3 && DEFAULTNOR(SDLK_HOME))
|
||||
shift_view(ctangent(2, t)), didsomething = true, playermoved = false;
|
||||
if(keystate[SDLK_RIGHT] && DEFAULTNOR(SDLK_RIGHT))
|
||||
rotate_view(GDIM == 2 ? xpush(-t) : cspin(0, 2, -t)), didsomething = true, playermoved = playermoved && GDIM == 3;
|
||||
if(keystate[SDLK_LEFT] && DEFAULTNOR(SDLK_LEFT))
|
||||
rotate_view(GDIM == 2 ? xpush(t) : cspin(0, 2, t)), didsomething = true, playermoved = playermoved && GDIM == 3;
|
||||
if(keystate[SDLK_UP] && DEFAULTNOR(SDLK_UP))
|
||||
rotate_view(GDIM == 2 ? ypush(t) : cspin(1, 2, t)), didsomething = true, playermoved = playermoved && GDIM == 3;
|
||||
if(keystate[SDLK_DOWN] && DEFAULTNOR(SDLK_DOWN))
|
||||
rotate_view(GDIM == 2 ? ypush(-t) : cspin(1, 2, -t)), didsomething = true, playermoved = playermoved && GDIM == 3;
|
||||
|
||||
auto roll = [&] (int dir, ld val) {
|
||||
if(GDIM == 3 && anyshiftclick)
|
||||
shift_view(ctangent(dir, -val)); /* -val because shift reverses */
|
||||
#if CAP_CRYSTAL
|
||||
else if(rug::rug_control() && rug::in_crystal())
|
||||
crystal::apply_rotation(cspin(dir, 2, val));
|
||||
#endif
|
||||
else
|
||||
rotate_view(GDIM == 2 ? cpush(dir, val) : cspin(dir, 2, val));
|
||||
didsomething = true, playermoved = playermoved && GDIM == 3;
|
||||
};
|
||||
|
||||
if(keystate[SDLK_RIGHT] && DEFAULTNOR(SDLK_RIGHT)) roll(0, -t);
|
||||
if(keystate[SDLK_LEFT] && DEFAULTNOR(SDLK_LEFT)) roll(0, t);
|
||||
if(keystate[SDLK_UP] && DEFAULTNOR(SDLK_UP)) roll(1, t);
|
||||
if(keystate[SDLK_DOWN] && DEFAULTNOR(SDLK_DOWN)) roll(1, -t);
|
||||
if(keystate[SDLK_PAGEUP] && DEFAULTNOR(SDLK_PAGEUP)) {
|
||||
if(history::on)
|
||||
models::rotation+=t;
|
||||
@ -865,7 +879,7 @@ EX void handle_event(SDL_Event& ev) {
|
||||
else if(ev.button.button==SDL_BUTTON_MIDDLE || rightclick) {
|
||||
sym = 1, didsomething = true;
|
||||
if(anyshift)
|
||||
vid.xposition = vid.yposition = 0;
|
||||
pconf.xposition = pconf.yposition = 0;
|
||||
}
|
||||
else if(ev.button.button == SDL_BUTTON_LEFT) {
|
||||
sym = getcstat, uni = getcstat, shiftmul = getcshift;
|
||||
@ -874,12 +888,12 @@ EX void handle_event(SDL_Event& ev) {
|
||||
else if(ev.button.button==SDL_BUTTON_WHEELDOWN) {
|
||||
if(anyctrl && anyshift && !rug::rugged && GDIM == 2) {
|
||||
mapeditor::scaleall(1/1.2);
|
||||
vid.alpha /= 1.2;
|
||||
pconf.alpha /= 1.2;
|
||||
}
|
||||
else if(anyctrl && !rug::rugged && GDIM == 2)
|
||||
mapeditor::scaleall(pow(2, -.25));
|
||||
else if(anyshift && !rug::rugged && GDIM == 2)
|
||||
vid.alpha -= 0.25;
|
||||
pconf.alpha -= 0.25;
|
||||
else if(rollchange) {
|
||||
sym = getcstat, uni = getcstat, shiftmul = getcshift, wheelclick = true;
|
||||
}
|
||||
@ -890,12 +904,12 @@ EX void handle_event(SDL_Event& ev) {
|
||||
if(ev.button.button==SDL_BUTTON_WHEELUP) {
|
||||
if(anyctrl && anyshift && !rug::rugged && GDIM == 2) {
|
||||
mapeditor::scaleall(1.2);
|
||||
vid.alpha *= 1.2;
|
||||
pconf.alpha *= 1.2;
|
||||
}
|
||||
else if(anyctrl && !rug::rugged && GDIM == 2)
|
||||
mapeditor::scaleall(pow(2, .25));
|
||||
else if(anyshift && !rug::rugged && GDIM == 2)
|
||||
vid.alpha += 0.25;
|
||||
pconf.alpha += 0.25;
|
||||
else if(rollchange) {
|
||||
sym = getcstat, uni = getcstat, shiftmul = -getcshift, wheelclick = true;
|
||||
}
|
||||
@ -929,8 +943,8 @@ EX void handle_event(SDL_Event& ev) {
|
||||
if((rightclick || (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MMASK)) && !mouseout2()) {
|
||||
fix_mouseh();
|
||||
if(anyctrl) {
|
||||
vid.xposition += (mousex - lmousex) * 1. / current_display->scrsize,
|
||||
vid.yposition += (mousey - lmousey) * 1. / current_display->scrsize;
|
||||
pconf.xposition += (mousex - lmousex) * 1. / current_display->scrsize,
|
||||
pconf.yposition += (mousey - lmousey) * 1. / current_display->scrsize;
|
||||
}
|
||||
else if(mouseh[LDIM] < 50 && mouseoh[LDIM] < 50) {
|
||||
panning(mouseoh, mouseh);
|
||||
@ -1047,7 +1061,7 @@ EX bool gmodekeys(int sym, int uni) {
|
||||
|
||||
if(GDIM == 2) {
|
||||
if(among(NUMBERKEY, '1', '2', '3') && !rug::rugged && euclid && WDIM == 2) {
|
||||
vid.xposition = vid.yposition = 0;
|
||||
pconf.xposition = pconf.yposition = 0;
|
||||
ld maxs = 0;
|
||||
auto& cd = current_display;
|
||||
for(auto& p: gmatrix) for(int i=0; i<p.first->type; i++) {
|
||||
@ -1057,15 +1071,15 @@ EX bool gmodekeys(int sym, int uni) {
|
||||
maxs = max(maxs, onscreen[0] / cd->xsize);
|
||||
maxs = max(maxs, onscreen[1] / cd->ysize);
|
||||
}
|
||||
vid.alpha = 1;
|
||||
vid.scale = vid.scale / 2 / maxs / cd->radius;
|
||||
if(NUMBERKEY == '3') vid.scale *= 2;
|
||||
if(NUMBERKEY == '1') vid.scale /= 2;
|
||||
pconf.alpha = 1;
|
||||
pconf.scale = pconf.scale / 2 / maxs / cd->radius;
|
||||
if(NUMBERKEY == '3') pconf.scale *= 2;
|
||||
if(NUMBERKEY == '1') pconf.scale /= 2;
|
||||
}
|
||||
else if(NUMBERKEY == '1' && !rug::rugged) { vid.alpha = 999; vid.scale = 998; vid.xposition = vid.yposition = 0; }
|
||||
else if(NUMBERKEY == '2' && !rug::rugged) { vid.alpha = 1; vid.scale = 0.4; vid.xposition = vid.yposition = 0; }
|
||||
else if(NUMBERKEY == '3' && !rug::rugged) { vid.alpha = 1; vid.scale = 1; vid.xposition = vid.yposition = 0; }
|
||||
else if(NUMBERKEY == '4' && !rug::rugged) { vid.alpha = 0; vid.scale = 1; vid.xposition = vid.yposition = 0; }
|
||||
else if(NUMBERKEY == '1' && !rug::rugged) { pconf.alpha = 999; pconf.scale = 998; pconf.xposition = pconf.yposition = 0; }
|
||||
else if(NUMBERKEY == '2' && !rug::rugged) { pconf.alpha = 1; pconf.scale = 0.4; pconf.xposition = pconf.yposition = 0; }
|
||||
else if(NUMBERKEY == '3' && !rug::rugged) { pconf.alpha = 1; pconf.scale = 1; pconf.xposition = pconf.yposition = 0; }
|
||||
else if(NUMBERKEY == '4' && !rug::rugged) { pconf.alpha = 0; pconf.scale = 1; pconf.xposition = pconf.yposition = 0; }
|
||||
else if(NUMBERKEY == '5') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 7; }
|
||||
else if(NUMBERKEY == '8') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; }
|
||||
else if(uni == '%') {
|
||||
@ -1183,10 +1197,10 @@ EX void show() {
|
||||
dialog::addItem(XLAT("experiment with geometry"), 'g');
|
||||
dialog::add_action([] () { runGeometryExperiments(); });
|
||||
|
||||
dialog::addSelItem(XLAT("projection"), fts(vid.alpha), 'p');
|
||||
dialog::addSelItem(XLAT("projection"), fts(vpconf.alpha), 'p');
|
||||
dialog::add_action([] () { projectionDialog(); });
|
||||
|
||||
dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z');
|
||||
dialog::addSelItem(XLAT("scale factor"), fts(vpconf.scale), 'z');
|
||||
dialog::add_action([] () { editScale(); });
|
||||
|
||||
dialog::addItem(XLAT("spherical VR"), 'v');
|
||||
@ -1195,7 +1209,7 @@ EX void show() {
|
||||
mode = 0; fullcenter();
|
||||
mode = 2; sensitivity = 1;
|
||||
vid.stereo_mode = sLR; vid.ipd = 0.2;
|
||||
vid.alpha = 0; vid.scale = 1;
|
||||
vpconf.alpha = 0; vpconf.scale = 1;
|
||||
});
|
||||
|
||||
dialog::addBreak(100);
|
||||
|
@ -1230,8 +1230,8 @@ void cut_triangle2(const hyperpoint pa, const hyperpoint pb, const hyperpoint pc
|
||||
|
||||
rug::rugpoint *rac = rug::addRugpoint(hac, 0);
|
||||
rug::rugpoint *rbc = rug::addRugpoint(hbc, 0);
|
||||
rac->flat = pac;
|
||||
rbc->flat = pbc;
|
||||
rac->native = pac;
|
||||
rbc->native = pbc;
|
||||
rac->valid = true;
|
||||
rbc->valid = true;
|
||||
rug::triangles.push_back(rug::triangle(rac, rbc, NULL));
|
||||
@ -1270,7 +1270,7 @@ EX void build_rugdata() {
|
||||
|
||||
if(!draw_cut) {
|
||||
rugpoint *v = addRugpoint(tC0(V), 0);
|
||||
v->flat = coord_to_flat(co);
|
||||
v->native = coord_to_flat(co);
|
||||
v->valid = true;
|
||||
|
||||
rugpoint *p[MAX_EDGE_CRYSTAL];
|
||||
@ -1278,7 +1278,7 @@ EX void build_rugdata() {
|
||||
for(int i=0; i<c->type; i++) {
|
||||
p[i] = addRugpoint(V * get_corner_position(c, i), 0);
|
||||
p[i]->valid = true;
|
||||
p[i]->flat = coord_to_flat(vcoord[i]);
|
||||
p[i]->native = coord_to_flat(vcoord[i]);
|
||||
}
|
||||
|
||||
for(int i=0; i<c->type; i++) addTriangle(v, p[i], p[(i+1) % c->type]);
|
||||
|
@ -6,6 +6,20 @@ namespace hr {
|
||||
|
||||
namespace tests {
|
||||
|
||||
string test_eq(hyperpoint h1, hyperpoint h2, ld err = 1e-6) {
|
||||
if(sqhypot_d(MDIM, h1 -h2) < err)
|
||||
return "OK";
|
||||
else
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
string test_eq(transmatrix T1, transmatrix T2, ld err = 1e-6) {
|
||||
if(eqmatrix(T1, T2, err))
|
||||
return "OK";
|
||||
else
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
@ -58,16 +72,30 @@ int readArgs() {
|
||||
int cx = (co + 1) % WDIM;
|
||||
int cy = (co + 2) % WDIM;
|
||||
auto oxy = [&] (ld x, ld y, ld z) { hyperpoint h = Hypc; h[co] = z; h[cx] = x; if(WDIM == 3) h[cy] = y; return tC0(bt::normalized_at(h)); };
|
||||
ld shrunk_x = geo_dist(oxy(0,0,-1), oxy(.01,0,-1), iTable);
|
||||
ld shrunk_y = geo_dist(oxy(0,0,-1), oxy(0,.01,-1), iTable);
|
||||
ld expand_x = geo_dist(oxy(0,0,+1), oxy(.01,0,+1), iTable);
|
||||
ld expand_y = geo_dist(oxy(0,0,+1), oxy(0,.01,+1), iTable);
|
||||
ld shrunk_x = geo_dist(oxy(0,0,-1), oxy(.01,0,-1));
|
||||
ld shrunk_y = geo_dist(oxy(0,0,-1), oxy(0,.01,-1));
|
||||
ld expand_x = geo_dist(oxy(0,0,+1), oxy(.01,0,+1));
|
||||
ld expand_y = geo_dist(oxy(0,0,+1), oxy(0,.01,+1));
|
||||
if(WDIM == 2) shrunk_y = expand_y = 1;
|
||||
println(hlog, "should be 1: ", lalign(10, (shrunk_x * shrunk_y * bt::area_expansion_rate()) / (expand_x * expand_y)), " : ", tie(shrunk_x, shrunk_y, expand_x, expand_y, aer));
|
||||
if(geometry == gArnoldCat)
|
||||
println(hlog, "(but not in Arnold's cat)");
|
||||
}
|
||||
}
|
||||
else if(argis("-test-push")) {
|
||||
PHASEFROM(3);
|
||||
for(eGeometry g: {gSol, gNil, gCubeTiling, gSpace534, gCell120}) {
|
||||
stop_game();
|
||||
set_geometry(g);
|
||||
println(hlog, "testing geometry: ", geometry_name());
|
||||
hyperpoint h = hyperpoint(.1, .2, .3, 1);
|
||||
h = normalize(h);
|
||||
println(hlog, "h = ", h);
|
||||
println(hlog, "test rgpushxto0: ", test_eq(rgpushxto0(h) * C0, h));
|
||||
println(hlog, "test gpushxto0: ", test_eq(gpushxto0(h) * h, C0));
|
||||
println(hlog, "test inverses: ", test_eq(inverse(rgpushxto0(h)), gpushxto0(h)));
|
||||
}
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1263,6 +1263,10 @@ EX namespace dialog {
|
||||
else act();
|
||||
}
|
||||
|
||||
inline void push_confirm_dialog(const reaction_t& act, const string& s) {
|
||||
pushScreen([act, s] () { confirm_dialog(s, act); });
|
||||
}
|
||||
|
||||
inline reaction_t add_confirmation(const reaction_t& act) {
|
||||
return [act] { do_if_confirmed(act); };
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ void launch(int seed, int elimit, int hlimit) {
|
||||
dual::switch_to(0);
|
||||
specialland = firstland = laCanvas;
|
||||
canvas_default_wall = waSea;
|
||||
vid.scale = .5;
|
||||
pconf.scale = .5;
|
||||
dual::switch_to(1);
|
||||
specialland = firstland = laCanvas;
|
||||
shrand(seed);
|
||||
|
114
drawing.cpp
114
drawing.cpp
@ -34,6 +34,9 @@ static const int POLY_ALWAYS_IN = (1<<21); // always draw this
|
||||
static const int POLY_TRIANGLES = (1<<22); // made of TRIANGLES, not TRIANGLE_FAN
|
||||
static const int POLY_INTENSE = (1<<23); // extra intense colors
|
||||
static const int POLY_DEBUG = (1<<24); // debug this shape
|
||||
static const int POLY_PRINTABLE = (1<<25); // these walls are printable
|
||||
static const int POLY_FAT = (1<<26); // fatten this model in WRL export (used for Rug)
|
||||
static const int POLY_SHADE_TEXTURE = (1<<27); // texture has 'z' coordinate for shading
|
||||
|
||||
/** \brief A graphical element that can be drawn. Objects are not drawn immediately but rather queued.
|
||||
*
|
||||
@ -181,6 +184,7 @@ vector<glvertex> line_vertices;
|
||||
#endif
|
||||
|
||||
EX void glflush() {
|
||||
DEBBI(DF_GRAPH, ("glflush"));
|
||||
#if MINIMIZE_GL_CALLS
|
||||
if(isize(triangle_vertices)) {
|
||||
// printf("%08X %08X | %d shapes, %d/%d vertices\n", triangle_color, line_color, shapes_merged, isize(triangle_vertices), isize(line_vertices));
|
||||
@ -262,13 +266,13 @@ void add1(const hyperpoint& H) {
|
||||
}
|
||||
|
||||
bool is_behind(const hyperpoint& H) {
|
||||
return pmodel == mdDisk && (hyperbolic ? H[2] >= 0 : true) && (nonisotropic ? false : vid.alpha + H[2] <= BEHIND_LIMIT);
|
||||
return pmodel == mdDisk && (hyperbolic ? H[2] >= 0 : true) && (nonisotropic ? false : pconf.alpha + H[2] <= BEHIND_LIMIT);
|
||||
}
|
||||
|
||||
hyperpoint be_just_on_view(const hyperpoint& H1, const hyperpoint &H2) {
|
||||
// H1[2] * t + H2[2] * (1-t) == BEHIND_LIMIT - vid.alpha
|
||||
// H2[2]- BEHIND_LIMIT + vid.alpha = t * (H2[2] - H1[2])
|
||||
ld t = (H2[2] - BEHIND_LIMIT + vid.alpha) / (H2[2] - H1[2]);
|
||||
// H1[2] * t + H2[2] * (1-t) == BEHIND_LIMIT - pconf.alpha
|
||||
// H2[2]- BEHIND_LIMIT + pconf.alpha = t * (H2[2] - H1[2])
|
||||
ld t = (H2[2] - BEHIND_LIMIT + pconf.alpha) / (H2[2] - H1[2]);
|
||||
return H1 * t + H2 * (1-t);
|
||||
}
|
||||
|
||||
@ -289,14 +293,14 @@ EX bool two_sided_model() {
|
||||
if(pmodel == mdDisk) return sphere;
|
||||
if(pmodel == mdHemisphere) return true;
|
||||
if(pmodel == mdRotatedHyperboles) return true;
|
||||
if(pmodel == mdSpiral && models::spiral_cone < 360) return true;
|
||||
if(pmodel == mdSpiral && pconf.spiral_cone < 360) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
EX int get_side(const hyperpoint& H) {
|
||||
if(pmodel == mdDisk && sphere) {
|
||||
double curnorm = H[0]*H[0]+H[1]*H[1]+H[2]*H[2];
|
||||
double horizon = curnorm / vid.alpha;
|
||||
double horizon = curnorm / pconf.alpha;
|
||||
return (H[2] <= -horizon) ? -1 : 1;
|
||||
}
|
||||
if(pmodel == mdRotatedHyperboles)
|
||||
@ -310,7 +314,7 @@ EX int get_side(const hyperpoint& H) {
|
||||
applymodel(H, res);
|
||||
return res[2] < 0 ? -1 : 1;
|
||||
}
|
||||
if(pmodel == mdSpiral && models::spiral_cone < 360) {
|
||||
if(pmodel == mdSpiral && pconf.spiral_cone < 360) {
|
||||
return cone_side(H);
|
||||
}
|
||||
return 0;
|
||||
@ -334,13 +338,13 @@ void fixpoint(glvertex& hscr, hyperpoint H) {
|
||||
}
|
||||
hyperpoint Hscr;
|
||||
applymodel(good, Hscr);
|
||||
hscr = glhr::makevertex(Hscr[0]*current_display->radius, Hscr[1]*current_display->radius*vid.stretch, Hscr[2]*current_display->radius);
|
||||
hscr = glhr::makevertex(Hscr[0]*current_display->radius, Hscr[1]*current_display->radius*pconf.stretch, Hscr[2]*current_display->radius);
|
||||
}
|
||||
|
||||
void addpoint(const hyperpoint& H) {
|
||||
if(true) {
|
||||
ld z = current_display->radius;
|
||||
// if(vid.alpha + H[2] <= BEHIND_LIMIT && pmodel == mdDisk) poly_flags |= POLY_BEHIND;
|
||||
// if(pconf.alpha + H[2] <= BEHIND_LIMIT && pmodel == mdDisk) poly_flags |= POLY_BEHIND;
|
||||
|
||||
if(spherespecial) {
|
||||
|
||||
@ -350,7 +354,7 @@ void addpoint(const hyperpoint& H) {
|
||||
}
|
||||
else if(sphere && (poly_flags & POLY_ISSIDE)) {
|
||||
double curnorm = H[0]*H[0]+H[1]*H[1]+H[2]*H[2];
|
||||
double horizon = curnorm / vid.alpha;
|
||||
double horizon = curnorm / pconf.alpha;
|
||||
poly_flags |= POLY_NOTINFRONT;
|
||||
if(last_infront && nif_error_in(glcoords.back()[0], glcoords.back()[1], H[0], H[1]))
|
||||
poly_flags |= POLY_NIF_ERROR;
|
||||
@ -358,8 +362,8 @@ void addpoint(const hyperpoint& H) {
|
||||
last_infront = true;
|
||||
|
||||
z *=
|
||||
(sqrt(curnorm - horizon*horizon) / (vid.alpha - horizon)) /
|
||||
(sqrt(curnorm - H[2]*H[2]) / (vid.alpha+H[2]));
|
||||
(sqrt(curnorm - horizon*horizon) / (pconf.alpha - horizon)) /
|
||||
(sqrt(curnorm - H[2]*H[2]) / (pconf.alpha+H[2]));
|
||||
}
|
||||
else {
|
||||
poly_flags |= POLY_NOTINFRONT;
|
||||
@ -385,12 +389,12 @@ void addpoint(const hyperpoint& H) {
|
||||
}
|
||||
if(GDIM == 2) {
|
||||
for(int i=0; i<3; i++) Hscr[i] *= z;
|
||||
Hscr[1] *= vid.stretch;
|
||||
Hscr[1] *= pconf.stretch;
|
||||
}
|
||||
else {
|
||||
Hscr[0] *= z;
|
||||
Hscr[1] *= z * vid.stretch;
|
||||
Hscr[2] = 1 - 2 * (-Hscr[2] - models::clip_min) / (models::clip_max - models::clip_min);
|
||||
Hscr[1] *= z * pconf.stretch;
|
||||
Hscr[2] = 1 - 2 * (-Hscr[2] - pconf.clip_min) / (pconf.clip_max - pconf.clip_min);
|
||||
}
|
||||
add1(Hscr);
|
||||
}
|
||||
@ -409,7 +413,7 @@ void coords_to_poly() {
|
||||
|
||||
bool behind3(hyperpoint h) {
|
||||
if(pmodel == mdGeodesic)
|
||||
h = lp_apply(inverse_exp(h, iTable));
|
||||
h = lp_apply(inverse_exp(h));
|
||||
return h[2] < 0;
|
||||
}
|
||||
|
||||
@ -482,11 +486,11 @@ void addpoly(const transmatrix& V, const vector<glvertex> &tab, int ofs, int cnt
|
||||
/*
|
||||
hyperpoint Hscr;
|
||||
applymodel(goodpoint, Hscr);
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius+10, Hscr[1]*current_display->radius*vid.stretch, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius, Hscr[1]*current_display->radius*vid.stretch+10, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius-10, Hscr[1]*current_display->radius*vid.stretch, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius, Hscr[1]*current_display->radius*vid.stretch-10, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius+10, Hscr[1]*current_display->radius*vid.stretch, Hscr[2]*vid.radius)); */
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius+10, Hscr[1]*current_display->radius*pconf.stretch, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius, Hscr[1]*current_display->radius*pconf.stretch+10, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius-10, Hscr[1]*current_display->radius*pconf.stretch, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius, Hscr[1]*current_display->radius*pconf.stretch-10, Hscr[2]*vid.radius));
|
||||
glcoords.push_back(make_array<GLfloat>(Hscr[0]*current_display->radius+10, Hscr[1]*current_display->radius*pconf.stretch, Hscr[2]*vid.radius)); */
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,6 +598,7 @@ void dqi_poly::gldraw() {
|
||||
|
||||
if(tinf) {
|
||||
glhr::be_textured();
|
||||
if(flags & POLY_SHADE_TEXTURE) current_display->next_shader_flags |= GF_TEXTURE_SHADED;
|
||||
glBindTexture(GL_TEXTURE_2D, tinf->texture_id);
|
||||
glhr::vertices_texture(v, tinf->tvertices, offset, offset_texture);
|
||||
ioffset = 0;
|
||||
@ -715,7 +720,7 @@ EX ld scale_at(const transmatrix& T) {
|
||||
|
||||
EX ld linewidthat(const hyperpoint& h) {
|
||||
if(!(vid.antialias & AA_LINEWIDTH)) return 1;
|
||||
else if(hyperbolic && pmodel == mdDisk && vid.alpha == 1 && !ISWEB) {
|
||||
else if(hyperbolic && pmodel == mdDisk && pconf.alpha == 1 && !ISWEB) {
|
||||
double dz = h[LDIM];
|
||||
if(dz < 1) return 1;
|
||||
else {
|
||||
@ -750,7 +755,7 @@ vector<ld> periods;
|
||||
ld period_at(ld y) {
|
||||
|
||||
ld m = current_display->radius;
|
||||
y /= (m * vid.stretch);
|
||||
y /= (m * pconf.stretch);
|
||||
|
||||
switch(pmodel) {
|
||||
case mdBand:
|
||||
@ -760,8 +765,8 @@ ld period_at(ld y) {
|
||||
case mdMollweide:
|
||||
return m * 2 * sqrt(1 - y*y*4);
|
||||
case mdCollignon: {
|
||||
if(vid.collignon_reflected && y > 0) y = -y;
|
||||
y += signed_sqrt(vid.collignon_parameter);
|
||||
if(pconf.collignon_reflected && y > 0) y = -y;
|
||||
y += signed_sqrt(pconf.collignon_parameter);
|
||||
return abs(m*y*2/1.2);
|
||||
}
|
||||
default:
|
||||
@ -785,7 +790,7 @@ void adjust(bool tinf) {
|
||||
|
||||
ld cmin = -chypot/2, cmax = chypot/2, dmin = -chypot, dmax = chypot;
|
||||
|
||||
ld z = vid.stretch * current_display->radius;
|
||||
ld z = pconf.stretch * current_display->radius;
|
||||
|
||||
switch(pmodel) {
|
||||
case mdSinusoidal: case mdBandEquidistant: case mdMollweide:
|
||||
@ -797,9 +802,9 @@ void adjust(bool tinf) {
|
||||
break;
|
||||
|
||||
case mdCollignon:
|
||||
dmin = z * (signed_sqrt(vid.collignon_parameter - 1) - signed_sqrt(vid.collignon_parameter));
|
||||
if(vid.collignon_reflected) dmax = -dmin;
|
||||
else dmax = z * (signed_sqrt(vid.collignon_parameter + 1) - signed_sqrt(vid.collignon_parameter));
|
||||
dmin = z * (signed_sqrt(pconf.collignon_parameter - 1) - signed_sqrt(pconf.collignon_parameter));
|
||||
if(pconf.collignon_reflected) dmax = -dmin;
|
||||
else dmax = z * (signed_sqrt(pconf.collignon_parameter + 1) - signed_sqrt(pconf.collignon_parameter));
|
||||
break;
|
||||
|
||||
default: ;
|
||||
@ -889,7 +894,7 @@ void compute_side_by_centerin(dqi_poly *p, bool& nofill) {
|
||||
else
|
||||
nofill = true;
|
||||
}
|
||||
applymodel(h1, hscr); hscr[0] *= current_display->radius; hscr[1] *= current_display->radius * vid.stretch;
|
||||
applymodel(h1, hscr); hscr[0] *= current_display->radius; hscr[1] *= current_display->radius * pconf.stretch;
|
||||
for(int i=0; i<isize(glcoords)-1; i++) {
|
||||
double x1 = glcoords[i][0] - hscr[0];
|
||||
double y1 = glcoords[i][1] - hscr[1];
|
||||
@ -914,11 +919,11 @@ void compute_side_by_centerin(dqi_poly *p, bool& nofill) {
|
||||
|
||||
/*
|
||||
if(poly_flags & POLY_BADCENTERIN) {
|
||||
glcoords.push_back(glhr::makevertex(hscr[0]+10, hscr[1]*vid.stretch, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0], hscr[1]*vid.stretch+10, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0]-10, hscr[1]*vid.stretch, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0], hscr[1]*vid.stretch-10, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0]+10, hscr[1]*vid.stretch, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0]+10, hscr[1]*pconf.stretch, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0], hscr[1]*pconf.stretch+10, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0]-10, hscr[1]*pconf.stretch, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0], hscr[1]*pconf.stretch-10, hscr[2]));
|
||||
glcoords.push_back(glhr::makevertex(hscr[0]+10, hscr[1]*pconf.stretch, hscr[2]));
|
||||
} */
|
||||
}
|
||||
|
||||
@ -1430,7 +1435,7 @@ void dqi_poly::draw() {
|
||||
for(int j=0; j<MAX_PHASE; j++) {
|
||||
twopoint_sphere_flips = j;
|
||||
hyperpoint h2; applymodel(h1, h2);
|
||||
glvertex h = glhr::pointtogl(h2 * current_display->radius); h[1] *= vid.stretch;
|
||||
glvertex h = glhr::pointtogl(h2 * current_display->radius); h[1] *= pconf.stretch;
|
||||
if(i == 0)
|
||||
phases[j].push_back(h);
|
||||
else {
|
||||
@ -1458,7 +1463,7 @@ void dqi_poly::draw() {
|
||||
for(int i=0; i<cnt; i++) {
|
||||
|
||||
hyperpoint h1 = V * glhr::gltopoint((*tab)[offset+i]);
|
||||
hyperpoint mh1; applymodel(h1, mh1); mh1[1] *= vid.stretch;
|
||||
hyperpoint mh1; applymodel(h1, mh1); mh1[1] *= pconf.stretch;
|
||||
phases[cpha].push_back(glhr::pointtogl(mh1 * current_display->radius));
|
||||
|
||||
// check if the i-th edge intersects the boundary of the ellipse
|
||||
@ -1474,7 +1479,7 @@ void dqi_poly::draw() {
|
||||
if(c1 < 0) c1 = -c1, c2 = -c2;
|
||||
hyperpoint h = ah1 * c1 + ah2 * c2;
|
||||
h /= hypot_d(3, h);
|
||||
if(h[2] < 0 && abs(h[0]) < sin(vid.twopoint_param)) cpha = 1-cpha, pha = 2;
|
||||
if(h[2] < 0 && abs(h[0]) < sin(pconf.twopoint_param)) cpha = 1-cpha, pha = 2;
|
||||
}
|
||||
if(cpha == 1) pha = 0;
|
||||
}
|
||||
@ -1530,7 +1535,7 @@ void dqi_poly::draw() {
|
||||
last_infront = false;
|
||||
|
||||
addpoly(V, *tab, offset, cnt);
|
||||
if(!(sphere && vid.alpha < .9)) if(pmodel != mdJoukowsky) if(!(flags & POLY_ALWAYS_IN)) for(int i=1; i<isize(glcoords); i++) {
|
||||
if(!(sphere && pconf.alpha < .9)) if(pmodel != mdJoukowsky) if(!(flags & POLY_ALWAYS_IN)) for(int i=1; i<isize(glcoords); i++) {
|
||||
ld dx = glcoords[i][0] - glcoords[i-1][0];
|
||||
ld dy = glcoords[i][1] - glcoords[i-1][1];
|
||||
if(dx > vid.xres * 2 || dy > vid.yres * 2) return;
|
||||
@ -1556,7 +1561,7 @@ void dqi_poly::draw() {
|
||||
|
||||
if(poly_flags & POLY_NIF_ERROR) return;
|
||||
|
||||
if(spherespecial == 1 && sphere && (poly_flags & POLY_INFRONT) && (poly_flags & POLY_NOTINFRONT) && vid.alpha <= 1) {
|
||||
if(spherespecial == 1 && sphere && (poly_flags & POLY_INFRONT) && (poly_flags & POLY_NOTINFRONT) && pconf.alpha <= 1) {
|
||||
bool around_center = false;
|
||||
for(int i=0; i<isize(glcoords)-1; i++) {
|
||||
double x1 = glcoords[i][0];
|
||||
@ -1574,9 +1579,9 @@ void dqi_poly::draw() {
|
||||
bool can_have_inverse = false;
|
||||
if(sphere && pmodel == mdDisk && (spherespecial > 0 || equi)) can_have_inverse = true;
|
||||
if(pmodel == mdJoukowsky) can_have_inverse = true;
|
||||
if(pmodel == mdJoukowskyInverted && vid.skiprope) can_have_inverse = true;
|
||||
if(pmodel == mdDisk && hyperbolic && vid.alpha <= -1) can_have_inverse = true;
|
||||
if(pmodel == mdSpiral && vid.skiprope) can_have_inverse = true;
|
||||
if(pmodel == mdJoukowskyInverted && pconf.skiprope) can_have_inverse = true;
|
||||
if(pmodel == mdDisk && hyperbolic && pconf.alpha <= -1) can_have_inverse = true;
|
||||
if(pmodel == mdSpiral && pconf.skiprope) can_have_inverse = true;
|
||||
if(pmodel == mdCentralInversion) can_have_inverse = true;
|
||||
|
||||
if(can_have_inverse && !(poly_flags & POLY_ISSIDE)) {
|
||||
@ -1591,7 +1596,7 @@ void dqi_poly::draw() {
|
||||
}
|
||||
|
||||
if(poly_flags & POLY_INVERSE) {
|
||||
if(curradius < vid.alpha - 1e-6) return;
|
||||
if(curradius < pconf.alpha - 1e-6) return;
|
||||
if(!sphere) return;
|
||||
}
|
||||
|
||||
@ -1620,7 +1625,7 @@ void dqi_poly::draw() {
|
||||
ld h = atan2(glcoords[0][0], glcoords[0][1]);
|
||||
for(int i=0; i<=360; i++) {
|
||||
ld a = i * degree + h;
|
||||
glcoords.push_back(glhr::makevertex(current_display->radius * sin(a), current_display->radius * vid.stretch * cos(a), 0));
|
||||
glcoords.push_back(glhr::makevertex(current_display->radius * sin(a), current_display->radius * pconf.stretch * cos(a), 0));
|
||||
}
|
||||
poly_flags ^= POLY_INVERSE;
|
||||
}
|
||||
@ -1853,7 +1858,7 @@ int qp[PMAX], qp0[PMAX];
|
||||
|
||||
color_t darken_color(color_t& color, bool outline) {
|
||||
int alpha = color & 255;
|
||||
if(sphere && pmodel == mdDisk && vid.alpha <= 1)
|
||||
if(sphere && pmodel == mdDisk && pconf.alpha <= 1)
|
||||
return 0;
|
||||
else {
|
||||
if(outline && alpha < 255)
|
||||
@ -1875,6 +1880,8 @@ void dqi_line::draw_back() {
|
||||
}
|
||||
|
||||
EX void sort_drawqueue() {
|
||||
|
||||
DEBBI(DF_GRAPH, ("sort_drawqueue"));
|
||||
|
||||
for(int a=0; a<PMAX; a++) qp[a] = 0;
|
||||
|
||||
@ -1925,6 +1932,7 @@ EX void reverse_side_priorities() {
|
||||
|
||||
// on the sphere, parts on the back are drawn first
|
||||
EX void draw_backside() {
|
||||
DEBBI(DF_GRAPH, ("draw_backside"));
|
||||
if(pmodel == mdHyperboloid && hyperbolic) {
|
||||
dynamicval<eModel> dv (pmodel, mdHyperboloidFlat);
|
||||
for(auto& ptd: ptds)
|
||||
@ -1964,6 +1972,7 @@ EX void reverse_transparent_walls() {
|
||||
}
|
||||
|
||||
EX void draw_main() {
|
||||
DEBBI(DF_GRAPH, ("draw_main"));
|
||||
if(sphere && GDIM == 3 && pmodel == mdPerspective) {
|
||||
for(int p: {1, 0, 2, 3}) {
|
||||
if(elliptic && p < 2) continue;
|
||||
@ -2032,7 +2041,14 @@ EX hookset<bool()> hooks_vr_draw_all;
|
||||
#endif
|
||||
|
||||
EX void drawqueue() {
|
||||
callhooks(hooks_drawqueue);
|
||||
|
||||
DEBBI(DF_GRAPH, ("drawqueue"));
|
||||
|
||||
#if CAP_WRL
|
||||
if(wrl::in) { wrl::render(); return; }
|
||||
#endif
|
||||
|
||||
callhooks(hook_drawqueue);
|
||||
current_display->next_shader_flags = 0;
|
||||
reset_projection();
|
||||
// reset_projection() is not sufficient here, because we need to know shaderside_projection
|
||||
@ -2045,6 +2061,8 @@ EX void drawqueue() {
|
||||
profile_start(3);
|
||||
|
||||
sort_drawqueue();
|
||||
|
||||
DEBB(DF_GRAPH, ("sort walls"));
|
||||
|
||||
if(GDIM == 2)
|
||||
for(PPR p: {PPR::REDWALLs, PPR::REDWALLs2, PPR::REDWALLs3, PPR::WALL3s,
|
||||
@ -2353,7 +2371,7 @@ EX void getcoord0(const hyperpoint& h, int& xc, int &yc, int &sc) {
|
||||
hyperpoint hscr;
|
||||
applymodel(h, hscr);
|
||||
xc = current_display->xcenter + current_display->radius * hscr[0];
|
||||
yc = current_display->ycenter + current_display->radius * vid.stretch * hscr[1];
|
||||
yc = current_display->ycenter + current_display->radius * pconf.stretch * hscr[1];
|
||||
sc = 0;
|
||||
// EYETODO sc = vid.eye * current_display->radius * hscr[2];
|
||||
}
|
||||
|
2722
fieldpattern.cpp
2722
fieldpattern.cpp
File diff suppressed because it is too large
Load Diff
@ -1011,6 +1011,8 @@ auto floor_hook =
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
|
||||
EX ld floor_texture_square_size;
|
||||
|
||||
void draw_shape_for_texture(floorshape* sh) {
|
||||
|
||||
int id = sh->id;
|
||||
@ -1064,23 +1066,30 @@ void draw_shape_for_texture(floorshape* sh) {
|
||||
hyperpoint inmodel;
|
||||
applymodel(center, inmodel);
|
||||
glvertex tmap;
|
||||
tmap[0] = (1 + inmodel[0] * vid.scale) / 2;
|
||||
tmap[1] = (1 - inmodel[1] * vid.scale) / 2;
|
||||
tmap[0] = (1 + inmodel[0] * pconf.scale) / 2;
|
||||
tmap[1] = (1 - inmodel[1] * pconf.scale) / 2;
|
||||
applymodel(center + v1, inmodel);
|
||||
tmap[2] = (1 + inmodel[0] * vid.scale) / 2 - tmap[0];
|
||||
tmap[2] = (1 + inmodel[0] * pconf.scale) / 2 - tmap[0];
|
||||
floor_texture_map[sh->id] = tmap;
|
||||
}
|
||||
|
||||
// SL2 needs 6 times more
|
||||
texture_order([&] (ld x, ld y) {
|
||||
auto tvec_at = [&] (ld x, ld y) {
|
||||
hyperpoint h = center + v1 * x + v2 * y;
|
||||
hyperpoint inmodel;
|
||||
applymodel(h, inmodel);
|
||||
glvec2 v;
|
||||
v[0] = (1 + inmodel[0] * vid.scale) / 2;
|
||||
v[1] = (1 - inmodel[1] * vid.scale) / 2;
|
||||
v[0] = (1 + inmodel[0] * pconf.scale) / 2;
|
||||
v[1] = (1 - inmodel[1] * pconf.scale) / 2;
|
||||
return v;
|
||||
};
|
||||
|
||||
// SL2 needs 6 times more
|
||||
texture_order([&] (ld x, ld y) {
|
||||
auto v = tvec_at(x, y);
|
||||
ftv.tvertices.push_back(glhr::makevertex(v[0], v[1], 0));
|
||||
});
|
||||
|
||||
floor_texture_square_size = 2 * (tvec_at(1, 0)[0] - tvec_at(0, 0)[0]);
|
||||
}
|
||||
|
||||
/** copy the texture vertices so that there are at least qty of them */
|
||||
@ -1102,7 +1111,9 @@ EX void bind_floor_texture(hpcshape& li, int id) {
|
||||
ensure_vertex_number(li);
|
||||
}
|
||||
|
||||
#if HDR
|
||||
const int FLOORTEXTURESIZE = 4096;
|
||||
#endif
|
||||
|
||||
void geometry_information::make_floor_textures_here() {
|
||||
require_shapes();
|
||||
@ -1110,9 +1121,9 @@ void geometry_information::make_floor_textures_here() {
|
||||
dynamicval<videopar> vi(vid, vid);
|
||||
vid.xres = FLOORTEXTURESIZE;
|
||||
vid.yres = FLOORTEXTURESIZE;
|
||||
vid.scale = 0.125;
|
||||
vid.camera_angle = 0;
|
||||
vid.alpha = 1;
|
||||
pconf.scale = 0.125;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.alpha = 1;
|
||||
dynamicval<ld> lw(vid.linewidth, 2);
|
||||
|
||||
floor_textures = new renderbuffer(vid.xres, vid.yres, vid.usingGL);
|
||||
@ -1127,7 +1138,7 @@ void geometry_information::make_floor_textures_here() {
|
||||
cd->xsize = cd->ysize = FLOORTEXTURESIZE;
|
||||
cd->xcenter = cd->ycenter = cd->scrsize = FLOORTEXTURESIZE/2;
|
||||
|
||||
cd->radius = cd->scrsize * vid.scale;
|
||||
cd->radius = cd->scrsize * pconf.scale;
|
||||
|
||||
floor_textures->enable();
|
||||
floor_textures->clear(0); // 0xE8E8E8 = 1
|
||||
|
24
geom-exp.cpp
24
geom-exp.cpp
@ -381,21 +381,21 @@ void ge_select_tiling() {
|
||||
|
||||
EX string current_proj_name() {
|
||||
bool h = hyperbolic || sn::in();
|
||||
if(pmodel != mdDisk)
|
||||
return models::get_model_name(pmodel);
|
||||
else if(h && vid.alpha == 1)
|
||||
if(vpconf.model != mdDisk)
|
||||
return models::get_model_name(vpconf.model);
|
||||
else if(h && vpconf.alpha == 1)
|
||||
return XLAT("Poincaré model");
|
||||
else if(h && vid.alpha == 0)
|
||||
else if(h && vpconf.alpha == 0)
|
||||
return XLAT("Klein-Beltrami model");
|
||||
else if(h && vid.alpha == -1)
|
||||
else if(h && vpconf.alpha == -1)
|
||||
return XLAT("inverted Poincaré model");
|
||||
else if(sphere && vid.alpha == 1)
|
||||
else if(sphere && vpconf.alpha == 1)
|
||||
return XLAT("stereographic projection");
|
||||
else if(sphere && vid.alpha == 0)
|
||||
else if(sphere && vpconf.alpha == 0)
|
||||
return XLAT("gnomonic projection");
|
||||
else if(sphere && vid.alpha >= 999)
|
||||
else if(sphere && vpconf.alpha >= 999)
|
||||
return XLAT("orthographic projection");
|
||||
else if(h && vid.alpha >= 999)
|
||||
else if(h && vpconf.alpha >= 999)
|
||||
return XLAT("Gans model");
|
||||
else
|
||||
return XLAT("general perspective");
|
||||
@ -405,7 +405,7 @@ EX string dim_name() {
|
||||
return " (" + its(WDIM) + "D)";
|
||||
}
|
||||
|
||||
#if CAP_THREAD
|
||||
#if CAP_THREAD && MAXMDIM >= 4
|
||||
EX void showQuotientConfig3() {
|
||||
|
||||
using namespace fieldpattern;
|
||||
@ -528,7 +528,7 @@ EX void select_quotient_screen() {
|
||||
println(hlog, "set prime = ", currfp.Prime);
|
||||
start_game();
|
||||
}
|
||||
#if CAP_THREAD
|
||||
#if CAP_THREAD && MAXMDIM >= 4
|
||||
pushScreen(showQuotientConfig3);
|
||||
#endif
|
||||
}
|
||||
@ -940,7 +940,7 @@ EX void runGeometryExperiments() {
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
|
||||
eGeometry readGeo(const string& ss) {
|
||||
EX eGeometry readGeo(const string& ss) {
|
||||
for(int i=0; i<isize(ginf); i++) if(ginf[i].shortname == ss) return eGeometry(i);
|
||||
bool numeric = true;
|
||||
for(char c: ss) if(c < '0' || c > '9') numeric = false;
|
||||
|
28
geometry.cpp
28
geometry.cpp
@ -710,24 +710,24 @@ EX namespace geom3 {
|
||||
void geometry_information::prepare_compute3() {
|
||||
using namespace geom3;
|
||||
DEBBI(DF_INIT | DF_POLY | DF_GEOM, ("geom3::compute"));
|
||||
// tanh(depth) / tanh(camera) == vid.alpha
|
||||
// tanh(depth) / tanh(camera) == pconf.alpha
|
||||
invalid = "";
|
||||
|
||||
if(GDIM == 3) ;
|
||||
else if(vid.tc_alpha < vid.tc_depth && vid.tc_alpha < vid.tc_camera)
|
||||
vid.alpha = tan_auto(vid.depth) / tan_auto(vid.camera);
|
||||
pconf.alpha = tan_auto(vid.depth) / tan_auto(vid.camera);
|
||||
else if(vid.tc_depth < vid.tc_alpha && vid.tc_depth < vid.tc_camera) {
|
||||
ld v = vid.alpha * tan_auto(vid.camera);
|
||||
ld v = pconf.alpha * tan_auto(vid.camera);
|
||||
if(hyperbolic && (v<1e-6-12 || v>1-1e-12)) invalid = "cannot adjust depth", vid.depth = vid.camera;
|
||||
else vid.depth = atan_auto(v);
|
||||
}
|
||||
else {
|
||||
ld v = tan_auto(vid.depth) / vid.alpha;
|
||||
ld v = tan_auto(vid.depth) / pconf.alpha;
|
||||
if(hyperbolic && (v<1e-12-1 || v>1-1e-12)) invalid = "cannot adjust camera", vid.camera = vid.depth;
|
||||
else vid.camera = atan_auto(v);
|
||||
}
|
||||
|
||||
if(fabs(vid.alpha) < 1e-6) invalid = "does not work with perfect Klein";
|
||||
if(fabs(pconf.alpha) < 1e-6) invalid = "does not work with perfect Klein";
|
||||
|
||||
if(invalid != "") {
|
||||
INFDEEP = .7;
|
||||
@ -851,20 +851,20 @@ EX void switch_always3() {
|
||||
|
||||
EX void switch_tpp() {
|
||||
if(dual::split(switch_fpp)) return;
|
||||
if(pmodel == mdDisk && vid.camera_angle) {
|
||||
if(pmodel == mdDisk && pconf.camera_angle) {
|
||||
vid.yshift = 0;
|
||||
vid.camera_angle = 0;
|
||||
vid.xposition = 0;
|
||||
vid.yposition = 0;
|
||||
vid.scale = 1;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = 0;
|
||||
pconf.scale = 1;
|
||||
vid.fixed_facing = false;
|
||||
}
|
||||
else {
|
||||
vid.yshift = -0.3;
|
||||
vid.camera_angle = -45;
|
||||
vid.scale = 18/16. * vid.xres / vid.yres / multi::players;
|
||||
vid.xposition = 0;
|
||||
vid.yposition = -0.9;
|
||||
pconf.camera_angle = -45;
|
||||
pconf.scale = 18/16. * vid.xres / vid.yres / multi::players;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = -0.9;
|
||||
vid.fixed_facing = true;
|
||||
vid.fixed_facing_dir = 90;
|
||||
}
|
||||
|
52
graph.cpp
52
graph.cpp
@ -1390,7 +1390,7 @@ EX bool drawMonsterType(eMonster m, cell *where, const transmatrix& V1, color_t
|
||||
}
|
||||
else {
|
||||
queuepoly(VHEAD1, cgi.shPHead, 0xF0A0D0FF);
|
||||
queuepoly(VBS, cgi.shFlowerHand, 0xC00000FF);
|
||||
queuepoly(VBODY * VBS, cgi.shFlowerHand, 0xC00000FF);
|
||||
queuepoly(VBODY2 * VBS, cgi.shSuspenders, 0xC00000FF);
|
||||
}
|
||||
}
|
||||
@ -2858,10 +2858,10 @@ int haveaura_cached;
|
||||
EX int haveaura() {
|
||||
if(!(vid.aurastr>0 && !svg::in && (auraNOGL || vid.usingGL))) return 0;
|
||||
if(sphere && mdAzimuthalEqui()) return 0;
|
||||
if(among(pmodel, mdJoukowsky, mdJoukowskyInverted) && hyperbolic && models::model_transition < 1)
|
||||
if(among(pmodel, mdJoukowsky, mdJoukowskyInverted) && hyperbolic && pconf.model_transition < 1)
|
||||
return 2;
|
||||
if(pmodel == mdFisheye) return 1;
|
||||
return pmodel == mdDisk && (!sphere || vid.alpha > 10) && !euclid;
|
||||
return pmodel == mdDisk && (!sphere || pconf.alpha > 10) && !euclid;
|
||||
}
|
||||
|
||||
vector<pair<int, int> > auraspecials;
|
||||
@ -2884,7 +2884,7 @@ void apply_joukowsky_aura(hyperpoint& h) {
|
||||
h = ret;
|
||||
}
|
||||
if(nonisotropic) {
|
||||
h = lp_apply(inverse_exp(h, iTable, true));
|
||||
h = lp_apply(inverse_exp(h, pfNO_DISTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2927,13 +2927,14 @@ void sumaura(int v) {
|
||||
vector<glhr::colored_vertex> auravertices;
|
||||
|
||||
void drawaura() {
|
||||
DEBBI(DF_GRAPH, ("draw aura"));
|
||||
if(!haveaura()) return;
|
||||
if(vid.stereo_mode) return;
|
||||
double rad = current_display->radius;
|
||||
if(sphere && !mdAzimuthalEqui()) rad /= sqrt(vid.alpha*vid.alpha - 1);
|
||||
if(sphere && !mdAzimuthalEqui()) rad /= sqrt(pconf.alpha*pconf.alpha - 1);
|
||||
if(hyperbolic && pmodel == mdFisheye) {
|
||||
ld h = 1;
|
||||
h /= vid.fisheye_param;
|
||||
h /= pconf.fisheye_param;
|
||||
ld nrad = h / sqrt(2 + h*h);
|
||||
rad *= nrad;
|
||||
}
|
||||
@ -2959,9 +2960,9 @@ void drawaura() {
|
||||
for(int x=0; x<vid.xres; x++) {
|
||||
|
||||
ld hx = (x * 1. - current_display->xcenter) / rad;
|
||||
ld hy = (y * 1. - current_display->ycenter) / rad / vid.stretch;
|
||||
ld hy = (y * 1. - current_display->ycenter) / rad / pconf.stretch;
|
||||
|
||||
if(vid.camera_angle) camrotate(hx, hy);
|
||||
if(pconf.camera_angle) camrotate(hx, hy);
|
||||
|
||||
ld fac = sqrt(hx*hx+hy*hy);
|
||||
if(fac < 1) continue;
|
||||
@ -3007,8 +3008,8 @@ void drawaura() {
|
||||
facs[10] = 10;
|
||||
cmul[1] = cmul[0];
|
||||
|
||||
bool inversion = vid.alpha <= -1 || pmodel == mdJoukowsky;
|
||||
bool joukowsky = among(pmodel, mdJoukowskyInverted, mdJoukowsky) && hyperbolic && models::model_transition < 1;
|
||||
bool inversion = pconf.alpha <= -1 || pmodel == mdJoukowsky;
|
||||
bool joukowsky = among(pmodel, mdJoukowskyInverted, mdJoukowsky) && hyperbolic && pconf.model_transition < 1;
|
||||
|
||||
for(int r=0; r<=AURA; r++) for(int z=0; z<11; z++) {
|
||||
float rr = (M_PI * 2 * r) / AURA;
|
||||
@ -3024,7 +3025,7 @@ void drawaura() {
|
||||
else
|
||||
models::apply_orientation(c1, s1);
|
||||
|
||||
ld& mt = models::model_transition;
|
||||
ld& mt = pconf.model_transition;
|
||||
ld mt2 = 1 - mt;
|
||||
|
||||
ld m = sqrt(c1*c1 + s1*s1 / mt2 / mt2);
|
||||
@ -3034,7 +3035,7 @@ void drawaura() {
|
||||
}
|
||||
|
||||
cx[r][z][0] = rad0 * c;
|
||||
cx[r][z][1] = rad0 * s * vid.stretch;
|
||||
cx[r][z][1] = rad0 * s * pconf.stretch;
|
||||
|
||||
for(int u=0; u<3; u++)
|
||||
cx[r][z][u+2] = bak[u] + (aurac[rm][u] / (aurac[rm][3]+.1) - bak[u]) * cmul[z];
|
||||
@ -3362,7 +3363,7 @@ bool openorsafe(cell *c) {
|
||||
EX color_t stdgridcolor = 0x202020FF;
|
||||
|
||||
EX int gridcolor(cell *c1, cell *c2) {
|
||||
if(cmode & sm::DRAW) return Dark(forecolor);
|
||||
if(cmode & sm::DRAW && !mapeditor::drawing_tool) return Dark(forecolor);
|
||||
if(!c2)
|
||||
return 0x202020 >> darken;
|
||||
int rd1 = rosedist(c1), rd2 = rosedist(c2);
|
||||
@ -3667,7 +3668,7 @@ bool celldrawer::cell_clipped() {
|
||||
hyperpoint H = tC0(V);
|
||||
if(abs(H[0]) <= 3 && abs(H[1]) <= 3 && abs(H[2]) <= 3 ) ;
|
||||
else {
|
||||
hyperpoint H2 = inverse_exp(H, iLazy);
|
||||
hyperpoint H2 = inverse_exp(H, pQUICK);
|
||||
for(hyperpoint& cpoint: clipping_planes) if((H2|cpoint) < -.4) return true;
|
||||
}
|
||||
noclipped++;
|
||||
@ -3676,7 +3677,7 @@ bool celldrawer::cell_clipped() {
|
||||
hyperpoint H = tC0(V);
|
||||
if(abs(H[0]) <= 3 && abs(H[1]) <= 3 && abs(H[2]) <= 3 ) ;
|
||||
else {
|
||||
hyperpoint H2 = inverse_exp(H, iLazy);
|
||||
hyperpoint H2 = inverse_exp(H, pQUICK);
|
||||
for(hyperpoint& cpoint: clipping_planes) if((H2|cpoint) < -2) return true;
|
||||
}
|
||||
noclipped++;
|
||||
@ -3697,7 +3698,8 @@ EX void gridline(const transmatrix& V1, const hyperpoint h1, const transmatrix&
|
||||
if(WDIM == 3 && fat_edges) {
|
||||
transmatrix T = V1 * rgpushxto0(h1);
|
||||
transmatrix S = rspintox(inverse(T) * V2 * h2);
|
||||
queuepoly(T * S, cgi.generate_pipe(d, vid.linewidth), col);
|
||||
auto& p = queuepoly(T * S, cgi.generate_pipe(d, vid.linewidth), col);
|
||||
p.intester = xpush0(d/2);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -4470,12 +4472,12 @@ EX void precise_mouseover() {
|
||||
if(WDIM == 3) {
|
||||
mouseover2 = mouseover = centerover;
|
||||
ld best = HUGE_VAL;
|
||||
hyperpoint h = direct_exp(lp_iapply(ztangent(0.01)), 100);
|
||||
hyperpoint h = direct_exp(lp_iapply(ztangent(0.01)));
|
||||
|
||||
transmatrix cov = ggmatrix(mouseover2);
|
||||
forCellIdEx(c1, i, mouseover2) {
|
||||
hyperpoint h1 = tC0(cov * currentmap->adj(mouseover2, i));
|
||||
ld dist = geo_dist(h, h1, iTable) - geo_dist(C0, h1, iTable);
|
||||
ld dist = geo_dist(h, h1) - geo_dist(C0, h1);
|
||||
if(dist < best) mouseover = c1, best = dist;
|
||||
}
|
||||
return;
|
||||
@ -4559,7 +4561,7 @@ EX void drawthemap() {
|
||||
#endif
|
||||
if(non_spatial_model())
|
||||
spatial_graphics = false;
|
||||
if(pmodel == mdDisk && abs(vid.alpha) < 1e-6) spatial_graphics = false;
|
||||
if(pmodel == mdDisk && abs(pconf.alpha) < 1e-6) spatial_graphics = false;
|
||||
|
||||
if(!spatial_graphics) wmspatial = mmspatial = false;
|
||||
if(GDIM == 3) wmspatial = mmspatial = true;
|
||||
@ -4628,6 +4630,8 @@ EX void drawthemap() {
|
||||
profile_stop(4);
|
||||
drawFlashes();
|
||||
|
||||
mapeditor::draw_dtshapes();
|
||||
|
||||
if(multi::players > 1 && !shmup::on) {
|
||||
if(multi::centerplayer != -1)
|
||||
cwtV = multi::whereis[multi::centerplayer];
|
||||
@ -4762,7 +4766,7 @@ EX void calcparam() {
|
||||
cd->xcenter = cd->xtop + cd->xsize / 2;
|
||||
cd->ycenter = cd->ytop + cd->ysize / 2;
|
||||
|
||||
if(vid.scale > -1e-2 && vid.scale < 1e-2) vid.scale = 1;
|
||||
if(pconf.scale > -1e-2 && pconf.scale < 1e-2) pconf.scale = 1;
|
||||
|
||||
ld realradius = min(cd->xsize / 2, cd->ysize / 2);
|
||||
|
||||
@ -4784,11 +4788,11 @@ EX void calcparam() {
|
||||
if(current_display->sidescreen) cd->xcenter = vid.yres/2;
|
||||
}
|
||||
|
||||
cd->radius = vid.scale * cd->scrsize;
|
||||
cd->radius = pconf.scale * cd->scrsize;
|
||||
if(GDIM == 3 && in_perspective()) cd->radius = cd->scrsize;
|
||||
realradius = min(realradius, cd->radius);
|
||||
|
||||
ld aradius = sphere ? cd->radius / (vid.alpha - 1) : cd->radius;
|
||||
ld aradius = sphere ? cd->radius / (pconf.alpha - 1) : cd->radius;
|
||||
|
||||
if(dronemode) { cd->ycenter -= cd->radius; cd->ycenter += vid.fsize/2; cd->ycenter += vid.fsize/2; cd->radius *= 2; }
|
||||
|
||||
@ -4800,8 +4804,8 @@ EX void calcparam() {
|
||||
cd->xcenter = cd->xtop + cd->xsize - vid.fsize - aradius;
|
||||
}
|
||||
|
||||
cd->xcenter += cd->scrsize * vid.xposition;
|
||||
cd->ycenter += cd->scrsize * vid.yposition;
|
||||
cd->xcenter += cd->scrsize * pconf.xposition;
|
||||
cd->ycenter += cd->scrsize * pconf.yposition;
|
||||
|
||||
cd->tanfov = tan(vid.fov * degree / 2);
|
||||
|
||||
|
@ -362,7 +362,7 @@ EX namespace history {
|
||||
}
|
||||
|
||||
ld measureLength() {
|
||||
ld r = bandhalf * vid.scale;
|
||||
ld r = bandhalf * pconf.scale;
|
||||
|
||||
ld tpixels = 0;
|
||||
int siz = isize(v);
|
||||
@ -526,7 +526,7 @@ EX namespace history {
|
||||
dialog::addBoolItem(XLAT("include history"), (includeHistory), 'i');
|
||||
|
||||
// bool notconformal0 = (pmodel >= 5 && pmodel <= 6) && !euclid;
|
||||
// bool notconformal = notconformal0 || abs(vid.alpha-1) > 1e-3;
|
||||
// bool notconformal = notconformal0 || abs(pconf.alpha-1) > 1e-3;
|
||||
|
||||
dialog::addSelItem(XLAT("projection"), current_proj_name(), 'm');
|
||||
|
||||
|
14
hud.cpp
14
hud.cpp
@ -401,20 +401,12 @@ EX void drawStats() {
|
||||
if(geometry == gRotSpace || geometry == gProduct) rots::draw_underlying(!cornermode);
|
||||
|
||||
{
|
||||
dynamicval<eModel> pm(pmodel, flat_model());
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
// dynamicval<videopar> v(vid, vid);
|
||||
// vid.alpha = vid.scale = 1;
|
||||
dynamicval<ld> va(vid.alpha, 1);
|
||||
dynamicval<ld> vs(vid.scale, 1);
|
||||
dynamicval<ld> vc(vid.camera_angle, 0);
|
||||
if(prod) vid.alpha = 30, vid.scale = 30;
|
||||
|
||||
auto& cd = current_display;
|
||||
auto xc = cd->xcenter;
|
||||
auto yc = cd->ycenter;
|
||||
|
||||
calcparam();
|
||||
flat_model_enabler fme;
|
||||
|
||||
if(crosshair_color && crosshair_size > 0) {
|
||||
initquickqueue();
|
||||
@ -469,7 +461,7 @@ EX void drawStats() {
|
||||
int spots = 0;
|
||||
for(int u=vid.fsize; u<vid.xres/2-s; u += s)
|
||||
for(int v=vid.fsize; v<vid.yres/2-s; v += s)
|
||||
if(hypot(vid.xres/2-u-s, (vid.yres/2-v-s) / vid.stretch) > rad) {
|
||||
if(hypot(vid.xres/2-u-s, (vid.yres/2-v-s) / pconf.stretch) > rad) {
|
||||
spots++;
|
||||
}
|
||||
if(spots >= bycorner[cor] && spots >= 3) {
|
||||
@ -482,7 +474,7 @@ EX void drawStats() {
|
||||
}
|
||||
for(int u=vid.fsize; u<vid.xres/2-s; u += s)
|
||||
for(int v=vid.fsize; v<vid.yres/2-s; v += s)
|
||||
if(hypot(vid.xres/2-u-s, (vid.yres/2-v-s) / vid.stretch) > rad) {
|
||||
if(hypot(vid.xres/2-u-s, (vid.yres/2-v-s) / pconf.stretch) > rad) {
|
||||
if(next >= isize(glyphstoshow)) break;
|
||||
|
||||
int cx = u;
|
||||
|
57
hyper.h
57
hyper.h
@ -13,8 +13,8 @@
|
||||
#define _HYPER_H_
|
||||
|
||||
// version numbers
|
||||
#define VER "11.3i"
|
||||
#define VERNUM_HEX 0xA829
|
||||
#define VER "11.3j"
|
||||
#define VERNUM_HEX 0xA82A
|
||||
|
||||
#include "sysconfig.h"
|
||||
|
||||
@ -228,9 +228,46 @@ enum eStereo { sOFF, sAnaglyph, sLR, sODS };
|
||||
|
||||
enum eModel : int;
|
||||
|
||||
/** configuration of the projection */
|
||||
struct projection_configuration {
|
||||
eModel model; /**< which projection, see classes.cpp */
|
||||
ld xposition, yposition; /**< move the center to another position */
|
||||
ld scale, alpha, camera_angle, fisheye_param, twopoint_param, stretch, ballangle, ballproj, euclid_to_sphere;
|
||||
ld clip_min, clip_max;
|
||||
ld model_orientation, halfplane_scale, model_orientation_yz;
|
||||
ld collignon_parameter;
|
||||
bool collignon_reflected;
|
||||
string formula;
|
||||
eModel basic_model;
|
||||
ld top_z;
|
||||
ld model_transition;
|
||||
ld spiral_angle;
|
||||
ld spiral_x;
|
||||
ld spiral_y;
|
||||
bool use_atan;
|
||||
ld right_spiral_multiplier;
|
||||
ld any_spiral_multiplier;
|
||||
ld sphere_spiral_multiplier;
|
||||
ld spiral_cone;
|
||||
ld skiprope;
|
||||
ld product_z_scale;
|
||||
|
||||
projection_configuration() {
|
||||
formula = "z^2"; top_z = 5; model_transition = 1; spiral_angle = 70; spiral_x = 10; spiral_y = 7;
|
||||
right_spiral_multiplier = 1;
|
||||
any_spiral_multiplier = 1;
|
||||
sphere_spiral_multiplier = 2;
|
||||
spiral_cone = 360;
|
||||
use_atan = false;
|
||||
product_z_scale = 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct videopar {
|
||||
ld scale, alpha, sspeed, mspeed, yshift, camera_angle;
|
||||
ld ballangle, ballproj, euclid_to_sphere, twopoint_param, fisheye_param, stretch, binary_width, fixed_facing_dir;
|
||||
projection_configuration projection_config, rug_config;
|
||||
ld yshift;
|
||||
ld sspeed, mspeed;
|
||||
ld binary_width, fixed_facing_dir;
|
||||
int mobilecompasssize;
|
||||
int radarsize; // radar for 3D geometries
|
||||
ld radarrange;
|
||||
@ -251,8 +288,6 @@ struct videopar {
|
||||
|
||||
int xscr, yscr;
|
||||
|
||||
ld xposition, yposition;
|
||||
|
||||
bool grid;
|
||||
bool particles;
|
||||
|
||||
@ -304,8 +339,6 @@ struct videopar {
|
||||
int cells_drawn_limit;
|
||||
int cells_generated_limit; // limit on cells generated per frame
|
||||
|
||||
ld skiprope;
|
||||
|
||||
eStereo stereo_mode;
|
||||
ld ipd;
|
||||
ld lr_eyewidth, anaglyph_eyewidth;
|
||||
@ -319,7 +352,6 @@ struct videopar {
|
||||
ld depth; // world level below the plane
|
||||
ld camera; // camera level above the plane
|
||||
ld wall_height, creature_scale, height_width;
|
||||
eModel vpmodel;
|
||||
ld lake_top, lake_bottom;
|
||||
ld rock_wall_ratio;
|
||||
ld human_wall_ratio;
|
||||
@ -331,7 +363,6 @@ struct videopar {
|
||||
ld eye;
|
||||
bool auto_eye;
|
||||
|
||||
ld collignon_parameter; bool collignon_reflected;
|
||||
ld plevel_factor;
|
||||
bool bubbles_special, bubbles_threshold, bubbles_all;
|
||||
int joysmooth;
|
||||
@ -341,7 +372,7 @@ extern videopar vid;
|
||||
|
||||
#define WDIM cginf.g.gameplay_dimension
|
||||
#define GDIM cginf.g.graphical_dimension
|
||||
#define MDIM cginf.g.homogeneous_dimension
|
||||
#define MDIM (MAXMDIM == 3 ? 3 : cginf.g.homogeneous_dimension)
|
||||
#define LDIM (MDIM-1)
|
||||
#define cclass g.kind
|
||||
|
||||
@ -660,7 +691,9 @@ enum orbAction { roMouse, roKeyboard, roCheck, roMouseForce, roMultiCheck, roMul
|
||||
|
||||
#define MODELCOUNT ((int) mdGUARD)
|
||||
|
||||
#define pmodel (vid.vpmodel)
|
||||
#define pconf vid.projection_config
|
||||
#define vpconf (rug::rugged ? vid.rug_config : vid.projection_config)
|
||||
#define pmodel (pconf.model)
|
||||
|
||||
color_t darkena(color_t c, int lev, int a);
|
||||
|
||||
|
@ -702,6 +702,8 @@ EX transmatrix rpushxto0(const hyperpoint& H) {
|
||||
|
||||
EX transmatrix ggpushxto0(const hyperpoint& H, ld co) {
|
||||
if(translatable) {
|
||||
if(nonisotropic)
|
||||
return co > 0 ? eupush(H) : inverse(eupush(H));
|
||||
return eupush(co * H);
|
||||
}
|
||||
if(prod) {
|
||||
@ -1030,13 +1032,13 @@ EX bool asign(ld y1, ld y2) { return signum(y1) != signum(y2); }
|
||||
|
||||
EX ld xcross(ld x1, ld y1, ld x2, ld y2) { return x1 + (x2 - x1) * y1 / (y1 - y2); }
|
||||
|
||||
EX transmatrix parallel_transport(const transmatrix Position, const transmatrix& ori, const hyperpoint direction, int precision IS(100)) {
|
||||
EX transmatrix parallel_transport(const transmatrix Position, const transmatrix& ori, const hyperpoint direction) {
|
||||
if(nonisotropic) return nisot::parallel_transport(Position, direction);
|
||||
else if(prod) {
|
||||
hyperpoint h = product::direct_exp(ori * direction);
|
||||
return Position * rgpushxto0(h);
|
||||
}
|
||||
else return Position * rgpushxto0(direct_exp(direction, precision));
|
||||
else return Position * rgpushxto0(direct_exp(direction));
|
||||
}
|
||||
|
||||
EX void apply_parallel_transport(transmatrix& Position, const transmatrix orientation, const hyperpoint direction) {
|
||||
@ -1151,8 +1153,8 @@ EX hyperpoint tangent_length(hyperpoint dir, ld length) {
|
||||
}
|
||||
|
||||
/** exponential function: follow the geodesic given by v */
|
||||
EX hyperpoint direct_exp(hyperpoint v, int steps) {
|
||||
if(sn::in()) return nisot::numerical_exp(v, steps);
|
||||
EX hyperpoint direct_exp(hyperpoint v) {
|
||||
if(sn::in()) return nisot::numerical_exp(v);
|
||||
if(nil) return nilv::formula_exp(v);
|
||||
if(sl2) return slr::formula_exp(v);
|
||||
if(prod) return product::direct_exp(v);
|
||||
@ -1163,20 +1165,26 @@ EX hyperpoint direct_exp(hyperpoint v, int steps) {
|
||||
}
|
||||
|
||||
#if HDR
|
||||
enum iePrecision { iLazy, iTable };
|
||||
constexpr flagtype pfNO_INTERPOLATION = 1; /**< in tables (sol/nih geometries), do not use interpolations */
|
||||
constexpr flagtype pfNO_DISTANCE = 2; /**< we just need the directions -- this makes it a bit faster in sol/nih geometries */
|
||||
constexpr flagtype pfLOW_BS_ITER = 4; /**< low iterations in binary search (nil geometry, sl2 not affected currently) */
|
||||
|
||||
constexpr flagtype pQUICK = pfNO_INTERPOLATION | pfLOW_BS_ITER;
|
||||
|
||||
constexpr flagtype pNORMAL = 0;
|
||||
#endif
|
||||
|
||||
/** inverse exponential function \see hr::direct_exp */
|
||||
EX hyperpoint inverse_exp(const hyperpoint h, iePrecision p, bool just_direction IS(true)) {
|
||||
EX hyperpoint inverse_exp(const hyperpoint h, flagtype prec IS(pNORMAL)) {
|
||||
#if CAP_SOLV
|
||||
if(sn::in()) {
|
||||
if(nih)
|
||||
return sn::get_inverse_exp_nsym(h, p == iLazy, just_direction);
|
||||
return sn::get_inverse_exp_nsym(h, prec);
|
||||
else
|
||||
return sn::get_inverse_exp_symsol(h, p == iLazy, just_direction);
|
||||
return sn::get_inverse_exp_symsol(h, prec);
|
||||
}
|
||||
#endif
|
||||
if(nil) return nilv::get_inverse_exp(h, p == iLazy ? 5 : 20);
|
||||
if(nil) return nilv::get_inverse_exp(h, prec);
|
||||
if(sl2) return slr::get_inverse_exp(h);
|
||||
if(prod) return product::inverse_exp(h);
|
||||
ld d = acos_auto_clamp(h[GDIM]);
|
||||
@ -1186,9 +1194,15 @@ EX hyperpoint inverse_exp(const hyperpoint h, iePrecision p, bool just_direction
|
||||
return v;
|
||||
}
|
||||
|
||||
EX ld geo_dist(const hyperpoint h1, const hyperpoint h2, iePrecision p) {
|
||||
EX ld geo_dist(const hyperpoint h1, const hyperpoint h2, flagtype prec IS(pNORMAL)) {
|
||||
if(!nonisotropic) return hdist(h1, h2);
|
||||
return hypot_d(3, inverse_exp(inverse(nisot::translate(h1)) * h2, p, false));
|
||||
return hypot_d(3, inverse_exp(inverse(nisot::translate(h1)) * h2, prec));
|
||||
}
|
||||
|
||||
EX ld geo_dist_q(const hyperpoint h1, const hyperpoint h2, flagtype prec IS(pNORMAL)) {
|
||||
auto d = geo_dist(h1, h2, prec);
|
||||
if(elliptic && d > M_PI/2) return M_PI - d;
|
||||
return d;
|
||||
}
|
||||
|
||||
EX hyperpoint lp_iapply(const hyperpoint h) {
|
||||
|
228
hypgraph.cpp
228
hypgraph.cpp
@ -12,7 +12,7 @@ ld ghx, ghy, ghgx, ghgy;
|
||||
hyperpoint ghpm = C0;
|
||||
|
||||
#if HDR
|
||||
inline bool sphereflipped() { return sphere && vid.alpha > 1.1 && GDIM == 3; }
|
||||
inline bool sphereflipped() { return sphere && pconf.alpha > 1.1 && GDIM == 3; }
|
||||
#endif
|
||||
|
||||
void ghcheck(hyperpoint &ret, const hyperpoint &H) {
|
||||
@ -22,7 +22,7 @@ void ghcheck(hyperpoint &ret, const hyperpoint &H) {
|
||||
}
|
||||
|
||||
EX void camrotate(ld& hx, ld& hy) {
|
||||
ld cam = vid.camera_angle * degree;
|
||||
ld cam = pconf.camera_angle * degree;
|
||||
GLfloat cc = cos(cam);
|
||||
GLfloat ss = sin(cam);
|
||||
ld ux = hx, uy = hy * cc + ss, uz = cc - ss * hy;
|
||||
@ -37,7 +37,7 @@ EX bool non_spatial_model() {
|
||||
return pmodel && vid.consider_shader_projection && (get_shader_flags() & SF_DIRECT);
|
||||
}
|
||||
|
||||
EX hyperpoint perspective_to_space(hyperpoint h, ld alpha IS(vid.alpha), eGeometryClass gc IS(ginf[geometry].cclass)) {
|
||||
EX hyperpoint perspective_to_space(hyperpoint h, ld alpha IS(pconf.alpha), eGeometryClass gc IS(ginf[geometry].cclass)) {
|
||||
ld hx = h[0], hy = h[1];
|
||||
|
||||
if(gc == gcEuclid)
|
||||
@ -59,7 +59,7 @@ EX hyperpoint perspective_to_space(hyperpoint h, ld alpha IS(vid.alpha), eGeomet
|
||||
B /= A; C /= A;
|
||||
|
||||
ld rootsign = 1;
|
||||
// if(gc == gcSphere && vid.alpha > 1) rootsign = -1;
|
||||
// if(gc == gcSphere && pconf.alpha > 1) rootsign = -1;
|
||||
|
||||
ld hz = B / 2 + rootsign * sqrt(C + B*B/4);
|
||||
|
||||
@ -72,7 +72,7 @@ EX hyperpoint perspective_to_space(hyperpoint h, ld alpha IS(vid.alpha), eGeomet
|
||||
return H;
|
||||
}
|
||||
|
||||
EX hyperpoint space_to_perspective(hyperpoint z, ld alpha IS(vid.alpha)) {
|
||||
EX hyperpoint space_to_perspective(hyperpoint z, ld alpha IS(pconf.alpha)) {
|
||||
ld s = 1 / (alpha + z[LDIM]);
|
||||
z[0] *= s;
|
||||
z[1] *= s;
|
||||
@ -88,21 +88,21 @@ EX hyperpoint space_to_perspective(hyperpoint z, ld alpha IS(vid.alpha)) {
|
||||
EX hyperpoint gethyper(ld x, ld y) {
|
||||
|
||||
ld hx = (x - current_display->xcenter) / current_display->radius;
|
||||
ld hy = (y - current_display->ycenter) / current_display->radius / vid.stretch;
|
||||
ld hy = (y - current_display->ycenter) / current_display->radius / pconf.stretch;
|
||||
|
||||
if(pmodel) {
|
||||
ghx = hx, ghy = hy;
|
||||
return ghpm;
|
||||
}
|
||||
|
||||
if(vid.camera_angle) camrotate(hx, hy);
|
||||
if(pconf.camera_angle) camrotate(hx, hy);
|
||||
|
||||
return perspective_to_space(hpxyz(hx, hy, 0));
|
||||
}
|
||||
|
||||
void ballmodel(hyperpoint& ret, double alpha, double d, double zl) {
|
||||
hyperpoint H = ypush(vid.camera) * xpush(d) * ypush(zl) * C0;
|
||||
ld tzh = vid.ballproj + H[LDIM];
|
||||
ld tzh = pconf.ballproj + H[LDIM];
|
||||
ld ax = H[0] / tzh;
|
||||
ld ay = H[1] / tzh;
|
||||
|
||||
@ -165,7 +165,7 @@ ld find_zlev(hyperpoint& H) {
|
||||
}
|
||||
|
||||
ld get_tz(hyperpoint H) {
|
||||
ld tz = vid.alpha+H[LDIM];
|
||||
ld tz = pconf.alpha+H[LDIM];
|
||||
if(tz < BEHIND_LIMIT && tz > -BEHIND_LIMIT) tz = BEHIND_LIMIT;
|
||||
return tz;
|
||||
}
|
||||
@ -237,7 +237,7 @@ void band_conformal(ld& x, ld& y) {
|
||||
}
|
||||
|
||||
void make_twopoint(ld& x, ld& y) {
|
||||
auto p = vid.twopoint_param;
|
||||
auto p = pconf.twopoint_param;
|
||||
ld dleft = hypot_auto(x-p, y);
|
||||
ld dright = hypot_auto(x+p, y);
|
||||
if(sphere) {
|
||||
@ -264,7 +264,7 @@ hyperpoint mobius(hyperpoint h, ld angle, ld scale = 1) {
|
||||
}
|
||||
|
||||
hyperpoint compute_hybrid(hyperpoint H, int rootid) {
|
||||
auto& t = vid.twopoint_param;
|
||||
auto& t = pconf.twopoint_param;
|
||||
hyperpoint Hl = xpush(+t) * H;
|
||||
hyperpoint Hr = xpush(-t) * H;
|
||||
ld g = (Hl[0] + 1e-7) / (Hl[1] + 1e-8);
|
||||
@ -315,11 +315,11 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
|
||||
hyperpoint H_orig = H;
|
||||
|
||||
if(models::product_model()) {
|
||||
if(models::product_model(pmodel)) {
|
||||
ld zlev = zlevel(H);
|
||||
H /= exp(zlev);
|
||||
hybrid::in_underlying_geometry([&] { applymodel(H, ret); });
|
||||
ret[2] = zlev * models::product_z_scale;
|
||||
ret[2] = zlev * pconf.product_z_scale;
|
||||
ret = NLP * ret;
|
||||
return;
|
||||
}
|
||||
@ -337,7 +337,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
}
|
||||
|
||||
case mdGeodesic: {
|
||||
auto S = lp_apply(inverse_exp(H, iTable));
|
||||
auto S = lp_apply(inverse_exp(H, pNORMAL | pfNO_DISTANCE));
|
||||
ld ratio = vid.xres / current_display->tanfov / current_display->radius / 2;
|
||||
ret[0] = S[0]/S[2] * ratio;
|
||||
ret[1] = S[1]/S[2] * ratio;
|
||||
@ -360,23 +360,23 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
|
||||
case mdDisk: {
|
||||
if(nonisotropic) {
|
||||
ret = lp_apply(inverse_exp(H, iTable, true));
|
||||
ret = lp_apply(inverse_exp(H, pNORMAL | pfNO_DISTANCE));
|
||||
ld w;
|
||||
if(sn::in()) {
|
||||
// w = 1 / sqrt(1 - sqhypot_d(3, ret));
|
||||
// w = w / (vid.alpha + w);
|
||||
w = 1 / (sqrt(1 - sqhypot_d(3, ret)) * vid.alpha + 1);
|
||||
// w = w / (pconf.alpha + w);
|
||||
w = 1 / (sqrt(1 - sqhypot_d(3, ret)) * pconf.alpha + 1);
|
||||
}
|
||||
else {
|
||||
w = hypot_d(3, ret);
|
||||
w = sinh(w) / ((vid.alpha + cosh(w)) * w);
|
||||
w = sinh(w) / ((pconf.alpha + cosh(w)) * w);
|
||||
}
|
||||
for(int i=0; i<3; i++) ret[i] *= w;
|
||||
ret[3] = 1;
|
||||
break;
|
||||
}
|
||||
ld tz = get_tz(H);
|
||||
if(!vid.camera_angle) {
|
||||
if(!pconf.camera_angle) {
|
||||
ret[0] = H[0] / tz;
|
||||
ret[1] = H[1] / tz;
|
||||
if(GDIM == 3) ret[2] = H[2] / tz;
|
||||
@ -386,7 +386,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
else {
|
||||
ld tx = H[0];
|
||||
ld ty = H[1];
|
||||
ld cam = vid.camera_angle * degree;
|
||||
ld cam = pconf.camera_angle * degree;
|
||||
GLfloat cc = cos(cam);
|
||||
GLfloat ss = sin(cam);
|
||||
ld ux = tx, uy = ty * cc - ss * tz, uz = tz * cc + ss * ty;
|
||||
@ -400,6 +400,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
case mdCentralInversion: {
|
||||
ld tz = get_tz(H);
|
||||
for(int d=0; d<GDIM; d++) ret[d] = H[d] / tz;
|
||||
for(int d=GDIM; d<MAXMDIM; d++) ret[d] = 1;
|
||||
ld r = 0;
|
||||
for(int d=0; d<GDIM; d++) r += ret[d]*ret[d];
|
||||
for(int d=0; d<GDIM; d++) ret[d] /= r;
|
||||
@ -422,7 +423,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
|
||||
if(GDIM == 3) {
|
||||
// a bit simpler when we do not care about 3D
|
||||
H *= models::halfplane_scale;
|
||||
H *= pconf.halfplane_scale;
|
||||
ret[0] = -H[0];
|
||||
ret[1] = 1 + H[1];
|
||||
ret[2] = H[2];
|
||||
@ -434,7 +435,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
|
||||
models::apply_orientation(H[0], H[1]);
|
||||
|
||||
H *= models::halfplane_scale;
|
||||
H *= pconf.halfplane_scale;
|
||||
|
||||
ret[0] = -models::osin - H[0];
|
||||
if(zlev != 1) {
|
||||
@ -485,14 +486,14 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
|
||||
case gcEuclid: default: {
|
||||
// stereographic projection to a sphere
|
||||
auto hd = hdist0(H) / vid.euclid_to_sphere;
|
||||
auto hd = hdist0(H) / pconf.euclid_to_sphere;
|
||||
if(hd == 0) ret = hpxyz(0, 0, -1);
|
||||
else {
|
||||
ld x = 2 * hd / (1 + hd * hd);
|
||||
ld y = x / hd;
|
||||
ret = H * x / hd / vid.euclid_to_sphere;
|
||||
ret = H * x / hd / pconf.euclid_to_sphere;
|
||||
ret[2] = (1 - y);
|
||||
ret = ret * (1 + (H[2]-1) * y / vid.euclid_to_sphere);
|
||||
ret = ret * (1 + (H[2]-1) * y / pconf.euclid_to_sphere);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -523,7 +524,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
break;
|
||||
}
|
||||
if(pmodel == mdHyperboloid) {
|
||||
ld& topz = models::top_z;
|
||||
ld& topz = pconf.top_z;
|
||||
if(H[2] > topz) {
|
||||
ld scale = sqrt(topz*topz-1) / hypot_d(2, H);
|
||||
H *= scale;
|
||||
@ -531,8 +532,8 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
H = space_to_perspective(H, vid.alpha);
|
||||
H[2] = 1 - vid.alpha;
|
||||
H = space_to_perspective(H, pconf.alpha);
|
||||
H[2] = 1 - pconf.alpha;
|
||||
}
|
||||
|
||||
ret[0] = H[0] / 3;
|
||||
@ -546,14 +547,14 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
case mdFisheye: {
|
||||
ld zlev;
|
||||
if(nonisotropic) {
|
||||
H = lp_apply(inverse_exp(H, iTable, false));
|
||||
H = lp_apply(inverse_exp(H));
|
||||
zlev = 1;
|
||||
}
|
||||
else {
|
||||
zlev = find_zlev(H);
|
||||
H = space_to_perspective(H);
|
||||
}
|
||||
H /= vid.fisheye_param;
|
||||
H /= pconf.fisheye_param;
|
||||
H[LDIM] = zlev;
|
||||
ret = H / sqrt(1 + sqhypot_d(GDIM+1, H));
|
||||
if(GDIM == 3) ret[LDIM] = zlev;
|
||||
@ -564,8 +565,8 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
models::apply_orientation_yz(H[1], H[2]);
|
||||
models::apply_orientation(H[0], H[1]);
|
||||
auto yz = move_z_to_y(H);
|
||||
hyperpoint Hl = xpush(-vid.twopoint_param) * H;
|
||||
hyperpoint Hr = xpush(+vid.twopoint_param) * H;
|
||||
hyperpoint Hl = xpush(-pconf.twopoint_param) * H;
|
||||
hyperpoint Hr = xpush(+pconf.twopoint_param) * H;
|
||||
ld lyx = (Hl[1] + 1e-7) / (Hl[0] + 1e-8);
|
||||
ld ryx = (Hr[1] + 1e-7) / (Hr[0] + 1e-8);
|
||||
// (r.x + t) * lyx = (r.x - t) * ryx = r.y
|
||||
@ -574,8 +575,8 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
// r.x = -t * (ryx+lyx) / (lyx-ryx)
|
||||
// r.x = - 2 * t * lyx * ryx / lyx / ryx
|
||||
|
||||
ret[0] = -vid.twopoint_param * (ryx + lyx) / (lyx - ryx);
|
||||
ret[1] = (ret[0] + vid.twopoint_param) * lyx;
|
||||
ret[0] = -pconf.twopoint_param * (ryx + lyx) / (lyx - ryx);
|
||||
ret[1] = (ret[0] + pconf.twopoint_param) * lyx;
|
||||
ret[2] = 0;
|
||||
|
||||
move_y_to_z(ret, yz);
|
||||
@ -603,11 +604,11 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
models::apply_orientation(H[0], H[1]);
|
||||
// with equal speed skiprope: models::apply_orientation(H[1], H[0]);
|
||||
|
||||
if(vid.skiprope) {
|
||||
if(pconf.skiprope) {
|
||||
static ld last_skiprope = 0;
|
||||
static transmatrix lastmatrix;
|
||||
if(vid.skiprope != last_skiprope) {
|
||||
ret = mobius(C0, -vid.skiprope, 2);
|
||||
if(pconf.skiprope != last_skiprope) {
|
||||
ret = mobius(C0, -pconf.skiprope, 2);
|
||||
const cld c1(1, 0);
|
||||
const cld c2(2, 0);
|
||||
const cld c4(4, 0);
|
||||
@ -617,7 +618,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
hyperpoint zr = hpxyz(real(z), imag(z), 0);
|
||||
|
||||
hyperpoint inhyp = perspective_to_space(zr, 1, gcHyperbolic);
|
||||
last_skiprope = vid.skiprope;
|
||||
last_skiprope = pconf.skiprope;
|
||||
lastmatrix = rgpushxto0(inhyp);
|
||||
}
|
||||
H = lastmatrix * H;
|
||||
@ -628,7 +629,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
ld r = hypot_d(2, H);
|
||||
ld c = H[0] / r;
|
||||
ld s = H[1] / r;
|
||||
ld& mt = models::model_transition;
|
||||
ld& mt = pconf.model_transition;
|
||||
ld a = 1 - .5 * mt, b = .5 * mt;
|
||||
swap(a, b);
|
||||
|
||||
@ -636,8 +637,8 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
ret[1] = (a * r - b/r) * s / 2;
|
||||
ret[2] = 0;
|
||||
|
||||
if(vid.skiprope)
|
||||
ret = mobius(ret, vid.skiprope, 2);
|
||||
if(pconf.skiprope)
|
||||
ret = mobius(ret, pconf.skiprope, 2);
|
||||
|
||||
if(pmodel == mdJoukowskyInverted) {
|
||||
ld r2 = sqhypot_d(2, ret);
|
||||
@ -681,8 +682,8 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
}
|
||||
|
||||
case mdBand:
|
||||
if(models::model_transition != 1) {
|
||||
ld& mt = models::model_transition;
|
||||
if(pconf.model_transition != 1) {
|
||||
ld& mt = pconf.model_transition;
|
||||
|
||||
H = space_to_perspective(H);
|
||||
|
||||
@ -745,10 +746,10 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
find_zlev(H);
|
||||
makeband(H, ret, [] (ld& x, ld& y) {
|
||||
ld sgn = 1;
|
||||
if(vid.collignon_reflected && y > 0) y = -y, sgn = -1;
|
||||
y = signed_sqrt(sin_auto(y) + vid.collignon_parameter);
|
||||
if(pconf.collignon_reflected && y > 0) y = -y, sgn = -1;
|
||||
y = signed_sqrt(sin_auto(y) + pconf.collignon_parameter);
|
||||
x *= y / 1.2;
|
||||
y -= signed_sqrt(vid.collignon_parameter);
|
||||
y -= signed_sqrt(pconf.collignon_parameter);
|
||||
y *= sgn;
|
||||
y *= M_PI;
|
||||
});
|
||||
@ -768,7 +769,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
|
||||
case mdEquidistant: case mdEquiarea: case mdEquivolume: {
|
||||
if(nonisotropic || prod) {
|
||||
ret = lp_apply(inverse_exp(H, iTable, false));
|
||||
ret = lp_apply(inverse_exp(H));
|
||||
ret[3] = 1;
|
||||
break;
|
||||
}
|
||||
@ -813,7 +814,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
ret[1] = cosh(x) * factor;
|
||||
ret[2] = 0;
|
||||
|
||||
if(models::use_atan) {
|
||||
if(pconf.use_atan) {
|
||||
ret[0] = atan(ret[0]);
|
||||
ret[1] = atan(ret[1]);
|
||||
}
|
||||
@ -822,7 +823,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
}
|
||||
|
||||
case mdFormula: {
|
||||
dynamicval<eModel> m(pmodel, models::basic_model);
|
||||
dynamicval<eModel> m(pmodel, pconf.basic_model);
|
||||
applymodel(H, ret);
|
||||
exp_parser ep;
|
||||
ep.extra_params["z"] = cld(ret[0], ret[1]);
|
||||
@ -832,7 +833,7 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
ep.extra_params["ux"] = H[0];
|
||||
ep.extra_params["uy"] = H[1];
|
||||
ep.extra_params["uz"] = H[2];
|
||||
ep.s = models::formula;
|
||||
ep.s = pconf.formula;
|
||||
cld res;
|
||||
try {
|
||||
res = ep.parse();
|
||||
@ -852,15 +853,15 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
else ret = H;
|
||||
z = cld(ret[0], ret[1]) * models::spiral_multiplier;
|
||||
|
||||
if(models::spiral_cone < 360) {
|
||||
ld alpha = imag(z) * 360 / models::spiral_cone;
|
||||
if(pconf.spiral_cone < 360) {
|
||||
ld alpha = imag(z) * 360 / pconf.spiral_cone;
|
||||
ld r = real(z);
|
||||
r = exp(r);
|
||||
|
||||
ret[0] = -sin(alpha) * r;
|
||||
ret[1] = cos(alpha) * r;
|
||||
if(euclid) ret = models::euclidean_spin * ret;
|
||||
ret[2] = (r-1) * sqrt( pow(360/models::spiral_cone, 2) - 1);
|
||||
ret[2] = (r-1) * sqrt( pow(360/pconf.spiral_cone, 2) - 1);
|
||||
|
||||
models::apply_ball(ret[2], ret[1]);
|
||||
}
|
||||
@ -870,8 +871,8 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) {
|
||||
ret[1] = imag(z);
|
||||
if(euclid) ret = models::euclidean_spin * ret;
|
||||
|
||||
if(vid.skiprope)
|
||||
ret = mobius(ret, vid.skiprope, 1);
|
||||
if(pconf.skiprope)
|
||||
ret = mobius(ret, pconf.skiprope, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -929,12 +930,12 @@ EX bool behindsphere(const hyperpoint& h) {
|
||||
|
||||
if(mdBandAny()) return false;
|
||||
|
||||
if(vid.alpha > 1) {
|
||||
if(h[LDIM] > -1/vid.alpha) return true;
|
||||
if(pconf.alpha > 1) {
|
||||
if(h[LDIM] > -1/pconf.alpha) return true;
|
||||
}
|
||||
|
||||
if(vid.alpha <= 1) {
|
||||
if(h[LDIM] < .2-vid.alpha) return true;
|
||||
if(pconf.alpha <= 1) {
|
||||
if(h[LDIM] < .2-pconf.alpha) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -949,11 +950,11 @@ ld to01(ld a0, ld a1, ld x) {
|
||||
EX ld spherity(const hyperpoint& h) {
|
||||
if(!sphere) return 1;
|
||||
|
||||
if(vid.alpha > 1) {
|
||||
return to01(1/vid.alpha, 1, abs(h[2]));
|
||||
if(pconf.alpha > 1) {
|
||||
return to01(1/pconf.alpha, 1, abs(h[2]));
|
||||
}
|
||||
|
||||
if(vid.alpha <= 1) {
|
||||
if(pconf.alpha <= 1) {
|
||||
return to01(-1.5, 1, h[2]);
|
||||
}
|
||||
|
||||
@ -1002,7 +1003,7 @@ EX transmatrix actualV(const heptspin& hs, const transmatrix& V) {
|
||||
EX bool point_behind(hyperpoint h) {
|
||||
if(sphere) return false;
|
||||
if(!in_perspective()) return false;
|
||||
if(pmodel == mdGeodesic) h = inverse_exp(h, iLazy);
|
||||
if(pmodel == mdGeodesic) h = inverse_exp(h, pQUICK);
|
||||
if(pmodel == mdPerspective && prod) h = product::inverse_exp(h);
|
||||
h = lp_apply(h);
|
||||
return h[2] < 1e-8;
|
||||
@ -1039,15 +1040,15 @@ EX bool in_smart_range(const transmatrix& T) {
|
||||
applymodel(h, h1);
|
||||
if(invalid_point(h1)) return false;
|
||||
ld x = current_display->xcenter + current_display->radius * h1[0];
|
||||
ld y = current_display->ycenter + current_display->radius * h1[1] * vid.stretch;
|
||||
ld y = current_display->ycenter + current_display->radius * h1[1] * pconf.stretch;
|
||||
|
||||
if(x > current_display->xtop + current_display->xsize * 2) return false;
|
||||
if(x < current_display->xtop - current_display->xsize * 1) return false;
|
||||
if(y > current_display->ytop + current_display->ysize * 2) return false;
|
||||
if(y < current_display->ytop - current_display->ysize * 1) return false;
|
||||
if(GDIM == 3) {
|
||||
if(-h1[2] < models::clip_min * 2 - models::clip_max) return false;
|
||||
if(-h1[2] > models::clip_max * 2 - models::clip_min) return false;
|
||||
if(-h1[2] < pconf.clip_min * 2 - pconf.clip_max) return false;
|
||||
if(-h1[2] > pconf.clip_max * 2 - pconf.clip_min) return false;
|
||||
}
|
||||
|
||||
ld epsilon = 0.01;
|
||||
@ -1057,14 +1058,14 @@ EX bool in_smart_range(const transmatrix& T) {
|
||||
hyperpoint h2;
|
||||
applymodel(T * cpush0(i, epsilon), h2);
|
||||
ld x1 = current_display->radius * abs(h2[0] - h1[0]) / epsilon;
|
||||
ld y1 = current_display->radius * abs(h2[1] - h1[1]) * vid.stretch / epsilon;
|
||||
ld y1 = current_display->radius * abs(h2[1] - h1[1]) * pconf.stretch / epsilon;
|
||||
dx = max(dx, x1); dy = max(dy, y1);
|
||||
if(GDIM == 3) dz = max(dz, abs(h2[2] - h1[2]));
|
||||
dh[i] = hypot(x1, y1);
|
||||
}
|
||||
|
||||
if(GDIM == 3) {
|
||||
if(-h1[2] + 2 * dz < models::clip_min || -h1[2] - 2 * dz > models::clip_max) return false;
|
||||
if(-h1[2] + 2 * dz < pconf.clip_min || -h1[2] - 2 * dz > pconf.clip_max) return false;
|
||||
sort(dh, dh+GDIM);
|
||||
ld scale = sqrt(dh[1] * dh[2]) * cgi.scalefactor * hcrossf7;
|
||||
if(scale <= (WDIM == 2 ? vid.smart_range_detail : vid.smart_range_detail_3)) return false;
|
||||
@ -1191,7 +1192,7 @@ void hrmap_standard::draw() {
|
||||
if(sphere && pmodel == mdSpiral && !in_multi) {
|
||||
in_multi = true;
|
||||
if(models::ring_not_spiral) {
|
||||
int qty = ceil(1. / models::sphere_spiral_multiplier);
|
||||
int qty = ceil(1. / pconf.sphere_spiral_multiplier);
|
||||
if(qty > 100) qty = 100;
|
||||
for(int i=-qty; i < qty; i++) {
|
||||
band_shift = 2 * M_PI * i;
|
||||
@ -1505,8 +1506,8 @@ EX void fullcenter() {
|
||||
|
||||
transmatrix screenpos(ld x, ld y) {
|
||||
transmatrix V = Id;
|
||||
V[0][2] += (x - current_display->xcenter) / current_display->radius * (1+vid.alpha);
|
||||
V[1][2] += (y - current_display->ycenter) / current_display->radius * (1+vid.alpha);
|
||||
V[0][2] += (x - current_display->xcenter) / current_display->radius * (1+pconf.alpha);
|
||||
V[1][2] += (y - current_display->ycenter) / current_display->radius * (1+pconf.alpha);
|
||||
return V;
|
||||
}
|
||||
|
||||
@ -1517,6 +1518,27 @@ transmatrix screenpos(ld x, ld y) {
|
||||
|
||||
EX eModel flat_model() { return MDIM == 4 ? mdPixel : mdDisk; }
|
||||
|
||||
/** \brief enable the 'flat' model for drawing HUD. See hr::flat_model_enabler */
|
||||
EX void enable_flat_model() {
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
pmodel = flat_model();
|
||||
pconf.alpha = 1;
|
||||
pconf.scale = 1;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.stretch = 1;
|
||||
if(prod) pconf.alpha = 30, pconf.scale = 30;
|
||||
calcparam();
|
||||
}
|
||||
|
||||
#if HDR
|
||||
/** \brief enable the 'flat' model for drawing HUD. Use RAII so it will be switched back later */
|
||||
struct flat_model_enabler {
|
||||
projection_configuration bak;
|
||||
flat_model_enabler() { bak = pconf; enable_flat_model(); }
|
||||
~flat_model_enabler() { pconf = bak; calcparam(); }
|
||||
};
|
||||
#endif
|
||||
|
||||
EX transmatrix atscreenpos(ld x, ld y, ld size) {
|
||||
transmatrix V = Id;
|
||||
|
||||
@ -1541,7 +1563,7 @@ EX transmatrix atscreenpos(ld x, ld y, ld size) {
|
||||
|
||||
void circle_around_center(ld radius, color_t linecol, color_t fillcol, PPR prio) {
|
||||
#if CAP_QUEUE
|
||||
if(among(pmodel, mdDisk, mdEquiarea, mdEquidistant, mdFisheye) && !(pmodel == mdDisk && hyperbolic && vid.alpha <= -1) && vid.camera_angle == 0) {
|
||||
if(among(pmodel, mdDisk, mdEquiarea, mdEquidistant, mdFisheye) && !(pmodel == mdDisk && hyperbolic && pconf.alpha <= -1) && pconf.camera_angle == 0) {
|
||||
hyperpoint ret;
|
||||
applymodel(xpush0(radius), ret);
|
||||
ld r = hypot_d(2, ret);
|
||||
@ -1552,7 +1574,7 @@ void circle_around_center(ld radius, color_t linecol, color_t fillcol, PPR prio)
|
||||
#if CAP_QUEUE
|
||||
for(int i=0; i<=360; i++) curvepoint(xspinpush0(i * degree, 10));
|
||||
auto& c = queuecurve(linecol, fillcol, prio);
|
||||
if(pmodel == mdDisk && hyperbolic && vid.alpha <= -1)
|
||||
if(pmodel == mdDisk && hyperbolic && pconf.alpha <= -1)
|
||||
c.flags |= POLY_FORCE_INVERTED;
|
||||
if(pmodel == mdJoukowsky)
|
||||
c.flags |= POLY_FORCE_INVERTED;
|
||||
@ -1571,7 +1593,7 @@ EX void draw_model_elements() {
|
||||
switch(pmodel) {
|
||||
|
||||
case mdRotatedHyperboles: {
|
||||
queuestr(current_display->xcenter, current_display->ycenter + current_display->radius * vid.alpha, 0, vid.fsize, "X", ringcolor, 1, 8);
|
||||
queuestr(current_display->xcenter, current_display->ycenter + current_display->radius * pconf.alpha, 0, vid.fsize, "X", ringcolor, 1, 8);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1581,11 +1603,11 @@ EX void draw_model_elements() {
|
||||
for(int mode=0; mode<4; mode++) {
|
||||
for(int s=-200; s<=200; s ++) {
|
||||
ld p = tanh(s / 40.);
|
||||
ld a = vid.twopoint_param * (1+p);
|
||||
ld b = vid.twopoint_param * (1-p);
|
||||
ld a = pconf.twopoint_param * (1+p);
|
||||
ld b = pconf.twopoint_param * (1-p);
|
||||
ld h = ((mode & 2) ? -1 : 1) * sqrt(asin_auto(tan_auto(a) * tan_auto(b)));
|
||||
|
||||
hyperpoint H = xpush(p * vid.twopoint_param) * ypush0(h);
|
||||
hyperpoint H = xpush(p * pconf.twopoint_param) * ypush0(h);
|
||||
|
||||
hyperpoint res = compute_hybrid(H, 2 | mode);
|
||||
models::apply_orientation(res[0], res[1]);
|
||||
@ -1600,9 +1622,9 @@ EX void draw_model_elements() {
|
||||
}
|
||||
|
||||
case mdTwoPoint: case mdSimulatedPerspective: {
|
||||
ld a = -models::model_orientation * degree;
|
||||
queuestr(xspinpush0(a, +vid.twopoint_param), vid.xres / 100, "X", ringcolor >> 8);
|
||||
queuestr(xspinpush0(a, -vid.twopoint_param), vid.xres / 100, "X", ringcolor >> 8);
|
||||
ld a = -pconf.model_orientation * degree;
|
||||
queuestr(xspinpush0(a, +pconf.twopoint_param), vid.xres / 100, "X", ringcolor >> 8);
|
||||
queuestr(xspinpush0(a, -pconf.twopoint_param), vid.xres / 100, "X", ringcolor >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1616,10 +1638,10 @@ EX void draw_model_elements() {
|
||||
if(hyperbolic) {
|
||||
#if CAP_QUEUE
|
||||
curvepoint(point3(0,0,1));
|
||||
curvepoint(point3(0,0,-vid.alpha));
|
||||
curvepoint(point3(0,0,-pconf.alpha));
|
||||
queuecurve(ringcolor, 0, PPR::CIRCLE);
|
||||
|
||||
ld& tz = models::top_z;
|
||||
ld& tz = pconf.top_z;
|
||||
ld z = acosh(tz);
|
||||
|
||||
hyperpoint a = xpush0(z);
|
||||
@ -1629,12 +1651,12 @@ EX void draw_model_elements() {
|
||||
a[1] = sb * a[2] / -cb;
|
||||
a[0] = sqrt(-1 + a[2] * a[2] - a[1] * a[1]);
|
||||
|
||||
curvepoint(point3(0,0,-vid.alpha));
|
||||
curvepoint(point3(0,0,-pconf.alpha));
|
||||
curvepoint(a);
|
||||
curvepoint(point3(0,0,0));
|
||||
a[0] = -a[0];
|
||||
curvepoint(a);
|
||||
curvepoint(point3(0,0,-vid.alpha));
|
||||
curvepoint(point3(0,0,-pconf.alpha));
|
||||
queuecurve(ringcolor, 0, PPR::CIRCLE);
|
||||
|
||||
curvepoint(point3(-1,0,0));
|
||||
@ -1643,10 +1665,10 @@ EX void draw_model_elements() {
|
||||
|
||||
a[1] = sb * tz / -cb;
|
||||
a[0] = sqrt(tz * tz - a[1] * a[1]);
|
||||
a[2] = tz - vid.alpha;
|
||||
a[2] = tz - pconf.alpha;
|
||||
|
||||
curvepoint(a);
|
||||
curvepoint(point3(0,0,-vid.alpha));
|
||||
curvepoint(point3(0,0,-pconf.alpha));
|
||||
a[0] = -a[0];
|
||||
curvepoint(a);
|
||||
queuecurve(ringcolor, 0, PPR::CIRCLE);
|
||||
@ -1727,7 +1749,7 @@ EX void draw_boundary(int w) {
|
||||
|
||||
for(int b=-1; b<=1; b+=2)
|
||||
for(ld a=-90; a<=90+1e-6; a+=pow(.5, vid.linequality)) {
|
||||
ld x = sin(a * vid.twopoint_param * b / 90);
|
||||
ld x = sin(a * pconf.twopoint_param * b / 90);
|
||||
ld y = 0;
|
||||
ld z = -sqrt(1 - x*x);
|
||||
models::apply_orientation(y, x);
|
||||
@ -1747,9 +1769,9 @@ EX void draw_boundary(int w) {
|
||||
|
||||
case mdBand: case mdBandEquidistant: case mdBandEquiarea: case mdSinusoidal: case mdMollweide: case mdCentralCyl: case mdCollignon: {
|
||||
if(GDIM == 3) return;
|
||||
if(pmodel == mdBand && models::model_transition != 1) return;
|
||||
if(pmodel == mdBand && pconf.model_transition != 1) return;
|
||||
bool bndband = (among(pmodel, mdBand, mdCentralCyl) ? hyperbolic : sphere);
|
||||
transmatrix T = spin(-models::model_orientation * degree);
|
||||
transmatrix T = spin(-pconf.model_orientation * degree);
|
||||
ld right = M_PI/2 - 1e-5;
|
||||
if(bndband)
|
||||
queuestraight(T * ypush0(hyperbolic ? 10 : right), 2, lc, fc, p);
|
||||
@ -1773,7 +1795,7 @@ EX void draw_boundary(int w) {
|
||||
|
||||
case mdHalfplane:
|
||||
if(hyperbolic && GDIM == 2) {
|
||||
queuestraight(xspinpush0(-models::model_orientation * degree - M_PI/2, fakeinf), 1, lc, fc, p);
|
||||
queuestraight(xspinpush0(-pconf.model_orientation * degree - M_PI/2, fakeinf), 1, lc, fc, p);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -1810,7 +1832,7 @@ EX void draw_boundary(int w) {
|
||||
|
||||
case mdHyperboloid: {
|
||||
if(hyperbolic) {
|
||||
ld& tz = models::top_z;
|
||||
ld& tz = pconf.top_z;
|
||||
ld mz = acosh(tz);
|
||||
ld cb = models::cos_ball;
|
||||
ld sb = models::sin_ball;
|
||||
@ -1871,7 +1893,7 @@ EX void draw_boundary(int w) {
|
||||
for(ld a=-10; a<=10; a+=0.01 / (1 << vid.linequality) / u) {
|
||||
cld z = exp(cld(a, a * imag(sm) / real(sm) + M_PI));
|
||||
hyperpoint ret = point2(real(z), imag(z));
|
||||
ret = mobius(ret, vid.skiprope, 1);
|
||||
ret = mobius(ret, pconf.skiprope, 1);
|
||||
ret *= current_display->radius;
|
||||
curvepoint(ret);
|
||||
}
|
||||
@ -1884,8 +1906,8 @@ EX void draw_boundary(int w) {
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(sphere && pmodel == mdDisk && vid.alpha > 1) {
|
||||
double rad = current_display->radius / sqrt(vid.alpha*vid.alpha - 1);
|
||||
if(sphere && pmodel == mdDisk && pconf.alpha > 1) {
|
||||
double rad = current_display->radius / sqrt(pconf.alpha*pconf.alpha - 1);
|
||||
queuecircle(current_display->xcenter, current_display->ycenter, rad, lc, p, fc);
|
||||
return;
|
||||
}
|
||||
@ -1898,7 +1920,7 @@ EX void draw_boundary(int w) {
|
||||
EX ld band_shift = 0;
|
||||
EX void fix_the_band(transmatrix& T) {
|
||||
if(((mdinf[pmodel].flags & mf::uses_bandshift) && T[LDIM][LDIM] > 1e6) || (sphere && pmodel == mdSpiral)) {
|
||||
T = spin(models::model_orientation * degree) * T;
|
||||
T = spin(pconf.model_orientation * degree) * T;
|
||||
hyperpoint H = tC0(T);
|
||||
find_zlev(H);
|
||||
|
||||
@ -1911,7 +1933,7 @@ EX void fix_the_band(transmatrix& T) {
|
||||
band_shift += x;
|
||||
T = xpush(-x) * T;
|
||||
fixmatrix(T);
|
||||
T = spin(-models::model_orientation * degree) * T;
|
||||
T = spin(-pconf.model_orientation * degree) * T;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1995,7 +2017,7 @@ EX bool do_draw(cell *c, const transmatrix& T) {
|
||||
if(cells_drawn > vid.cells_drawn_limit) return false;
|
||||
if(cells_drawn < 50) { limited_generation(c); return true; }
|
||||
if(nil && pmodel == mdGeodesic) {
|
||||
ld dist = hypot_d(3, inverse_exp(tC0(T), iLazy));
|
||||
ld dist = hypot_d(3, inverse_exp(tC0(T), pQUICK));
|
||||
if(dist > sightranges[geometry] + (vid.sloppy_3d ? 0 : 0.9)) return false;
|
||||
if(dist <= extra_generation_distance && !limited_generation(c)) return false;
|
||||
}
|
||||
@ -2004,7 +2026,7 @@ EX bool do_draw(cell *c, const transmatrix& T) {
|
||||
if(!limited_generation(c)) return false;
|
||||
}
|
||||
else if(pmodel == mdGeodesic && nih) {
|
||||
hyperpoint h = inverse_exp(tC0(T), iLazy, false);
|
||||
hyperpoint h = inverse_exp(tC0(T), pQUICK);
|
||||
ld dist = hypot_d(3, h);
|
||||
if(dist > sightranges[geometry] + (vid.sloppy_3d ? 0 : cgi.corner_bonus)) return false;
|
||||
if(dist <= extra_generation_distance && !limited_generation(c)) return false;
|
||||
@ -2056,7 +2078,7 @@ EX int cone_side(const hyperpoint H) {
|
||||
cld z = cld(ret[0], ret[1]) * models::spiral_multiplier;
|
||||
|
||||
auto zth = [&] (cld z) {
|
||||
ld alpha = imag(z) * 360 / models::spiral_cone;
|
||||
ld alpha = imag(z) * 360 / pconf.spiral_cone;
|
||||
ld r = real(z);
|
||||
r = exp(r);
|
||||
|
||||
@ -2064,7 +2086,7 @@ EX int cone_side(const hyperpoint H) {
|
||||
|
||||
ret[0] = -sin(alpha) * r;
|
||||
ret[1] = cos(alpha) * r;
|
||||
ret[2] = (r-1) * sqrt( pow(360/models::spiral_cone, 2) - 1);
|
||||
ret[2] = (r-1) * sqrt( pow(360/pconf.spiral_cone, 2) - 1);
|
||||
|
||||
models::apply_ball(ret[2], ret[1]);
|
||||
return ret;
|
||||
@ -2096,7 +2118,7 @@ EX void rotate_view(transmatrix T) {
|
||||
/** shift the view according to the given tangent vector */
|
||||
EX transmatrix get_shift_view_of(const hyperpoint H, const transmatrix V) {
|
||||
if(!nonisotropic) {
|
||||
return rgpushxto0(direct_exp(lp_iapply(H), 100)) * V;
|
||||
return rgpushxto0(direct_exp(lp_iapply(H))) * V;
|
||||
}
|
||||
else if(!nisot::geodesic_movement) {
|
||||
transmatrix IV = inverse(V);
|
||||
@ -2132,7 +2154,7 @@ void multiply_view(transmatrix T) {
|
||||
|
||||
EX void shift_view_to(hyperpoint H) {
|
||||
if(!nonisotropic) multiply_view(gpushxto0(H));
|
||||
else shift_view(-inverse_exp(H, iTable, false));
|
||||
else shift_view(-inverse_exp(H));
|
||||
}
|
||||
|
||||
EX void shift_view_towards(hyperpoint H, ld l) {
|
||||
@ -2141,7 +2163,7 @@ EX void shift_view_towards(hyperpoint H, ld l) {
|
||||
else if(nonisotropic && !nisot::geodesic_movement)
|
||||
shift_view(tangent_length(H-C0, -l));
|
||||
else {
|
||||
hyperpoint ie = inverse_exp(H, iTable, true);
|
||||
hyperpoint ie = inverse_exp(H, pNORMAL | pfNO_DISTANCE);
|
||||
if(prod) ie = lp_apply(ie);
|
||||
shift_view(tangent_length(ie, -l));
|
||||
}
|
||||
|
@ -513,14 +513,7 @@ EX namespace inv {
|
||||
int j = 0, oc = 6;
|
||||
|
||||
if(1) {
|
||||
dynamicval<eModel> pm(pmodel, flat_model());
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
// dynamicval<videopar> v(vid, vid);
|
||||
// vid.alpha = vid.scale = 1;
|
||||
dynamicval<ld> va(vid.alpha, 1);
|
||||
dynamicval<ld> vs(vid.scale, 1);
|
||||
dynamicval<ld> vc(vid.camera_angle, 0);
|
||||
calcparam();
|
||||
flat_model_enabler fme;
|
||||
|
||||
for(int i=0; i<ittypes; i++) {
|
||||
eItem o = eItem(i);
|
||||
@ -689,7 +682,7 @@ EX namespace inv {
|
||||
|
||||
#if CAP_SAVE
|
||||
EX void applyBox(eItem it) {
|
||||
scores::applyBoxNum(inv::usedup[it]);
|
||||
scores::applyBoxNum(inv::usedup[it], "@inv-" + dnameof(it));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1054,8 +1054,11 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
break;
|
||||
|
||||
case laCA:
|
||||
if(fargen)
|
||||
if(fargen) {
|
||||
c->wall = (hrand(1000000) < ca::prob * 1000000) ? ca::wlive : waNone;
|
||||
if(c->wall == ca::wlive)
|
||||
ca::list_adj(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case laLivefjord:
|
||||
|
@ -49,7 +49,7 @@ void loadOldConfig(FILE *f) {
|
||||
float a, b, c, d;
|
||||
err=fscanf(f, "%f%f%f%f\n", &a, &b, &c, &d);
|
||||
if(err == 4) {
|
||||
vid.scale = a; vid.alpha = c; vid.sspeed = d;
|
||||
vid.scale = a; pconf.alpha = c; vid.sspeed = d;
|
||||
}
|
||||
err=fscanf(f, "%d%d%d%d%d%d%d", &vid.wallmode, &vid.monmode, &vid.axes, &musicvolume, &vid.framelimit, &gl, &vid.antialias);
|
||||
vid.usingGL = gl;
|
||||
|
479
mapeditor.cpp
479
mapeditor.cpp
@ -10,12 +10,241 @@ namespace hr {
|
||||
|
||||
EX namespace mapeditor {
|
||||
|
||||
EX bool drawing_tool;
|
||||
|
||||
#if HDR
|
||||
enum eShapegroup { sgPlayer, sgMonster, sgItem, sgFloor, sgWall };
|
||||
static const int USERSHAPEGROUPS = 5;
|
||||
#endif
|
||||
|
||||
EX color_t dtfill = 0;
|
||||
EX color_t dtcolor = 0x000000FF;
|
||||
EX ld dtwidth = .02;
|
||||
|
||||
hyperpoint lstart;
|
||||
/* drawing_tool shapes */
|
||||
struct dtshape {
|
||||
cell *where;
|
||||
color_t col, fill;
|
||||
ld lw;
|
||||
|
||||
virtual void rotate(const transmatrix& T) = 0;
|
||||
virtual void save(hstream& hs) = 0;
|
||||
virtual dtshape* load(hstream& hs) = 0;
|
||||
virtual void draw(const transmatrix& V) = 0;
|
||||
virtual ld distance(hyperpoint h) = 0;
|
||||
virtual ~dtshape() {}
|
||||
};
|
||||
|
||||
struct dtline : dtshape {
|
||||
|
||||
hyperpoint s, e;
|
||||
|
||||
void rotate(const transmatrix& T) override {
|
||||
s = T * s;
|
||||
e = T * e;
|
||||
}
|
||||
void save(hstream& hs) override {
|
||||
hs.write<char>(1);
|
||||
hs.write(s);
|
||||
hs.write(e);
|
||||
}
|
||||
dtshape *load(hstream& hs) override {
|
||||
hs.read(s);
|
||||
hs.read(e);
|
||||
return this;
|
||||
}
|
||||
void draw(const transmatrix& V) override {
|
||||
queueline(V*s, V*e, col, 2 + vid.linequality);
|
||||
}
|
||||
ld distance(hyperpoint h) override {
|
||||
return hdist(s, h) + hdist(e, h) - hdist(s, e);
|
||||
}
|
||||
};
|
||||
|
||||
struct dtcircle : dtshape {
|
||||
|
||||
hyperpoint s; ld radius;
|
||||
|
||||
void rotate(const transmatrix& T) override {
|
||||
s = T * s;
|
||||
}
|
||||
void save(hstream& hs) override {
|
||||
hs.write<char>(2);
|
||||
hs.write(s);
|
||||
hs.write(radius);
|
||||
}
|
||||
dtshape *load(hstream& hs) override {
|
||||
hs.read(s);
|
||||
hs.read(radius);
|
||||
return this;
|
||||
}
|
||||
void draw(const transmatrix& V) override {
|
||||
ld len = sin_auto(radius);
|
||||
int ll = ceil(360 * len);
|
||||
transmatrix W = V * rgpushxto0(s);
|
||||
for(int i=0; i<=ll; i++)
|
||||
curvepoint(W * xspinpush0(360*degree*i/ll, radius));
|
||||
queuecurve(col, fill, PPR::LINE);
|
||||
}
|
||||
|
||||
ld distance(hyperpoint h) override {
|
||||
return abs(hdist(s, h) - radius);
|
||||
}
|
||||
};
|
||||
|
||||
struct dtfree : dtshape {
|
||||
|
||||
vector<hyperpoint> lh;
|
||||
|
||||
void rotate(const transmatrix& T) override {
|
||||
for(auto& h: lh) h = T * h;
|
||||
}
|
||||
void save(hstream& hs) override {
|
||||
hs.write<char>(3);
|
||||
hs.write(lh);
|
||||
}
|
||||
dtshape *load(hstream& hs) override {
|
||||
hs.read(lh);
|
||||
return this;
|
||||
}
|
||||
void draw(const transmatrix& V) override {
|
||||
for(auto& p: lh) curvepoint(V*p);
|
||||
queuecurve(col, fill, PPR::LINE);
|
||||
}
|
||||
|
||||
ld distance(hyperpoint h) override {
|
||||
ld mind = 99;
|
||||
for(auto h1: lh) mind = min(mind, hdist(h, h1));
|
||||
return mind;
|
||||
}
|
||||
};
|
||||
|
||||
vector<unique_ptr<dtshape>> dtshapes;
|
||||
|
||||
EX void draw_dtshapes() {
|
||||
for(auto& shp: dtshapes) {
|
||||
if(shp == nullptr) continue;
|
||||
auto& sh = *shp;
|
||||
cell*& c = sh.where;
|
||||
for(const transmatrix& V: current_display->all_drawn_copies[c]) {
|
||||
dynamicval<ld> lw(vid.linewidth, vid.linewidth * sh.lw);
|
||||
sh.draw(V);
|
||||
}
|
||||
}
|
||||
|
||||
if(drawing_tool && (cmode & sm::DRAW)) {
|
||||
dynamicval<ld> lw(vid.linewidth, vid.linewidth * dtwidth * 100);
|
||||
if(holdmouse && mousekey == 'c')
|
||||
queue_hcircle(rgpushxto0(lstart), hdist(lstart, mouseh));
|
||||
else if(holdmouse && mousekey == 'l')
|
||||
queueline(lstart, mouseh, dtcolor, 4 + vid.linequality, PPR::LINE);
|
||||
else if(!holdmouse) {
|
||||
transmatrix T = rgpushxto0(mouseh);
|
||||
queueline(T * xpush0(-.1), T * xpush0(.1), dtcolor);
|
||||
queueline(T * ypush0(-.1), T * ypush0(.1), dtcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** dtshapes takes ownership of sh */
|
||||
void dt_add(cell *where, dtshape *sh) {
|
||||
sh->where = where;
|
||||
sh->col = dtcolor;
|
||||
sh->fill = dtfill;
|
||||
sh->lw = dtwidth * 100;
|
||||
|
||||
dtshapes.push_back(unique_ptr<dtshape>(sh));
|
||||
}
|
||||
|
||||
EX void dt_add_line(hyperpoint h1, hyperpoint h2, int maxl) {
|
||||
if(hdist(h1, h2) > 1 && maxl > 0) {
|
||||
hyperpoint h3 = mid(h1, h2);
|
||||
dt_add_line(h1, h3, maxl-1);
|
||||
dt_add_line(h3, h2, maxl-1);
|
||||
return;
|
||||
}
|
||||
cell *b = centerover;
|
||||
transmatrix T = rgpushxto0(h1);
|
||||
|
||||
auto T1 = inverse(ggmatrix(b)) * T;
|
||||
virtualRebase(b, T1);
|
||||
|
||||
auto l = new dtline;
|
||||
l->s = tC0(T1);
|
||||
l->e = T1 * gpushxto0(h1) * h2;
|
||||
dt_add(b, l);
|
||||
}
|
||||
|
||||
EX void dt_add_circle(hyperpoint h1, hyperpoint h2) {
|
||||
cell *b = centerover;
|
||||
|
||||
auto d = hdist(h1, h2);
|
||||
|
||||
h1 = inverse(ggmatrix(b)) * h1;
|
||||
virtualRebase(b, h1);
|
||||
|
||||
auto l = new dtcircle;
|
||||
l->s = h1;
|
||||
l->radius = d;
|
||||
dt_add(b, l);
|
||||
}
|
||||
|
||||
dtshape *load_shape(hstream& hs) {
|
||||
char type = hs.get<char>();
|
||||
switch(type) {
|
||||
case 1:
|
||||
return (new dtline)->load(hs);
|
||||
case 2:
|
||||
return (new dtcircle)->load(hs);
|
||||
case 3:
|
||||
return (new dtfree)->load(hs);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
dtfree *cfree;
|
||||
cell *cfree_at;
|
||||
transmatrix cfree_T;
|
||||
|
||||
EX void dt_add_free(hyperpoint h) {
|
||||
|
||||
cell *b = centerover;
|
||||
transmatrix T = rgpushxto0(h);
|
||||
auto T1 = inverse(ggmatrix(b)) * T;
|
||||
virtualRebase(b, T1);
|
||||
|
||||
if(cfree)
|
||||
cfree->lh.push_back(cfree_T * h);
|
||||
|
||||
if(b != cfree_at && !(dtfill && cfree_at)) {
|
||||
cfree = new dtfree;
|
||||
dt_add(b, cfree);
|
||||
cfree_T = T1 * gpushxto0(h);
|
||||
cfree->lh.push_back(cfree_T * h);
|
||||
cfree_at = b;
|
||||
}
|
||||
}
|
||||
|
||||
EX void dt_erase(hyperpoint h) {
|
||||
ld nearest = 1;
|
||||
int nearest_id = -1;
|
||||
int id = -1;
|
||||
for(auto& shp: dtshapes) {
|
||||
id++;
|
||||
if(shp == nullptr) continue;
|
||||
auto& sh = *shp;
|
||||
cell*& c = sh.where;
|
||||
for(const transmatrix& V: current_display->all_drawn_copies[c]) {
|
||||
ld dist = sh.distance(inverse(V) * h);
|
||||
if(dist < nearest) nearest = dist, nearest_id = id;
|
||||
}
|
||||
}
|
||||
if(nearest_id >= 0)
|
||||
dtshapes.erase(dtshapes.begin() + nearest_id);
|
||||
}
|
||||
|
||||
EX hyperpoint lstart;
|
||||
cell *lstartcell;
|
||||
ld front_edit = 0.5;
|
||||
enum class eFront { sphere_camera, sphere_center, equidistants, const_x, const_y };
|
||||
@ -43,16 +272,16 @@ EX namespace mapeditor {
|
||||
// mx = xb + ssiz*xpos + mrx * scale
|
||||
// mx = xb + ssiz*xpos' + mrx * scale'
|
||||
|
||||
ld mrx = (.0 + mousex - current_display->xcenter) / vid.scale;
|
||||
ld mry = (.0 + mousey - current_display->ycenter) / vid.scale;
|
||||
ld mrx = (.0 + mousex - current_display->xcenter) / vpconf.scale;
|
||||
ld mry = (.0 + mousey - current_display->ycenter) / vpconf.scale;
|
||||
|
||||
if(vid.xres > vid.yres) {
|
||||
vid.xposition += (vid.scale - vid.scale*z) * mrx / current_display->scrsize;
|
||||
vid.yposition += (vid.scale - vid.scale*z) * mry / current_display->scrsize;
|
||||
vpconf.xposition += (vpconf.scale - vpconf.scale*z) * mrx / current_display->scrsize;
|
||||
vpconf.yposition += (vpconf.scale - vpconf.scale*z) * mry / current_display->scrsize;
|
||||
}
|
||||
|
||||
vid.scale *= z;
|
||||
// printf("scale = " LDF "\n", vid.scale);
|
||||
vpconf.scale *= z;
|
||||
// printf("scale = " LDF "\n", vpconf.scale);
|
||||
#if CAP_TEXTURE
|
||||
// display(texture::itt);
|
||||
texture::config.itt = xyscale(texture::config.itt, 1/z);
|
||||
@ -101,6 +330,39 @@ namespace mapstream {
|
||||
vector<cell*> cellbyid;
|
||||
vector<char> relspin;
|
||||
|
||||
void load_drawing_tool(fhstream& hs) {
|
||||
using namespace mapeditor;
|
||||
if(hs.vernum < 0xA82A) return;
|
||||
int i = hs.get<int>();
|
||||
while(i--) {
|
||||
auto sh = load_shape(hs);
|
||||
if(!sh) continue;
|
||||
hs.read(sh->col);
|
||||
hs.read(sh->fill);
|
||||
hs.read(sh->lw);
|
||||
int id = hs.get<int>();
|
||||
sh->where = cellbyid[id];
|
||||
sh->rotate(spin(currentmap->spin_angle(sh->where, relspin[id]) - currentmap->spin_angle(sh->where, 0)));
|
||||
dtshapes.push_back(unique_ptr<dtshape>(sh));
|
||||
}
|
||||
}
|
||||
|
||||
void save_drawing_tool(hstream& hs) {
|
||||
using namespace mapeditor;
|
||||
hs.write<int>(isize(dtshapes));
|
||||
for(auto& shp: dtshapes) {
|
||||
if(shp == nullptr) { hs.write<char>(0); }
|
||||
else {
|
||||
auto& sh = *shp;
|
||||
sh.save(hs);
|
||||
hs.write(sh.col);
|
||||
hs.write(sh.fill);
|
||||
hs.write(sh.lw);
|
||||
hs.write(cellids[sh.where]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void addToQueue(cell* c) {
|
||||
if(cellids.count(c)) return;
|
||||
@ -325,6 +587,8 @@ namespace mapstream {
|
||||
int32_t n = -1; f.write(n);
|
||||
int32_t id = cellids.count(cwt.at) ? cellids[cwt.at] : -1;
|
||||
f.write(id);
|
||||
|
||||
save_drawing_tool(f);
|
||||
|
||||
f.write(vid.always3);
|
||||
f.write(mutantphase);
|
||||
@ -507,6 +771,8 @@ namespace mapstream {
|
||||
savecount = 0; savetime = 0;
|
||||
cheater = 1;
|
||||
|
||||
load_drawing_tool(f);
|
||||
|
||||
dynamicval<bool> a3(vid.always3, vid.always3);
|
||||
if(f.vernum >= 0xA616) { f.read(vid.always3); geom3::apply_always3(); }
|
||||
|
||||
@ -730,7 +996,7 @@ namespace mapeditor {
|
||||
displayButton(8, vid.yres-8-fs*11, XLAT("F1 = help"), SDLK_F1, 0);
|
||||
displayButton(8, vid.yres-8-fs*10, XLAT("F2 = save"), SDLK_F2, 0);
|
||||
displayButton(8, vid.yres-8-fs*9, XLAT("F3 = load"), SDLK_F3, 0);
|
||||
displayButton(8, vid.yres-8-fs*7, XLAT("F5 = restart"), SDLK_F5, 0);
|
||||
displayButton(8, vid.yres-8-fs*7, drawing_tool ? XLAT("F5 = clear") : XLAT("F5 = restart"), SDLK_F5, 0);
|
||||
#if CAP_SHOT
|
||||
displayButton(8, vid.yres-8-fs*6, XLAT("F6 = HQ shot"), SDLK_F6, 0);
|
||||
#endif
|
||||
@ -983,6 +1249,32 @@ namespace mapeditor {
|
||||
if(d == -1 && fix) d = hrand(mouseover->type);
|
||||
return cellwalker(mouseover, d);
|
||||
}
|
||||
|
||||
void save_level() {
|
||||
dialog::openFileDialog(levelfile, XLAT("level to save:"), ".lev", [] () {
|
||||
if(mapstream::saveMap(levelfile.c_str())) {
|
||||
addMessage(XLAT("Map saved to %1", levelfile));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
addMessage(XLAT("Failed to save map to %1", levelfile));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void load_level() {
|
||||
dialog::openFileDialog(levelfile, XLAT("level to load:"), ".lev", [] () {
|
||||
if(mapstream::loadMap(levelfile.c_str())) {
|
||||
addMessage(XLAT("Map loaded from %1", levelfile));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
addMessage(XLAT("Failed to load map from %1", levelfile));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void showList() {
|
||||
dialog::v.clear();
|
||||
@ -1083,31 +1375,10 @@ namespace mapeditor {
|
||||
else if(uni == 'G')
|
||||
push_debug_screen();
|
||||
else if(sym == SDLK_F5) {
|
||||
restart_game();
|
||||
dialog::push_confirm_dialog([] { restart_game(); }, XLAT("Are you sure you want to clear the map?"));
|
||||
}
|
||||
else if(sym == SDLK_F2) {
|
||||
dialog::openFileDialog(levelfile, XLAT("level to save:"), ".lev", [] () {
|
||||
if(mapstream::saveMap(levelfile.c_str())) {
|
||||
addMessage(XLAT("Map saved to %1", levelfile));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
addMessage(XLAT("Failed to save map to %1", levelfile));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(sym == SDLK_F3)
|
||||
dialog::openFileDialog(levelfile, XLAT("level to load:"), ".lev", [] () {
|
||||
if(mapstream::loadMap(levelfile.c_str())) {
|
||||
addMessage(XLAT("Map loaded from %1", levelfile));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
addMessage(XLAT("Failed to load map from %1", levelfile));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
else if(sym == SDLK_F2) save_level();
|
||||
else if(sym == SDLK_F3) load_level();
|
||||
#if CAP_SHOT
|
||||
else if(sym == SDLK_F6) {
|
||||
pushScreen(shot::menu);
|
||||
@ -1188,7 +1459,7 @@ namespace mapeditor {
|
||||
unsigned gridcolor = 0xC0C0C040;
|
||||
|
||||
hyperpoint in_front_dist(ld d) {
|
||||
return direct_exp(lp_iapply(ztangent(d)), 100);
|
||||
return direct_exp(lp_iapply(ztangent(d)));
|
||||
}
|
||||
|
||||
hyperpoint find_mouseh3() {
|
||||
@ -1203,7 +1474,7 @@ namespace mapeditor {
|
||||
ld d1 = front_edit;
|
||||
hyperpoint h1 = in_front_dist(d);
|
||||
if(front_config == eFront::sphere_center)
|
||||
d1 = geo_dist(drawtrans * C0, h1, iTable);
|
||||
d1 = geo_dist(drawtrans * C0, h1);
|
||||
if(front_config == eFront::equidistants) {
|
||||
hyperpoint h = idt * in_front_dist(d);
|
||||
d1 = asin_auto(h[2]);
|
||||
@ -1232,6 +1503,7 @@ namespace mapeditor {
|
||||
ld equi_range = 1;
|
||||
|
||||
EX void drawGrid() {
|
||||
if(!drawcell) drawcell = cwt.at;
|
||||
color_t lightgrid = gridcolor;
|
||||
lightgrid -= (lightgrid & 0xFF) / 2;
|
||||
transmatrix d2 = drawtrans * rgpushxto0(ccenter) * rspintox(gpushxto0(ccenter) * coldcenter);
|
||||
@ -1246,7 +1518,7 @@ namespace mapeditor {
|
||||
}
|
||||
if(front_config == eFront::sphere_center) for(int i=0; i<4; i+=2) {
|
||||
auto pt = [&] (ld a, ld b) {
|
||||
return d2 * direct_exp(spin(a*degree) * cspin(0, 2, b*degree) * xtangent(front_edit), 100);
|
||||
return d2 * direct_exp(spin(a*degree) * cspin(0, 2, b*degree) * xtangent(front_edit));
|
||||
};
|
||||
for(int ai=0; ai<parallels; ai++) {
|
||||
ld a = ai * 360 / parallels;
|
||||
@ -1363,6 +1635,9 @@ namespace mapeditor {
|
||||
usershape *us = NULL;
|
||||
|
||||
bool intexture = false;
|
||||
(void) intexture;
|
||||
|
||||
bool freedraw = drawing_tool;
|
||||
|
||||
#if CAP_TEXTURE
|
||||
if(texture::config.tstate == texture::tsActive) {
|
||||
@ -1371,12 +1646,12 @@ namespace mapeditor {
|
||||
line2 = "";
|
||||
texture::config.data.update();
|
||||
intexture = true;
|
||||
freedraw = true;
|
||||
drawing_tool = false;
|
||||
}
|
||||
#else
|
||||
if(0);
|
||||
#endif
|
||||
|
||||
else {
|
||||
|
||||
if(!freedraw) {
|
||||
|
||||
sg = drawcellShapeGroup();
|
||||
|
||||
@ -1419,7 +1694,7 @@ namespace mapeditor {
|
||||
// displayButton(8, 8+fs*9, XLAT("l = lands"), 'l', 0);
|
||||
displayfr(8, 8+fs, 2, vid.fsize, line1, 0xC0C0C0, 0);
|
||||
|
||||
if(!intexture) {
|
||||
if(!freedraw) {
|
||||
if(sg == sgFloor)
|
||||
displayButton(8, 8+fs*2, line2 + XLAT(" (r = complex tesselations)"), 'r', 0);
|
||||
else
|
||||
@ -1466,17 +1741,21 @@ namespace mapeditor {
|
||||
|
||||
}
|
||||
#if CAP_TEXTURE
|
||||
else if(texture::config.tstate == texture::tsActive) {
|
||||
else if(freedraw) {
|
||||
displayButton(8, 8+fs*2, XLAT(texture::texturesym ? "0 = symmetry" : "0 = asymmetry"), '0', 0);
|
||||
if(mousekey == 'g')
|
||||
displayButton(8, 8+fs*16, XLAT("p = grid color"), 'p', 0);
|
||||
else
|
||||
displayButton(8, 8+fs*16, XLAT("p = color"), 'p', 0);
|
||||
displayButton(8, 8+fs*4, XLAT("b = brush size: %1", fts(texture::penwidth)), 'b', 0);
|
||||
if(drawing_tool)
|
||||
displayButton(8, 8+fs*17, XLAT("f = fill") + (dtfill ? " (on)" : " (off)"), 'f', 0);
|
||||
displayButton(8, 8+fs*4, XLAT("b = brush size: %1", fts(dtwidth)), 'b', 0);
|
||||
displayButton(8, 8+fs*5, XLAT("u = undo"), 'u', 0);
|
||||
displaymm('d', 8, 8+fs*7, 2, vid.fsize, XLAT("d = draw"), 0);
|
||||
displaymm('l', 8, 8+fs*8, 2, vid.fsize, XLAT("l = line"), 0);
|
||||
displaymm('c', 8, 8+fs*9, 2, vid.fsize, XLAT("c = circle"), 0);
|
||||
if(drawing_tool)
|
||||
displaymm('e', 8, 8+fs*10, 2, vid.fsize, XLAT("e = erase"), 0);
|
||||
int s = isize(texture::config.data.pixels_to_draw);
|
||||
if(s) displaymm(0, 8, 8+fs*11, 2, vid.fsize, its(s), 0);
|
||||
}
|
||||
@ -1498,15 +1777,15 @@ namespace mapeditor {
|
||||
displaymm('g', vid.xres-8, 8+fs*4, 2, vid.fsize, XLAT("g = grid"), 16);
|
||||
|
||||
#if CAP_TEXTURE
|
||||
if(intexture) for(int i=0; i<10; i++) {
|
||||
if(freedraw) for(int i=0; i<10; i++) {
|
||||
if(8 + fs * (6+i) < vid.yres - 8 - fs * 7)
|
||||
displayColorButton(vid.xres-8, 8+fs*(6+i), "###", 1000 + i, 16, 1, dialog::displaycolor(texture_colors[i+1]));
|
||||
|
||||
if(displayfr(vid.xres-8 - fs * 3, 8+fs*(6+i), 0, vid.fsize, its(i+1), texture::penwidth == brush_sizes[i] ? 0xFF8000 : 0xC0C0C0, 16))
|
||||
if(displayfr(vid.xres-8 - fs * 3, 8+fs*(6+i), 0, vid.fsize, its(i+1), dtwidth == brush_sizes[i] ? 0xFF8000 : 0xC0C0C0, 16))
|
||||
getcstat = 2000+i;
|
||||
}
|
||||
|
||||
if(texture::config.tstate != texture::tsActive)
|
||||
if(!freedraw)
|
||||
displaymm('e', vid.xres-8, 8+fs, 2, vid.fsize, XLAT("e = edit this"), 16);
|
||||
#endif
|
||||
|
||||
@ -1524,7 +1803,7 @@ namespace mapeditor {
|
||||
displayfr(vid.xres-8, vid.yres-8-fs*5, 2, vid.fsize, XLAT("z: %1", fts(mh[2],4)), 0xC0C0C0, 16);
|
||||
if(MDIM == 4)
|
||||
displayfr(vid.xres-8, vid.yres-8-fs*4, 2, vid.fsize, XLAT("w: %1", fts(mh[3],4)), 0xC0C0C0, 16);
|
||||
mh = inverse_exp(mh, iTable, false);
|
||||
mh = inverse_exp(mh);
|
||||
displayfr(vid.xres-8, vid.yres-8-fs*3, 2, vid.fsize, XLAT("r: %1", fts(hypot_d(3, mh),4)), 0xC0C0C0, 16);
|
||||
if(GDIM == 3) {
|
||||
displayfr(vid.xres-8, vid.yres-8-fs, 2, vid.fsize, XLAT("ϕ: %1°", fts(-atan2(mh[2], hypot_d(2, mh)) / degree,4)), 0xC0C0C0, 16);
|
||||
@ -1933,12 +2212,35 @@ namespace mapeditor {
|
||||
if(mkuni == 'g')
|
||||
coldcenter = ccenter, ccenter = mh, clickused = true;
|
||||
|
||||
if(uni == 'd' || uni == 'l' || uni == 'c')
|
||||
if(uni == 'd' || uni == 'l' || uni == 'c' || uni == 'e')
|
||||
mousekey = uni;
|
||||
|
||||
if(drawing_tool) {
|
||||
if(sym == SDLK_F2) save_level();
|
||||
if(sym == SDLK_F3) load_level();
|
||||
if(sym == SDLK_F5) {
|
||||
dialog::push_confirm_dialog([] {
|
||||
stop_game();
|
||||
firstland = specialland = laCanvas;
|
||||
canvas_default_wall = waInvisibleFloor;
|
||||
patterns::whichCanvas = 'g';
|
||||
patterns::canvasback = 0xFFFFFF;
|
||||
dtcolor = (forecolor << 8) | 255;
|
||||
drawplayer = false;
|
||||
vid.use_smart_range = 2;
|
||||
start_game();
|
||||
},
|
||||
XLAT("Are you sure you want to restart? This will let you draw on a blank screen.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(uni == ' ' && (cheater || autocheat)) {
|
||||
popScreen();
|
||||
pushScreen(showMapEditor);
|
||||
drawing_tool = !drawing_tool;
|
||||
if(!drawing_tool) {
|
||||
popScreen();
|
||||
pushScreen(showMapEditor);
|
||||
}
|
||||
}
|
||||
|
||||
if(uni == 'z' && GDIM == 3) {
|
||||
@ -2001,35 +2303,57 @@ namespace mapeditor {
|
||||
|
||||
if(sym == SDLK_F10) popScreen();
|
||||
|
||||
#if CAP_TEXTURE
|
||||
if(texture::config.tstate == texture::tsActive) {
|
||||
(void)clickused;
|
||||
|
||||
int tcolor = (texture::config.paint_color >> 8) | ((texture::config.paint_color & 0xFF) << 24);
|
||||
|
||||
bool freedraw = drawing_tool;
|
||||
#if CAP_TEXTURE
|
||||
bool intexture = texture::config.tstate == texture::tsActive;
|
||||
freedraw |= intexture;
|
||||
#else
|
||||
always_false intexture;
|
||||
#endif
|
||||
|
||||
if(freedraw) {
|
||||
|
||||
int tcolor = (dtcolor >> 8) | ((dtcolor & 0xFF) << 24);
|
||||
|
||||
if(uni == '-' && !clickused) {
|
||||
if(mousekey == 'l' || mousekey == 'c') {
|
||||
if(mousekey == 'e') {
|
||||
dt_erase(mouseh);
|
||||
clickused = true;
|
||||
}
|
||||
else if(mousekey == 'l' || mousekey == 'c') {
|
||||
if(!holdmouse) lstart = mouseh, lstartcell = mouseover, holdmouse = true;
|
||||
}
|
||||
else {
|
||||
else if(intexture) {
|
||||
if(!holdmouse) texture::config.data.undoLock();
|
||||
texture::drawPixel(mouseover, mouseh, tcolor);
|
||||
holdmouse = true; lstartcell = NULL;
|
||||
}
|
||||
else {
|
||||
dt_add_free(mouseh);
|
||||
holdmouse = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(sym == PSEUDOKEY_RELEASE) {
|
||||
printf("release\n");
|
||||
if(mousekey == 'l') {
|
||||
if(mousekey == 'l' && intexture) {
|
||||
texture::config.data.undoLock();
|
||||
texture::where = mouseover;
|
||||
texture::drawPixel(mouseover, mouseh, tcolor);
|
||||
texture::drawLine(mouseh, lstart, tcolor);
|
||||
lstartcell = NULL;
|
||||
}
|
||||
if(mousekey == 'c') {
|
||||
else if(mousekey == 'l') {
|
||||
dt_add_line(mouseh, lstart, 10);
|
||||
lstartcell = NULL;
|
||||
}
|
||||
else if(mousekey == 'c' && intexture) {
|
||||
texture::config.data.undoLock();
|
||||
ld rad = hdist(lstart, mouseh);
|
||||
int circp = int(1 + 3 * (circlelength(rad) / texture::penwidth));
|
||||
int circp = int(1 + 3 * (circlelength(rad) / dtwidth));
|
||||
if(circp > 1000) circp = 1000;
|
||||
transmatrix T = rgpushxto0(lstart);
|
||||
texture::where = lstartcell;
|
||||
@ -2037,13 +2361,21 @@ namespace mapeditor {
|
||||
texture::drawPixel(T * xspinpush0(2 * M_PI * i / circp, rad), tcolor);
|
||||
lstartcell = NULL;
|
||||
}
|
||||
else if(mousekey == 'c') {
|
||||
dt_add_circle(lstart, mouseh);
|
||||
lstartcell = NULL;
|
||||
}
|
||||
else {
|
||||
cfree = nullptr;
|
||||
cfree_at = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(uni >= 1000 && uni < 1010)
|
||||
texture::config.paint_color = texture_colors[uni - 1000 + 1];
|
||||
dtcolor = texture_colors[uni - 1000 + 1];
|
||||
|
||||
if(uni >= 2000 && uni < 2010)
|
||||
texture::penwidth = brush_sizes[uni - 2000];
|
||||
dtwidth = brush_sizes[uni - 2000];
|
||||
|
||||
if(uni == '0')
|
||||
texture::texturesym = !texture::texturesym;
|
||||
@ -2054,16 +2386,19 @@ namespace mapeditor {
|
||||
|
||||
if(uni == 'p') {
|
||||
if(!clickused)
|
||||
dialog::openColorDialog(texture::config.paint_color, texture_colors);
|
||||
dialog::openColorDialog(dtcolor, texture_colors);
|
||||
}
|
||||
|
||||
if(uni == 'f') {
|
||||
if(dtfill == dtcolor)
|
||||
dtfill = 0;
|
||||
else
|
||||
dtfill = dtcolor;
|
||||
}
|
||||
|
||||
if(uni == 'b')
|
||||
dialog::editNumber(texture::penwidth, 0, 0.1, 0.005, 0.02, XLAT("brush size"), XLAT("brush size"));
|
||||
dialog::editNumber(dtwidth, 0, 0.1, 0.005, 0.02, XLAT("brush size"), XLAT("brush size"));
|
||||
}
|
||||
#else
|
||||
(void)clickused;
|
||||
if(0);
|
||||
#endif
|
||||
|
||||
else {
|
||||
dslayer %= USERLAYERS;
|
||||
@ -2137,6 +2472,10 @@ namespace mapeditor {
|
||||
if(!cheater) patterns::displaycodes = false;
|
||||
if(!cheater) patterns::whichShape = 0;
|
||||
modelcell.clear();
|
||||
mapeditor::dtshapes.clear();
|
||||
mapeditor::cfree = nullptr;
|
||||
mapeditor::cfree_at = nullptr;
|
||||
drawcell = nullptr;
|
||||
}) +
|
||||
addHook(hooks_removecells, 0, [] () {
|
||||
modelcell.clear();
|
||||
@ -2159,8 +2498,7 @@ namespace mapeditor {
|
||||
|
||||
transmatrix textrans;
|
||||
|
||||
#if CAP_TEXTURE
|
||||
void queue_hcircle(transmatrix Ctr, ld radius) {
|
||||
EX void queue_hcircle(transmatrix Ctr, ld radius) {
|
||||
vector<hyperpoint> pts;
|
||||
int circp = int(6 * pow(2, vid.linequality));
|
||||
if(radius > 0.04) circp *= 2;
|
||||
@ -2170,9 +2508,8 @@ namespace mapeditor {
|
||||
pts.push_back(Ctr * xspinpush0(M_PI*j*2/circp, radius));
|
||||
for(int j=0; j<circp; j++) curvepoint(pts[j]);
|
||||
curvepoint(pts[0]);
|
||||
queuecurve(texture::config.paint_color, 0, PPR::LINE);
|
||||
queuecurve(dtcolor, 0, PPR::LINE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CAP_POLY
|
||||
EX bool haveUserShape(eShapegroup group, int id) {
|
||||
@ -2210,10 +2547,10 @@ namespace mapeditor {
|
||||
queue_hcircle(M2 * ml, hdist(lstart, mouseh));
|
||||
break;
|
||||
case 'l':
|
||||
queueline(M2 * mh * C0, M2 * ml * C0, texture::config.paint_color, 4 + vid.linequality, PPR::LINE);
|
||||
queueline(M2 * mh * C0, M2 * ml * C0, dtcolor, 4 + vid.linequality, PPR::LINE);
|
||||
break;
|
||||
default:
|
||||
queue_hcircle(M2 * mh, texture::penwidth);
|
||||
queue_hcircle(M2 * mh, dtwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
menus.cpp
40
menus.cpp
@ -323,7 +323,7 @@ EX void showMainMenu() {
|
||||
// -- display modes --
|
||||
|
||||
EX void editScale() {
|
||||
dialog::editNumber(vid.scale, .001, 1000, .1, 1, XLAT("scale factor"),
|
||||
dialog::editNumber(vpconf.scale, .001, 1000, .1, 1, XLAT("scale factor"),
|
||||
XLAT("Scale the displayed model."));
|
||||
dialog::scaleSinh();
|
||||
}
|
||||
@ -335,10 +335,10 @@ EX void showGraphQuickKeys() {
|
||||
dialog::init(XLAT("quick options"));
|
||||
|
||||
if(GDIM == 2) {
|
||||
dialog::addBoolItem(XLAT("orthogonal projection"), vid.alpha >= 500, '1');
|
||||
dialog::addBoolItem(XLAT(sphere ? "stereographic projection" : euclid ? "zoomed out" : "small Poincaré model"), vid.alpha == 1 && vid.scale < 1, '2');
|
||||
dialog::addBoolItem(XLAT(sphere ? "zoomed stereographic projection" : euclid ? "zoomed in" : "big Poincaré model"), vid.alpha == 1 && vid.scale >= 1, '3');
|
||||
dialog::addBoolItem(XLAT((sphere || euclid) ? "gnomonic projection" : "Klein-Beltrami model"), vid.alpha == 0, '4');
|
||||
dialog::addBoolItem(XLAT("orthogonal projection"), vpconf.alpha >= 500, '1');
|
||||
dialog::addBoolItem(XLAT(sphere ? "stereographic projection" : euclid ? "zoomed out" : "small Poincaré model"), vpconf.alpha == 1 && vpconf.scale < 1, '2');
|
||||
dialog::addBoolItem(XLAT(sphere ? "zoomed stereographic projection" : euclid ? "zoomed in" : "big Poincaré model"), vpconf.alpha == 1 && vpconf.scale >= 1, '3');
|
||||
dialog::addBoolItem(XLAT((sphere || euclid) ? "gnomonic projection" : "Klein-Beltrami model"), vpconf.alpha == 0, '4');
|
||||
}
|
||||
else {
|
||||
dialog::addBoolItem(XLAT("first person perspective"), vid.yshift == 0 && vid.sspeed > -5, '1');
|
||||
@ -433,13 +433,25 @@ EX void showCreative() {
|
||||
#endif
|
||||
|
||||
#if CAP_EDIT
|
||||
dialog::addItem(XLAT("vector graphics editor"), 'g');
|
||||
dialog::addItem(XLAT("shape editor"), 'g');
|
||||
dialog::add_action([] {
|
||||
mapeditor::drawing_tool = false;
|
||||
pushScreen(mapeditor::showDrawEditor);
|
||||
mapeditor::initdraw(cwt.at);
|
||||
});
|
||||
#endif
|
||||
|
||||
#if CAP_EDIT
|
||||
dialog::addItem(XLAT("drawing tool"), 'd');
|
||||
dialog::add_action([] {
|
||||
dialog::cheat_if_confirmed([] {
|
||||
mapeditor::drawing_tool = true;
|
||||
pushScreen(mapeditor::showDrawEditor);
|
||||
mapeditor::initdraw(cwt.at);
|
||||
});
|
||||
});
|
||||
#endif
|
||||
|
||||
// display modes
|
||||
#if CAP_MODEL
|
||||
if(GDIM == 2) {
|
||||
@ -875,11 +887,11 @@ EX void showStartMenu() {
|
||||
specialland = laHalloween;
|
||||
set_geometry(gSphere);
|
||||
start_game();
|
||||
vid.alpha = 999;
|
||||
vid.scale = 998;
|
||||
pconf.alpha = 999;
|
||||
pconf.scale = 998;
|
||||
}
|
||||
}
|
||||
#if CAP_RACING
|
||||
#if CAP_RACING && MAXMDIM >= 4
|
||||
else if(uni == 'r' - 96) {
|
||||
popScreenAll();
|
||||
resetModes();
|
||||
@ -889,13 +901,13 @@ EX void showStartMenu() {
|
||||
specialland = racing::race_lands[rand() % isize(racing::race_lands)];
|
||||
start_game();
|
||||
pmodel = mdBand;
|
||||
models::model_orientation = racing::race_angle;
|
||||
pconf.model_orientation = racing::race_angle;
|
||||
racing::race_advance = 1;
|
||||
vid.yshift = 0;
|
||||
vid.camera_angle = 0;
|
||||
vid.xposition = 0;
|
||||
vid.yposition = 0;
|
||||
vid.scale = 1;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = 0;
|
||||
pconf.scale = 1;
|
||||
vid.use_smart_range = 1;
|
||||
vid.smart_range_detail = 3;
|
||||
}
|
||||
|
297
models.cpp
297
models.cpp
@ -115,20 +115,13 @@ inline bool mdPseudocylindrical() { return mdBandAny() && !(mdinf[pmodel].flags
|
||||
|
||||
EX namespace models {
|
||||
|
||||
EX string formula = "z^2";
|
||||
EX eModel basic_model;
|
||||
|
||||
EX ld rotation = 0;
|
||||
EX ld rotation_xz = 90;
|
||||
EX ld rotation_xy2 = 90;
|
||||
EX int do_rotate = 1;
|
||||
EX ld model_orientation, halfplane_scale, model_orientation_yz;
|
||||
EX ld clip_min, clip_max;
|
||||
EX ld ocos, osin, ocos_yz, osin_yz;
|
||||
EX ld cos_ball, sin_ball;
|
||||
EX bool model_straight, model_straight_yz;
|
||||
EX ld top_z = 5;
|
||||
EX ld model_transition = 1;
|
||||
|
||||
#if HDR
|
||||
// screen coordinates to logical coordinates: apply_orientation(x,y)
|
||||
@ -146,53 +139,43 @@ EX namespace models {
|
||||
return spin(rotation_xy2 * degree) * cspin(0, 2, -rotation_xz * degree) * spin(rotation * degree);
|
||||
}
|
||||
|
||||
EX ld spiral_angle = 70;
|
||||
EX ld spiral_x = 10;
|
||||
EX ld spiral_y = 7;
|
||||
int spiral_id = 7;
|
||||
EX bool use_atan = false;
|
||||
|
||||
EX cld spiral_multiplier;
|
||||
EX ld right_spiral_multiplier = 1;
|
||||
EX ld any_spiral_multiplier = 1;
|
||||
EX ld sphere_spiral_multiplier = 2;
|
||||
EX ld spiral_cone = 360;
|
||||
EX ld spiral_cone_rad;
|
||||
EX bool ring_not_spiral;
|
||||
|
||||
/** the matrix to rotate the Euclidean view from the standard coordinates to the screen coordinates */
|
||||
EX transmatrix euclidean_spin;
|
||||
|
||||
EX ld product_z_scale = 1;
|
||||
|
||||
EX void configure() {
|
||||
ld ball = -vid.ballangle * degree;
|
||||
ld ball = -pconf.ballangle * degree;
|
||||
cos_ball = cos(ball), sin_ball = sin(ball);
|
||||
ocos = cos(model_orientation * degree);
|
||||
osin = sin(model_orientation * degree);
|
||||
ocos_yz = cos(model_orientation_yz * degree);
|
||||
osin_yz = sin(model_orientation_yz * degree);
|
||||
ocos = cos(pconf.model_orientation * degree);
|
||||
osin = sin(pconf.model_orientation * degree);
|
||||
ocos_yz = cos(pconf.model_orientation_yz * degree);
|
||||
osin_yz = sin(pconf.model_orientation_yz * degree);
|
||||
model_straight = (ocos > 1 - 1e-9);
|
||||
model_straight_yz = GDIM == 2 || (ocos_yz > 1-1e-9);
|
||||
if(history::on) history::apply();
|
||||
|
||||
if(!euclid) {
|
||||
ld b = spiral_angle * degree;
|
||||
ld b = pconf.spiral_angle * degree;
|
||||
ld cos_spiral = cos(b);
|
||||
ld sin_spiral = sin(b);
|
||||
spiral_cone_rad = spiral_cone * degree;
|
||||
spiral_cone_rad = pconf.spiral_cone * degree;
|
||||
ring_not_spiral = abs(cos_spiral) < 1e-3;
|
||||
ld mul = 1;
|
||||
if(sphere) mul = .5 * sphere_spiral_multiplier;
|
||||
else if(ring_not_spiral) mul = right_spiral_multiplier;
|
||||
else mul = any_spiral_multiplier * cos_spiral;
|
||||
if(sphere) mul = .5 * pconf.sphere_spiral_multiplier;
|
||||
else if(ring_not_spiral) mul = pconf.right_spiral_multiplier;
|
||||
else mul = pconf.any_spiral_multiplier * cos_spiral;
|
||||
|
||||
spiral_multiplier = cld(cos_spiral, sin_spiral) * cld(spiral_cone_rad * mul / 2., 0);
|
||||
}
|
||||
if(euclid) {
|
||||
euclidean_spin = pispin * inverse(cview() * master_relative(centerover, true));
|
||||
euclidean_spin = gpushxto0(euclidean_spin * C0) * euclidean_spin;
|
||||
hyperpoint h = inverse(euclidean_spin) * (C0 + (euc::eumove(gp::loc{1,0})*C0 - C0) * spiral_x + (euc::eumove(gp::loc{0,1})*C0 - C0) * spiral_y);
|
||||
hyperpoint h = inverse(euclidean_spin) * (C0 + (euc::eumove(gp::loc{1,0})*C0 - C0) * vpconf.spiral_x + (euc::eumove(gp::loc{0,1})*C0 - C0) * vpconf.spiral_y);
|
||||
spiral_multiplier = cld(0, 2 * M_PI) / cld(h[0], h[1]);
|
||||
}
|
||||
|
||||
@ -222,18 +205,27 @@ EX namespace models {
|
||||
return true;
|
||||
}
|
||||
|
||||
EX bool model_has_orientation() {
|
||||
EX bool has_orientation(eModel m) {
|
||||
return
|
||||
among(pmodel, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic) || mdBandAny();
|
||||
among(m, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic) || mdBandAny();
|
||||
}
|
||||
|
||||
EX bool model_has_transition() {
|
||||
return among(pmodel, mdJoukowsky, mdJoukowskyInverted, mdBand) && GDIM == 2;
|
||||
EX bool is_perspective(eModel m) {
|
||||
return among(m, mdPerspective, mdGeodesic);
|
||||
}
|
||||
|
||||
EX bool is_3d(const projection_configuration& p) {
|
||||
if(GDIM == 3) return true;
|
||||
return among(p.model, mdBall, mdHyperboloid, mdHemisphere) || (p.model == mdSpiral && p.spiral_cone != 360);
|
||||
}
|
||||
|
||||
EX bool product_model() {
|
||||
EX bool has_transition(eModel m) {
|
||||
return among(m, mdJoukowsky, mdJoukowskyInverted, mdBand) && GDIM == 2;
|
||||
}
|
||||
|
||||
EX bool product_model(eModel m) {
|
||||
if(!prod) return false;
|
||||
if(among(pmodel, mdPerspective, mdHyperboloid, mdEquidistant)) return false;
|
||||
if(among(m, mdPerspective, mdHyperboloid, mdEquidistant)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -286,16 +278,16 @@ EX namespace models {
|
||||
dialog::editNumber(spiral_id, 0, isize(torus_zeros)-1, 1, 10, XLAT("match the period of the torus"), "");
|
||||
dialog::reaction = [] () {
|
||||
auto& co = torus_zeros[spiral_id];
|
||||
spiral_x = co.first;
|
||||
spiral_y = co.second;
|
||||
vpconf.spiral_x = co.first;
|
||||
vpconf.spiral_y = co.second;
|
||||
};
|
||||
dialog::bound_low(0);
|
||||
dialog::bound_up(isize(torus_zeros)-1);
|
||||
}
|
||||
|
||||
EX void edit_formula() {
|
||||
if(pmodel != mdFormula) basic_model = pmodel;
|
||||
dialog::edit_string(formula, "formula",
|
||||
if(vpconf.model != mdFormula) vpconf.basic_model = vpconf.model;
|
||||
dialog::edit_string(vpconf.formula, "formula",
|
||||
XLAT(
|
||||
"This lets you specify the projection as a formula f. "
|
||||
"The formula has access to the value 'z', which is a complex number corresponding to the (x,y) coordinates in the currently selected model; "
|
||||
@ -314,12 +306,12 @@ EX namespace models {
|
||||
curvepoint(point2(a*current_display->radius, +M_PI/2*current_display->radius));
|
||||
queuecurve(forecolor, 0, PPR::LINE);
|
||||
}
|
||||
queuereset(pmodel, PPR::LINE);
|
||||
queuereset(vpconf.model, PPR::LINE);
|
||||
quickqueue();
|
||||
};
|
||||
#endif
|
||||
dialog::reaction_final = [] () {
|
||||
pmodel = mdFormula;
|
||||
vpconf.model = mdFormula;
|
||||
};
|
||||
}
|
||||
|
||||
@ -351,24 +343,25 @@ EX namespace models {
|
||||
cmode = sm::SIDE | sm::MAYDARK | sm::CENTER;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("models & projections"));
|
||||
USING_NATIVE_GEOMETRY_IN_RUG;
|
||||
|
||||
for(int i=0; i<mdGUARD; i++) {
|
||||
eModel m = eModel(i);
|
||||
if(m == mdFormula && ISMOBILE) continue;
|
||||
if(model_available(m)) {
|
||||
dialog::addBoolItem(get_model_name(m), pmodel == m, (i < 26 ? 'a'+i : 'A'+i-26));
|
||||
dialog::addBoolItem(get_model_name(m), vpconf.model == m, (i < 26 ? 'a'+i : 'A'+i-26));
|
||||
dialog::add_action([m] () {
|
||||
if(m == mdFormula) {
|
||||
edit_formula();
|
||||
return;
|
||||
}
|
||||
pmodel = m;
|
||||
vpconf.model = m;
|
||||
polygonal::solve();
|
||||
vid.alpha = 1; vid.scale = 1;
|
||||
vpconf.alpha = 1; vpconf.scale = 1;
|
||||
if(pmodel == mdBand && sphere)
|
||||
vid.scale = .3;
|
||||
vpconf.scale = .3;
|
||||
if(pmodel == mdDisk && sphere)
|
||||
vid.scale = .4;
|
||||
vpconf.scale = .4;
|
||||
popScreen();
|
||||
});
|
||||
}
|
||||
@ -378,24 +371,24 @@ EX namespace models {
|
||||
}
|
||||
|
||||
void edit_stretch() {
|
||||
dialog::editNumber(vid.stretch, 0, 10, .1, 1, XLAT("vertical stretch"),
|
||||
dialog::editNumber(vpconf.stretch, 0, 10, .1, 1, XLAT("vertical stretch"),
|
||||
"Vertical stretch factor."
|
||||
);
|
||||
dialog::extra_options = [] () {
|
||||
dialog::addBreak(100);
|
||||
if(sphere && pmodel == mdBandEquiarea) {
|
||||
dialog::addBoolItem("Gall-Peters", vid.stretch == 2, 'O');
|
||||
dialog::add_action([] { vid.stretch = 2; dialog::ne.s = "2"; });
|
||||
dialog::addBoolItem("Gall-Peters", vpconf.stretch == 2, 'O');
|
||||
dialog::add_action([] { vpconf.stretch = 2; dialog::ne.s = "2"; });
|
||||
}
|
||||
if(pmodel == mdBandEquiarea) {
|
||||
// y = K * sin(phi)
|
||||
// cos(phi) * cos(phi) = 1/K
|
||||
if(sphere && vid.stretch >= 1) {
|
||||
ld phi = acos(sqrt(1/vid.stretch));
|
||||
if(sphere && vpconf.stretch >= 1) {
|
||||
ld phi = acos(sqrt(1/vpconf.stretch));
|
||||
dialog::addInfo(XLAT("The current value makes the map conformal at the latitude of %1 (%2°).", fts(phi), fts(phi / degree)));
|
||||
}
|
||||
else if(hyperbolic && abs(vid.stretch) <= 1 && abs(vid.stretch) >= 1e-9) {
|
||||
ld phi = acosh(abs(sqrt(1/vid.stretch)));
|
||||
else if(hyperbolic && abs(vpconf.stretch) <= 1 && abs(vpconf.stretch) >= 1e-9) {
|
||||
ld phi = acosh(abs(sqrt(1/vpconf.stretch)));
|
||||
dialog::addInfo(XLAT("The current value makes the map conformal %1 units from the main line.", fts(phi)));
|
||||
}
|
||||
else dialog::addInfo("");
|
||||
@ -406,9 +399,12 @@ EX namespace models {
|
||||
EX void model_menu() {
|
||||
cmode = sm::SIDE | sm::MAYDARK | sm::CENTER;
|
||||
gamescreen(0);
|
||||
USING_NATIVE_GEOMETRY_IN_RUG;
|
||||
dialog::init(XLAT("models & projections"));
|
||||
|
||||
dialog::addSelItem(XLAT("projection type"), get_model_name(pmodel), 'm');
|
||||
auto vpmodel = vpconf.model;
|
||||
|
||||
dialog::addSelItem(XLAT("projection type"), get_model_name(vpmodel), 'm');
|
||||
dialog::add_action_push(model_list);
|
||||
|
||||
if(nonisotropic && !sl2)
|
||||
@ -420,61 +416,61 @@ EX namespace models {
|
||||
dialog::lastItem().value += " " + its(rotation) + "°";
|
||||
else
|
||||
dialog::lastItem().value += " " + its(rotation) + "°" + its(rotation_xz) + "°" + its(rotation_xy2) + "°";
|
||||
dialog::add_action([] { edit_rotation(models::rotation); });
|
||||
dialog::add_action([] { edit_rotation(rotation); });
|
||||
|
||||
// if(pmodel == mdBand && sphere)
|
||||
// if(vpmodel == mdBand && sphere)
|
||||
if(!in_perspective()) {
|
||||
dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z');
|
||||
dialog::addSelItem(XLAT("scale factor"), fts(vpconf.scale), 'z');
|
||||
dialog::add_action(editScale);
|
||||
}
|
||||
|
||||
if(abs(vid.alpha-1) > 1e-3 && pmodel != mdBall && pmodel != mdHyperboloid && pmodel != mdHemisphere && pmodel != mdDisk) {
|
||||
if(abs(pconf.alpha-1) > 1e-3 && vpmodel != mdBall && vpmodel != mdHyperboloid && vpmodel != mdHemisphere && vpmodel != mdDisk) {
|
||||
dialog::addBreak(50);
|
||||
dialog::addInfo("NOTE: this works 'correctly' only if the Poincaré model/stereographic projection is used.");
|
||||
dialog::addBreak(50);
|
||||
}
|
||||
|
||||
if(among(pmodel, mdDisk, mdBall, mdHyperboloid, mdRotatedHyperboles)) {
|
||||
dialog::addSelItem(XLAT("projection distance"), fts(vid.alpha) + " (" + current_proj_name() + ")", 'p');
|
||||
if(among(vpmodel, mdDisk, mdBall, mdHyperboloid, mdRotatedHyperboles)) {
|
||||
dialog::addSelItem(XLAT("projection distance"), fts(vpconf.alpha) + " (" + current_proj_name() + ")", 'p');
|
||||
dialog::add_action(projectionDialog);
|
||||
}
|
||||
|
||||
if(model_has_orientation()) {
|
||||
dialog::addSelItem(XLAT("model orientation"), fts(model_orientation) + "°", 'l');
|
||||
if(has_orientation(vpmodel)) {
|
||||
dialog::addSelItem(XLAT("model orientation"), fts(vpconf.model_orientation) + "°", 'l');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(model_orientation, 0, 360, 90, 0, XLAT("model orientation"), "");
|
||||
dialog::editNumber(vpconf.model_orientation, 0, 360, 90, 0, XLAT("model orientation"), "");
|
||||
});
|
||||
if(GDIM == 3) {
|
||||
dialog::addSelItem(XLAT("model orientation (y/z plane)"), fts(model_orientation_yz) + "°", 'L');
|
||||
dialog::addSelItem(XLAT("model orientation (y/z plane)"), fts(vpconf.model_orientation_yz) + "°", 'L');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(model_orientation_yz, 0, 360, 90, 0, XLAT("model orientation (y/z plane)"), "");
|
||||
dialog::editNumber(vpconf.model_orientation_yz, 0, 360, 90, 0, XLAT("model orientation (y/z plane)"), "");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(GDIM == 3 && pmodel != mdPerspective) {
|
||||
if(GDIM == 3 && vpmodel != mdPerspective) {
|
||||
const string cliphelp = XLAT(
|
||||
"Your view of the 3D model is naturally bounded from four directions by your window. "
|
||||
"Here, you can also set up similar bounds in the Z direction. Radius of the ball/band "
|
||||
"models, and the distance from the center to the plane in the halfspace model, are 1.\n\n");
|
||||
dialog::addSelItem(XLAT("near clipping plane"), fts(clip_max), 'c');
|
||||
dialog::addSelItem(XLAT("near clipping plane"), fts(vpconf.clip_max), 'c');
|
||||
dialog::add_action([cliphelp] () {
|
||||
dialog::editNumber(clip_max, -10, 10, 0.2, 1, XLAT("near clipping plane"),
|
||||
dialog::editNumber(vpconf.clip_max, -10, 10, 0.2, 1, XLAT("near clipping plane"),
|
||||
cliphelp + XLAT("Objects with Z coordinate "
|
||||
"bigger than this parameter are not shown. This is useful with the models which "
|
||||
"extend infinitely in the Z direction, or if you want things close to your character "
|
||||
"to be not obscured by things closer to the camera."));
|
||||
});
|
||||
dialog::addSelItem(XLAT("far clipping plane"), fts(clip_min), 'C');
|
||||
dialog::addSelItem(XLAT("far clipping plane"), fts(vpconf.clip_min), 'C');
|
||||
dialog::add_action([cliphelp] () {
|
||||
dialog::editNumber(clip_min, -10, 10, 0.2, -1, XLAT("far clipping plane"),
|
||||
dialog::editNumber(vpconf.clip_min, -10, 10, 0.2, -1, XLAT("far clipping plane"),
|
||||
cliphelp + XLAT("Objects with Z coordinate "
|
||||
"smaller than this parameter are not shown; it also affects the fog effect"
|
||||
" (near clipping plane = 0% fog, far clipping plane = 100% fog)."));
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdPolynomial) {
|
||||
if(vpmodel == mdPolynomial) {
|
||||
dialog::addSelItem(XLAT("coefficient"),
|
||||
fts(polygonal::coefr[polygonal::coefid]), 'x');
|
||||
dialog::add_action([] () {
|
||||
@ -496,26 +492,26 @@ EX namespace models {
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdHalfplane) {
|
||||
dialog::addSelItem(XLAT("half-plane scale"), fts(halfplane_scale), 'b');
|
||||
if(vpmodel == mdHalfplane) {
|
||||
dialog::addSelItem(XLAT("half-plane scale"), fts(vpconf.halfplane_scale), 'b');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(halfplane_scale, 0, 2, 0.25, 1, XLAT("half-plane scale"), "");
|
||||
dialog::editNumber(vpconf.halfplane_scale, 0, 2, 0.25, 1, XLAT("half-plane scale"), "");
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdRotatedHyperboles) {
|
||||
dialog::addBoolItem_action(XLAT("use atan to make it finite"), use_atan, 'x');
|
||||
if(vpmodel == mdRotatedHyperboles) {
|
||||
dialog::addBoolItem_action(XLAT("use atan to make it finite"), vpconf.use_atan, 'x');
|
||||
}
|
||||
|
||||
if(pmodel == mdBall) {
|
||||
dialog::addSelItem(XLAT("projection in ball model"), fts(vid.ballproj), 'x');
|
||||
if(vpmodel == mdBall) {
|
||||
dialog::addSelItem(XLAT("projection in ball model"), fts(vpconf.ballproj), 'x');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(vid.ballproj, 0, 100, .1, 0, XLAT("projection in ball model"),
|
||||
dialog::editNumber(vpconf.ballproj, 0, 100, .1, 0, XLAT("projection in ball model"),
|
||||
"This parameter affects the ball model the same way as the projection parameter affects the disk model.");
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdPolygonal) {
|
||||
if(vpmodel == mdPolygonal) {
|
||||
dialog::addSelItem(XLAT("polygon sides"), its(polygonal::SI), 'x');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(polygonal::SI, 3, 10, 1, 4, XLAT("polygon sides"), "");
|
||||
@ -534,90 +530,91 @@ EX namespace models {
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdBall || pmodel == mdHyperboloid || pmodel == mdHemisphere || (pmodel == mdSpiral && spiral_cone != 360)) {
|
||||
dialog::addSelItem(XLAT("camera rotation in 3D models"), fts(vid.ballangle) + "°", 'b');
|
||||
if(is_3d(vpconf) && GDIM == 2) {
|
||||
dialog::addSelItem(XLAT("camera rotation in 3D models"), fts(vpconf.ballangle) + "°", 'b');
|
||||
dialog::add_action(config_camera_rotation);
|
||||
}
|
||||
|
||||
if(pmodel == mdHyperboloid) {
|
||||
dialog::addSelItem(XLAT("maximum z coordinate to show"), fts(top_z), 'l');
|
||||
if(vpmodel == mdHyperboloid) {
|
||||
dialog::addSelItem(XLAT("maximum z coordinate to show"), fts(vpconf.top_z), 'l');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(top_z, 1, 20, 0.25, 4, XLAT("maximum z coordinate to show"), "");
|
||||
dialog::editNumber(vpconf.top_z, 1, 20, 0.25, 4, XLAT("maximum z coordinate to show"), "");
|
||||
});
|
||||
}
|
||||
|
||||
if(model_has_transition()) {
|
||||
dialog::addSelItem(XLAT("model transition"), fts(model_transition), 't');
|
||||
if(has_transition(vpmodel)) {
|
||||
dialog::addSelItem(XLAT("model transition"), fts(vpconf.model_transition), 't');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(model_transition, 0, 1, 0.1, 1, XLAT("model transition"),
|
||||
dialog::editNumber(vpconf.model_transition, 0, 1, 0.1, 1, XLAT("model transition"),
|
||||
"You can change this parameter for a transition from another model to this one."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if(among(pmodel, mdJoukowsky, mdJoukowskyInverted, mdSpiral) && GDIM == 2) {
|
||||
dialog::addSelItem(XLAT("Möbius transformations"), fts(vid.skiprope) + "°", 'S');
|
||||
if(among(vpmodel, mdJoukowsky, mdJoukowskyInverted, mdSpiral) && GDIM == 2) {
|
||||
dialog::addSelItem(XLAT("Möbius transformations"), fts(vpconf.skiprope) + "°", 'S');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(vid.skiprope, 0, 360, 15, 0, XLAT("Möbius transformations"), "");
|
||||
dialog::editNumber(vpconf.skiprope, 0, 360, 15, 0, XLAT("Möbius transformations"), "");
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdHemisphere && euclid) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vid.euclid_to_sphere), 'l');
|
||||
if(vpmodel == mdHemisphere && euclid) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vpconf.euclid_to_sphere), 'l');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(vid.euclid_to_sphere, 0, 10, .1, 1, XLAT("parameter"),
|
||||
dialog::editNumber(vpconf.euclid_to_sphere, 0, 10, .1, 1, XLAT("parameter"),
|
||||
"Stereographic projection to a sphere. Choose the radius of the sphere."
|
||||
);
|
||||
dialog::scaleLog();
|
||||
});
|
||||
}
|
||||
|
||||
if(among(pmodel, mdTwoPoint, mdSimulatedPerspective, mdTwoHybrid)) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vid.twopoint_param), 'b');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(vid.twopoint_param, 1e-3, 10, .1, 1, XLAT("parameter"),
|
||||
if(among(vpmodel, mdTwoPoint, mdSimulatedPerspective, mdTwoHybrid)) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vpconf.twopoint_param), 'b');
|
||||
dialog::add_action([vpmodel](){
|
||||
dialog::editNumber(vpconf.twopoint_param, 1e-3, 10, .1, 1, XLAT("parameter"),
|
||||
s0 + (vpmodel == mdTwoPoint ?
|
||||
"This model maps the world so that the distances from two points "
|
||||
"are kept. This parameter gives the distance from the two points to "
|
||||
"are kept. " : "") + "This parameter gives the distance from the two points to "
|
||||
"the center."
|
||||
);
|
||||
dialog::scaleLog();
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdFisheye) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vid.fisheye_param), 'b');
|
||||
if(vpmodel == mdFisheye) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vpconf.fisheye_param), 'b');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(vid.fisheye_param, 1e-3, 10, .1, 1, XLAT("parameter"),
|
||||
dialog::editNumber(vpconf.fisheye_param, 1e-3, 10, .1, 1, XLAT("parameter"),
|
||||
"Size of the fish eye."
|
||||
);
|
||||
dialog::scaleLog();
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdCollignon) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vid.collignon_parameter) + (vid.collignon_reflected ? " (r)" : ""), 'b');
|
||||
if(vpmodel == mdCollignon) {
|
||||
dialog::addSelItem(XLAT("parameter"), fts(vpconf.collignon_parameter) + (vpconf.collignon_reflected ? " (r)" : ""), 'b');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(vid.collignon_parameter, -1, 1, .1, 1, XLAT("parameter"),
|
||||
dialog::editNumber(vpconf.collignon_parameter, -1, 1, .1, 1, XLAT("parameter"),
|
||||
""
|
||||
);
|
||||
dialog::extra_options = [] {
|
||||
dialog::addBoolItem_action(XLAT("reflect"), vid.collignon_reflected, 'R');
|
||||
dialog::addBoolItem_action(XLAT("reflect"), vpconf.collignon_reflected, 'R');
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdSpiral && !euclid) {
|
||||
dialog::addSelItem(XLAT("spiral angle"), fts(spiral_angle) + "°", 'x');
|
||||
if(vpmodel == mdSpiral && !euclid) {
|
||||
dialog::addSelItem(XLAT("spiral angle"), fts(vpconf.spiral_angle) + "°", 'x');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(spiral_angle, 0, 360, 15, 0, XLAT("spiral angle"),
|
||||
dialog::editNumber(vpconf.spiral_angle, 0, 360, 15, 0, XLAT("spiral angle"),
|
||||
XLAT("set to 90° for the ring projection")
|
||||
);
|
||||
});
|
||||
|
||||
ld& which =
|
||||
sphere ? sphere_spiral_multiplier :
|
||||
ring_not_spiral ? right_spiral_multiplier :
|
||||
any_spiral_multiplier;
|
||||
sphere ? vpconf.sphere_spiral_multiplier :
|
||||
ring_not_spiral ? vpconf.right_spiral_multiplier :
|
||||
vpconf.any_spiral_multiplier;
|
||||
|
||||
dialog::addSelItem(XLAT("spiral multiplier"), fts(which) + "°", 'M');
|
||||
dialog::add_action([&which](){
|
||||
@ -631,20 +628,20 @@ EX namespace models {
|
||||
);
|
||||
});
|
||||
|
||||
dialog::addSelItem(XLAT("spiral cone"), fts(spiral_cone) + "°", 'C');
|
||||
dialog::addSelItem(XLAT("spiral cone"), fts(vpconf.spiral_cone) + "°", 'C');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(spiral_cone, 0, 360, -45, 360, XLAT("spiral cone"), "");
|
||||
dialog::editNumber(vpconf.spiral_cone, 0, 360, -45, 360, XLAT("spiral cone"), "");
|
||||
});
|
||||
}
|
||||
|
||||
if(pmodel == mdSpiral && euclid) {
|
||||
dialog::addSelItem(XLAT("spiral period: x"), fts(spiral_x), 'x');
|
||||
if(vpmodel == mdSpiral && euclid) {
|
||||
dialog::addSelItem(XLAT("spiral period: x"), fts(vpconf.spiral_x), 'x');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(spiral_x, -20, 20, 1, 10, XLAT("spiral period: x"), "");
|
||||
dialog::editNumber(vpconf.spiral_x, -20, 20, 1, 10, XLAT("spiral period: x"), "");
|
||||
});
|
||||
dialog::addSelItem(XLAT("spiral period: y"), fts(spiral_y), 'y');
|
||||
dialog::addSelItem(XLAT("spiral period: y"), fts(vpconf.spiral_y), 'y');
|
||||
dialog::add_action([](){
|
||||
dialog::editNumber(spiral_y, -20, 20, 1, 10, XLAT("spiral period: y"), "");
|
||||
dialog::editNumber(vpconf.spiral_y, -20, 20, 1, 10, XLAT("spiral period: y"), "");
|
||||
});
|
||||
if(euclid && quotient) {
|
||||
dialog::addSelItem(XLAT("match the period"), its(spiral_id), 'n');
|
||||
@ -652,13 +649,13 @@ EX namespace models {
|
||||
}
|
||||
}
|
||||
|
||||
dialog::addSelItem(XLAT("vertical stretch"), fts(vid.stretch), 's');
|
||||
dialog::addSelItem(XLAT("vertical stretch"), fts(vpconf.stretch), 's');
|
||||
dialog::add_action(edit_stretch);
|
||||
|
||||
if(product_model()) {
|
||||
dialog::addSelItem(XLAT("product Z stretch"), fts(product_z_scale), 'Z');
|
||||
if(product_model(vpmodel)) {
|
||||
dialog::addSelItem(XLAT("product Z stretch"), fts(vpconf.product_z_scale), 'Z');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(product_z_scale, 0.1, 10, 0.1, 1, XLAT("product Z stretch"), "");
|
||||
dialog::editNumber(vpconf.product_z_scale, 0.1, 10, 0.1, 1, XLAT("product Z stretch"), "");
|
||||
dialog::scaleLog();
|
||||
});
|
||||
}
|
||||
@ -667,7 +664,7 @@ EX namespace models {
|
||||
bool shaderside_projection = get_shader_flags() & SF_DIRECT;
|
||||
if(vid.consider_shader_projection && !shaderside_projection)
|
||||
dialog::lastItem().value = XLAT("N/A");
|
||||
if(vid.consider_shader_projection && shaderside_projection && pmodel)
|
||||
if(vid.consider_shader_projection && shaderside_projection && vpmodel)
|
||||
dialog::lastItem().value += XLAT(" (2D only)");
|
||||
dialog::add_action([] { vid.consider_shader_projection = !vid.consider_shader_projection; });
|
||||
|
||||
@ -677,7 +674,7 @@ EX namespace models {
|
||||
dialog::addItem(XLAT("history mode"), 'a');
|
||||
dialog::add_action_push(history::history_menu);
|
||||
#if CAP_RUG
|
||||
if(GDIM == 2) {
|
||||
if(GDIM == 2 || rug::rugged) {
|
||||
dialog::addItem(XLAT("hypersian rug mode"), 'u');
|
||||
dialog::add_action_push(rug::show);
|
||||
}
|
||||
@ -707,39 +704,39 @@ EX namespace models {
|
||||
shift_arg_formula(history::extra_line_steps);
|
||||
}
|
||||
else if(argis("-stretch")) {
|
||||
PHASEFROM(2); shift_arg_formula(vid.stretch);
|
||||
PHASEFROM(2); shift_arg_formula(vpconf.stretch);
|
||||
}
|
||||
else if(argis("-PM")) {
|
||||
PHASEFROM(2); shift(); pmodel = read_model(args());
|
||||
if(pmodel == mdFormula) {
|
||||
shift(); basic_model = eModel(argi());
|
||||
shift(); formula = args();
|
||||
PHASEFROM(2); shift(); vpconf.model = read_model(args());
|
||||
if(vpconf.model == mdFormula) {
|
||||
shift(); vpconf.basic_model = eModel(argi());
|
||||
shift(); vpconf.formula = args();
|
||||
}
|
||||
}
|
||||
else if(argis("-ballangle")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(vid.ballangle);
|
||||
shift_arg_formula(vpconf.ballangle);
|
||||
}
|
||||
else if(argis("-topz")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::top_z);
|
||||
shift_arg_formula(vpconf.top_z);
|
||||
}
|
||||
else if(argis("-twopoint")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(vid.twopoint_param);
|
||||
shift_arg_formula(vpconf.twopoint_param);
|
||||
}
|
||||
else if(argis("-hp")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::halfplane_scale);
|
||||
shift_arg_formula(vpconf.halfplane_scale);
|
||||
}
|
||||
else if(argis("-mori")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::model_orientation);
|
||||
shift_arg_formula(vpconf.model_orientation);
|
||||
}
|
||||
else if(argis("-mori2")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::model_orientation);
|
||||
shift_arg_formula(models::model_orientation_yz);
|
||||
shift_arg_formula(vpconf.model_orientation);
|
||||
shift_arg_formula(vpconf.model_orientation_yz);
|
||||
}
|
||||
else if(argis("-crot")) {
|
||||
PHASEFROM(2);
|
||||
@ -749,43 +746,43 @@ EX namespace models {
|
||||
}
|
||||
else if(argis("-clip")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::clip_min);
|
||||
shift_arg_formula(models::clip_max);
|
||||
shift_arg_formula(vpconf.clip_min);
|
||||
shift_arg_formula(vpconf.clip_max);
|
||||
}
|
||||
else if(argis("-mtrans")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::model_transition);
|
||||
shift_arg_formula(vpconf.model_transition);
|
||||
}
|
||||
else if(argis("-sang")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::spiral_angle);
|
||||
shift_arg_formula(vpconf.spiral_angle);
|
||||
if(sphere)
|
||||
shift_arg_formula(models::sphere_spiral_multiplier);
|
||||
else if(models::spiral_angle == 90)
|
||||
shift_arg_formula(models::right_spiral_multiplier);
|
||||
shift_arg_formula(vpconf.sphere_spiral_multiplier);
|
||||
else if(vpconf.spiral_angle == 90)
|
||||
shift_arg_formula(vpconf.right_spiral_multiplier);
|
||||
}
|
||||
else if(argis("-ssm")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::any_spiral_multiplier);
|
||||
shift_arg_formula(vpconf.any_spiral_multiplier);
|
||||
}
|
||||
else if(argis("-scone")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::spiral_cone);
|
||||
shift_arg_formula(vpconf.spiral_cone);
|
||||
}
|
||||
else if(argis("-sxy")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(models::spiral_x);
|
||||
shift_arg_formula(models::spiral_y);
|
||||
shift_arg_formula(vpconf.spiral_x);
|
||||
shift_arg_formula(vpconf.spiral_y);
|
||||
}
|
||||
else if(argis("-mob")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(vid.skiprope);
|
||||
shift_arg_formula(vpconf.skiprope);
|
||||
}
|
||||
else if(argis("-zoom")) {
|
||||
PHASEFROM(2); shift_arg_formula(vid.scale);
|
||||
PHASEFROM(2); shift_arg_formula(vpconf.scale);
|
||||
}
|
||||
else if(argis("-alpha")) {
|
||||
PHASEFROM(2); shift_arg_formula(vid.alpha);
|
||||
PHASEFROM(2); shift_arg_formula(vpconf.alpha);
|
||||
}
|
||||
else if(argis("-d:model"))
|
||||
launch_dialog(model_menu);
|
||||
|
@ -307,7 +307,7 @@ EX namespace netgen {
|
||||
renderbuffer rbuf(2000, 2000, vid.usingGL);
|
||||
|
||||
dynamicval<videopar> dv(vid, vid);
|
||||
vid.xres = vid.yres = 2000; vid.scale = 0.99;
|
||||
vid.xres = vid.yres = 2000; pconf.scale = 0.99;
|
||||
|
||||
if(1) {
|
||||
resetbuffer rb;
|
||||
|
106
nonisotropic.cpp
106
nonisotropic.cpp
@ -104,7 +104,7 @@ EX namespace sn {
|
||||
hyperpoint res;
|
||||
|
||||
if(lazy) {
|
||||
return decompress(get_int(int(ix), int(iy), int(iz)));
|
||||
return decompress(get_int(int(ix+.5), int(iy+.5), int(iz+.5)));
|
||||
}
|
||||
|
||||
else {
|
||||
@ -552,7 +552,7 @@ EX namespace sn {
|
||||
}
|
||||
}
|
||||
|
||||
EX hyperpoint get_inverse_exp_symsol(hyperpoint h, bool lazy, bool just_direction) {
|
||||
EX hyperpoint get_inverse_exp_symsol(hyperpoint h, flagtype flags) {
|
||||
auto& s = get_tabled();
|
||||
s.load();
|
||||
|
||||
@ -562,18 +562,17 @@ EX namespace sn {
|
||||
|
||||
if(h[2] < 0.) { iz = -iz; swap(ix, iy); }
|
||||
|
||||
hyperpoint res = s.get(ix, iy, iz, lazy);
|
||||
hyperpoint res = s.get(ix, iy, iz, flags & pfNO_INTERPOLATION);
|
||||
|
||||
if(h[2] < 0.) { swap(res[0], res[1]); res[2] = -res[2]; }
|
||||
if(h[0] < 0.) res[0] = -res[0];
|
||||
if(h[1] < 0.) res[1] = -res[1];
|
||||
|
||||
if(!just_direction) return table_to_azeq(res);
|
||||
|
||||
return res;
|
||||
if(flags & pfNO_DISTANCE) return res;
|
||||
return table_to_azeq(res);
|
||||
}
|
||||
|
||||
EX hyperpoint get_inverse_exp_nsym(hyperpoint h, bool lazy, bool just_direction) {
|
||||
EX hyperpoint get_inverse_exp_nsym(hyperpoint h, flagtype flags) {
|
||||
auto& s = get_tabled();
|
||||
s.load();
|
||||
|
||||
@ -581,14 +580,13 @@ EX namespace sn {
|
||||
ld iy = h[1] >= 0. ? sn::x_to_ix(h[1]) : sn::x_to_ix(-h[1]);
|
||||
ld iz = sn::z_to_iz(h[2]);
|
||||
|
||||
hyperpoint res = s.get(ix, iy, iz, lazy);
|
||||
hyperpoint res = s.get(ix, iy, iz, flags & pfNO_INTERPOLATION);
|
||||
|
||||
if(h[0] < 0.) res[0] = -res[0];
|
||||
if(h[1] < 0.) res[1] = -res[1];
|
||||
|
||||
if(!just_direction) return table_to_azeq(res);
|
||||
|
||||
return res;
|
||||
if(flags & pfNO_DISTANCE) return res;
|
||||
return table_to_azeq(res);
|
||||
}
|
||||
|
||||
EX string shader_symsol = sn::common +
|
||||
@ -745,7 +743,7 @@ EX namespace nilv {
|
||||
);
|
||||
}
|
||||
|
||||
EX hyperpoint get_inverse_exp(hyperpoint h, int iterations) {
|
||||
EX hyperpoint get_inverse_exp(hyperpoint h, flagtype prec IS(pNORMAL)) {
|
||||
ld wmin, wmax;
|
||||
|
||||
ld side = h[2] - h[0] * h[1] / 2;
|
||||
@ -769,11 +767,13 @@ EX namespace nilv {
|
||||
|
||||
ld s = sin(2 * alpha_total);
|
||||
|
||||
int max_iter = (prec & pfLOW_BS_ITER) ? 5 : 20;
|
||||
|
||||
for(int it=0;; it++) {
|
||||
ld w = (wmin + wmax) / 2;
|
||||
ld z = b * b * (s + (sin(w) - w)/(cos(w) - 1)) + w;
|
||||
|
||||
if(it == iterations) {
|
||||
if(it == max_iter) {
|
||||
ld alpha = alpha_total - w/2;
|
||||
ld c = b / sin(w/2);
|
||||
return point3(c * w * cos(alpha), c * w * sin(alpha), w);
|
||||
@ -967,7 +967,7 @@ EX namespace nilv {
|
||||
|
||||
EX hyperpoint on_geodesic(hyperpoint s0, hyperpoint s1, ld x) {
|
||||
hyperpoint local = inverse(nisot::translate(s0)) * s1;
|
||||
hyperpoint h = get_inverse_exp(local, 100);
|
||||
hyperpoint h = get_inverse_exp(local);
|
||||
return nisot::translate(s0) * formula_exp(h * x);
|
||||
}
|
||||
|
||||
@ -1822,7 +1822,7 @@ EX namespace rots {
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
hyperpoint h = tC0(T);
|
||||
Spin = inverse(gpushxto0(h) * T);
|
||||
d = hr::inverse_exp(h, iTable);
|
||||
d = hr::inverse_exp(h);
|
||||
alpha = atan2(Spin[0][1], Spin[0][0]);
|
||||
distance = hdist0(h);
|
||||
beta = atan2(h[1], h[0]);
|
||||
@ -1933,8 +1933,8 @@ EX namespace rots {
|
||||
dynamicval<transmatrix> m3(playerV, Id);
|
||||
dynamicval<transmatrix> m4(actual_view_transform, Id);
|
||||
dynamicval<eModel> pm(pmodel, mdDisk);
|
||||
dynamicval<ld> pss(vid.scale, (sphere ? 10 : 1) * underlying_scale);
|
||||
dynamicval<ld> psa(vid.alpha, sphere ? 10 : 1);
|
||||
dynamicval<ld> pss(pconf.scale, (sphere ? 10 : 1) * underlying_scale);
|
||||
dynamicval<ld> psa(pconf.alpha, sphere ? 10 : 1);
|
||||
dynamicval<hrmap*> p(hybrid::pmap, NULL);
|
||||
dynamicval<int> psr(sightrange_bonus, 0);
|
||||
calcparam();
|
||||
@ -1970,25 +1970,29 @@ EX namespace nisot {
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
EX void geodesic_step(hyperpoint& at, hyperpoint& velocity) {
|
||||
auto acc = christoffel(at, velocity, velocity);
|
||||
|
||||
auto at2 = at + velocity / 2;
|
||||
auto velocity2 = velocity + acc / 2;
|
||||
|
||||
auto acc2 = christoffel(at2, velocity2, velocity2);
|
||||
|
||||
at = at + velocity + acc2 / 2;
|
||||
|
||||
velocity = velocity + acc;
|
||||
|
||||
EX hyperpoint get_acceleration(const hyperpoint& at, const hyperpoint& vel) {
|
||||
return christoffel(at, vel, vel);
|
||||
}
|
||||
|
||||
EX hyperpoint numerical_exp(hyperpoint v, int steps) {
|
||||
EX void geodesic_step(hyperpoint& at, hyperpoint& vel) {
|
||||
/* RK4 method */
|
||||
auto acc1 = get_acceleration(at, vel);
|
||||
auto acc2 = get_acceleration(at + vel/2, vel + acc1/2);
|
||||
auto acc3 = get_acceleration(at + vel/2 + acc1/4, vel + acc2/2);
|
||||
auto acc4 = get_acceleration(at + vel + acc2/2, vel + acc3);
|
||||
|
||||
at += vel + (acc1+acc2+acc3)/6;
|
||||
vel += (acc1+2*acc2+2*acc3+acc4)/6;
|
||||
}
|
||||
|
||||
EX int rk_steps = 20;
|
||||
|
||||
EX hyperpoint numerical_exp(hyperpoint v) {
|
||||
hyperpoint at = point31(0, 0, 0);
|
||||
v /= steps;
|
||||
v /= rk_steps;
|
||||
v[3] = 0;
|
||||
for(int i=0; i<steps; i++) geodesic_step(at, v);
|
||||
for(int i=0; i<rk_steps; i++) geodesic_step(at, v);
|
||||
return at;
|
||||
}
|
||||
|
||||
@ -2009,13 +2013,34 @@ EX namespace nisot {
|
||||
}
|
||||
else h = Pos * h;
|
||||
|
||||
int steps = 100;
|
||||
int steps = rk_steps;
|
||||
h /= steps;
|
||||
|
||||
auto& at = tPos[3];
|
||||
auto& vel = h;
|
||||
|
||||
for(int i=0; i<steps; i++) {
|
||||
for(int j=0; j<3; j++)
|
||||
tPos[j] += christoffel(tPos[3], h, tPos[j]);
|
||||
geodesic_step(tPos[3], h);
|
||||
auto acc1 = get_acceleration(at, vel);
|
||||
auto at1 = at + vel/2; auto vel1 = vel + acc1/2;
|
||||
auto acc2 = get_acceleration(at1, vel1);
|
||||
auto at2 = at1 + acc1/4; auto vel2 = vel + acc2/2;
|
||||
auto acc3 = get_acceleration(at2, vel2);
|
||||
auto at3 = at + vel + acc2/2; auto vel3 = vel + acc3;
|
||||
auto acc4 = get_acceleration(at3, vel3);
|
||||
|
||||
for(int j=0; j<3; j++) {
|
||||
auto& tra = tPos[j];
|
||||
|
||||
auto tacc1 = christoffel(at, vel, tra);
|
||||
auto tacc2 = christoffel(at1, vel1, tra + tacc1/2);
|
||||
auto tacc3 = christoffel(at2, vel2, tra + tacc2/2);
|
||||
auto tacc4 = christoffel(at3, vel3, tra + tacc3);
|
||||
|
||||
tra += (tacc1+tacc2*2+tacc3*2+tacc4) / 6;
|
||||
}
|
||||
|
||||
at += vel + (acc1+acc2+acc3)/6;
|
||||
vel += (acc1+2*acc2+2*acc3+acc4)/6;
|
||||
}
|
||||
|
||||
if(sl2) {
|
||||
@ -2043,12 +2068,12 @@ EX namespace nisot {
|
||||
return parallel_transport_bare(P, direction);
|
||||
}
|
||||
|
||||
EX transmatrix spin_towards(const transmatrix Position, const hyperpoint goal) {
|
||||
EX transmatrix spin_towards(const transmatrix Position, const hyperpoint goal, flagtype prec IS(pNORMAL)) {
|
||||
|
||||
hyperpoint at = tC0(Position);
|
||||
transmatrix push_back = inverse(translate(at));
|
||||
hyperpoint back_goal = push_back * goal;
|
||||
back_goal = inverse_exp(back_goal, iTable);
|
||||
back_goal = inverse_exp(back_goal, prec);
|
||||
|
||||
transmatrix back_Position = push_back * Position;
|
||||
|
||||
@ -2131,6 +2156,11 @@ EX namespace nisot {
|
||||
shift_arg_formula(nilv::nilwidth);
|
||||
return 0;
|
||||
}
|
||||
else if(argis("-rk-steps")) {
|
||||
PHASEFROM(2);
|
||||
shift(); rk_steps = argi();
|
||||
return 0;
|
||||
}
|
||||
else if(argis("-nilv")) {
|
||||
PHASEFROM(2);
|
||||
if(nil) stop_game();
|
||||
|
@ -81,7 +81,7 @@ bool ishex2(cell *c) {
|
||||
else return c->master->c7 != c;
|
||||
}
|
||||
|
||||
int chessvalue(cell *c) {
|
||||
EX int chessvalue(cell *c) {
|
||||
#if CAP_ARCM
|
||||
if(arcm::in())
|
||||
return arcm::chessvalue(c);
|
||||
@ -2938,6 +2938,10 @@ int read_pattern_args() {
|
||||
lp->color = arghex();
|
||||
}
|
||||
|
||||
else if(argis("-fat-edges")) {
|
||||
PHASEFROM(2); shift(); fat_edges = argi();
|
||||
}
|
||||
|
||||
else if(argis("-palw")) {
|
||||
PHASEFROM(2);
|
||||
shift(); string ss = args();
|
||||
|
@ -756,7 +756,7 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
|
||||
ld yy = log(2) / 2;
|
||||
|
||||
bshape(shWall3D[id], PPR::WALL);
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
last->flags |= POLY_TRIANGLES | POLY_PRINTABLE;
|
||||
|
||||
hyperpoint center = Hypc;
|
||||
int n = isize(vertices);
|
||||
@ -842,8 +842,13 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
|
||||
hpcpush(mid(C0, hpc[a]));
|
||||
if(shWall3D[id].flags & POLY_TRIANGLES)
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
if(shWall3D[id].flags & POLY_PRINTABLE)
|
||||
last->flags |= POLY_PRINTABLE;
|
||||
|
||||
finishshape();
|
||||
|
||||
shWall3D[id].intester = C0;
|
||||
shMiniWall3D[id].intester = C0;
|
||||
|
||||
shPlainWall3D[id] = shWall3D[id]; // force_triangles ? shWall3D[id] : shWireframe3D[id];
|
||||
}
|
||||
|
10
quit.cpp
10
quit.cpp
@ -274,13 +274,13 @@ EX hint hints[] = {
|
||||
specialland = laHalloween;
|
||||
set_geometry(gSphere);
|
||||
start_game();
|
||||
vid.alpha = 999;
|
||||
vid.scale = 998;
|
||||
pconf.alpha = 999;
|
||||
pconf.scale = 998;
|
||||
}
|
||||
else {
|
||||
resetModes();
|
||||
vid.alpha = 1;
|
||||
vid.scale = 1;
|
||||
pconf.alpha = 1;
|
||||
pconf.scale = 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -415,7 +415,7 @@ EX void showMission() {
|
||||
if(canmove) {
|
||||
if(sphere) {
|
||||
dialog::addItem(XLAT("return to your game"), '1');
|
||||
dialog::addItem(XLAT(vid.alpha < 2 ? "orthogonal projection" : "stereographic projection"), '3');
|
||||
dialog::addItem(XLAT(pconf.alpha < 2 ? "orthogonal projection" : "stereographic projection"), '3');
|
||||
}
|
||||
else if(euclid) {
|
||||
dialog::addItem(XLAT("return to your game"), '2');
|
||||
|
55
racing.cpp
55
racing.cpp
@ -939,15 +939,15 @@ void race_projection() {
|
||||
|
||||
dialog::init(XLAT("racing projections"));
|
||||
|
||||
dialog::addBoolItem(XLAT("Poincaré disk model"), pmodel == mdDisk && !vid.camera_angle, '1');
|
||||
dialog::addBoolItem(XLAT("Poincaré disk model"), pmodel == mdDisk && !pconf.camera_angle, '1');
|
||||
dialog::add_action([] () {
|
||||
pmodel = mdDisk;
|
||||
race_advance = 0;
|
||||
vid.yshift = 0;
|
||||
vid.camera_angle = 0;
|
||||
vid.xposition = 0;
|
||||
vid.yposition = 0;
|
||||
vid.scale = 1;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = 0;
|
||||
pconf.scale = 1;
|
||||
vid.use_smart_range = 0;
|
||||
vid.smart_range_detail = 3;
|
||||
});
|
||||
@ -955,13 +955,13 @@ void race_projection() {
|
||||
dialog::addBoolItem(XLAT("band"), pmodel == mdBand, '2');
|
||||
dialog::add_action([] () {
|
||||
pmodel = mdBand;
|
||||
models::model_orientation = race_angle;
|
||||
pconf.model_orientation = race_angle;
|
||||
race_advance = 1;
|
||||
vid.yshift = 0;
|
||||
vid.camera_angle = 0;
|
||||
vid.xposition = 0;
|
||||
vid.yposition = 0;
|
||||
vid.scale = 1;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = 0;
|
||||
pconf.scale = 1;
|
||||
vid.use_smart_range = 1;
|
||||
vid.smart_range_detail = 3;
|
||||
});
|
||||
@ -969,26 +969,26 @@ void race_projection() {
|
||||
dialog::addBoolItem(XLAT("half-plane"), pmodel == mdHalfplane, '3');
|
||||
dialog::add_action([] () {
|
||||
pmodel = mdHalfplane;
|
||||
models::model_orientation = race_angle + 90;
|
||||
pconf.model_orientation = race_angle + 90;
|
||||
race_advance = 0.5;
|
||||
vid.yshift = 0;
|
||||
vid.camera_angle = 0;
|
||||
vid.xposition = 0;
|
||||
vid.yposition = 0;
|
||||
vid.scale = 1;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = 0;
|
||||
pconf.scale = 1;
|
||||
vid.use_smart_range = 1;
|
||||
vid.smart_range_detail = 3;
|
||||
});
|
||||
|
||||
dialog::addBoolItem(XLAT("third-person perspective"), pmodel == mdDisk && vid.camera_angle, '4');
|
||||
dialog::addBoolItem(XLAT("third-person perspective"), pmodel == mdDisk && pconf.camera_angle, '4');
|
||||
dialog::add_action([] () {
|
||||
pmodel = mdDisk;
|
||||
race_advance = 0;
|
||||
vid.yshift = -0.3;
|
||||
vid.camera_angle = -45;
|
||||
vid.scale = 18/16. * vid.xres / vid.yres / multi::players;
|
||||
vid.xposition = 0;
|
||||
vid.yposition = -0.9;
|
||||
pconf.camera_angle = -45;
|
||||
pconf.scale = 18/16. * vid.xres / vid.yres / multi::players;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = -0.9;
|
||||
vid.use_smart_range = 1;
|
||||
vid.smart_range_detail = 3;
|
||||
});
|
||||
@ -1011,8 +1011,8 @@ void race_projection() {
|
||||
dialog::addSelItem(XLAT("race angle"), fts(race_angle), 'a');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(race_angle, 0, 360, 15, 90, XLAT("race angle"), "");
|
||||
int q = models::model_orientation - race_angle;
|
||||
dialog::reaction = [q] () { models::model_orientation = race_angle + q; };
|
||||
int q = pconf.model_orientation - race_angle;
|
||||
dialog::reaction = [q] () { pconf.model_orientation = race_angle + q; };
|
||||
});
|
||||
}
|
||||
|
||||
@ -1060,6 +1060,7 @@ void race_projection() {
|
||||
|
||||
bool alternate = false;
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
EX void thurston_racing() {
|
||||
gamescreen(1);
|
||||
dialog::init(XLAT("racing in Thurston geometries"));
|
||||
@ -1085,16 +1086,20 @@ void race_projection() {
|
||||
add_thurston_race(XLAT("Euclidean"), [] { stop_game(); euc::clear_torus3(); set_geometry(gBitrunc3); });
|
||||
add_thurston_race(XLAT("hyperbolic"), [] { set_geometry(gBinary3); vid.texture_step = 4; });
|
||||
add_thurston_race(XLAT("spherical"), [] { set_geometry(gCell120); });
|
||||
#if CAP_SOLV
|
||||
add_thurston_race(XLAT("Solv geometry"), [] { sn::solrange_xy = 10; sn::solrange_z = 3; set_geometry(gSol); });
|
||||
#endif
|
||||
add_thurston_race(XLAT("S2xE"), [] { set_geometry(gSphere); set_variation(eVariation::bitruncated); set_geometry(gProduct); });
|
||||
add_thurston_race(XLAT("H2xE"), [] { set_geometry(gNormal); set_variation(eVariation::bitruncated); set_geometry(gProduct); });
|
||||
add_thurston_race(XLAT("Nil"), [] { stop_game(); nilv::nilperiod[0] = 0; set_geometry(gNil); });
|
||||
add_thurston_race(XLAT("PSL(2,R)"), [] { set_geometry(gNormal); set_variation(eVariation::pure); set_geometry(gRotSpace); });
|
||||
}
|
||||
else {
|
||||
#if CAP_SOLV
|
||||
add_thurston_race(XLAT("stretched hyperbolic"), [] { set_geometry(gNIH); vid.texture_step = 4; });
|
||||
add_thurston_race(XLAT("stretched Solv"), [] { set_geometry(gSolN); sn::solrange_xy = 10; sn::solrange_z = 3; vid.texture_step = 4; });
|
||||
add_thurston_race(XLAT("periodic Solv"), [] { stop_game(); sn::solrange_xy = 5; sn::solrange_z = 2; asonov::period_xy = 8; asonov::period_z = 0; asonov::set_flags(); set_geometry(gArnoldCat); });
|
||||
#endif
|
||||
add_thurston_race(XLAT("hyperbolic crystal"), [] { set_geometry(gCrystal344); vid.texture_step = 4; });
|
||||
add_thurston_race(XLAT("torus x E"), [] { stop_game(); euc::eu_input = euc::torus3(4, 4, 0); set_geometry(gCubeTiling); });
|
||||
add_thurston_race(XLAT("hyperbolic regular"), [] { set_geometry(gSpace534); });
|
||||
@ -1108,6 +1113,7 @@ void race_projection() {
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
#endif
|
||||
|
||||
void raceconfigurer() {
|
||||
|
||||
@ -1195,8 +1201,10 @@ void race_projection() {
|
||||
});
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
dialog::addItem(XLAT("racing in Thurston geometries"), 'T');
|
||||
dialog::add_action_push(thurston_racing);
|
||||
#endif
|
||||
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
@ -1373,8 +1381,7 @@ EX void drawStats() {
|
||||
|
||||
if(!racing::on) return;
|
||||
|
||||
dynamicval<eModel> pm(pmodel, flat_model());
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
flat_model_enabler fme;
|
||||
initquickqueue();
|
||||
|
||||
int bsize = vid.fsize * 2;
|
||||
|
@ -26,7 +26,7 @@ pair<bool, hyperpoint> makeradar(hyperpoint h) {
|
||||
ld d = hdist0(h);
|
||||
|
||||
if(sol && nisot::geodesic_movement) {
|
||||
h = inverse_exp(h, iLazy);
|
||||
h = inverse_exp(h, pQUICK);
|
||||
ld r = hypot_d(3, h);
|
||||
if(r < 1) h = h * (atanh(r) / r);
|
||||
else return {false, h};
|
||||
|
@ -25,7 +25,7 @@ EX int want_use = 1;
|
||||
|
||||
EX ld exp_start = 1, exp_decay_exp = 4, exp_decay_poly = 10;
|
||||
|
||||
EX ld maxstep_sol = .02;
|
||||
EX ld maxstep_sol = .05;
|
||||
EX ld maxstep_nil = .1;
|
||||
EX ld minstep = .001;
|
||||
|
||||
@ -479,6 +479,10 @@ void enable_raycaster() {
|
||||
" return vec4(x*vel.y*tra.y - 0.5*dot(vel.yz,tra.zy), -.5*x*dot(vel.yx,tra.xy) + .5 * dot(vel.zx,tra.xz), -.5*(x*x-1.)*dot(vel.yx,tra.xy)+.5*x*dot(vel.zx,tra.xz), 0.);\n"
|
||||
// " return vec4(0.,0.,0.,0.);\n"
|
||||
" }\n";
|
||||
|
||||
fsh += "mediump vec4 get_acc(mediump vec4 pos, mediump vec4 vel) {\n"
|
||||
" return christoffel(pos, vel, vel);\n"
|
||||
" }\n";
|
||||
|
||||
if(sn::in() && !asonov) fsh += "uniform mediump float uBinaryWidth;\n";
|
||||
|
||||
@ -502,12 +506,13 @@ void enable_raycaster() {
|
||||
if(nil) fmain += "tangent = translate(position, itranslate(position, tangent));\n";
|
||||
|
||||
if(sn::in()) fmain +=
|
||||
"mediump vec4 acc = christoffel(position, tangent, tangent);\n"
|
||||
"mediump vec4 pos2 = position + tangent * dist / 2.;\n"
|
||||
"mediump vec4 tan2 = tangent + acc * dist / 2.;\n"
|
||||
"mediump vec4 acc2 = christoffel(pos2, tan2, tan2);\n"
|
||||
"mediump vec4 nposition = position + tangent * dist + acc2 / 2. * dist * dist;\n";
|
||||
|
||||
"mediump vec4 vel = tangent * dist;\n"
|
||||
"mediump vec4 acc1 = get_acc(position, vel);\n"
|
||||
"mediump vec4 acc2 = get_acc(position + vel / 2., vel + acc1/2.);\n"
|
||||
"mediump vec4 acc3 = get_acc(position + vel / 2. + acc1/4., vel + acc2/2.);\n"
|
||||
"mediump vec4 acc4 = get_acc(position + vel + acc2/2., vel + acc3/2.);\n"
|
||||
"mediump vec4 nposition = position + vel + (acc1+acc2+acc3)/6.;\n";
|
||||
|
||||
if(nil) {
|
||||
fmain +=
|
||||
"mediump vec4 xp, xt;\n"
|
||||
@ -629,7 +634,7 @@ void enable_raycaster() {
|
||||
"position = nposition;\n";
|
||||
|
||||
if(!nil) fmain +=
|
||||
"tangent = tangent + acc * dist;\n";
|
||||
"tangent = tangent + (acc1+2.*acc2+2.*acc3+acc4)/(6.*dist);\n";
|
||||
}
|
||||
else fmain +=
|
||||
"position = position + tangent * dist;\n";
|
||||
@ -1138,7 +1143,7 @@ EX void configure() {
|
||||
if(nonisotropic) {
|
||||
dialog::addSelItem(XLAT("max step"), fts(maxstep_current()), 'x');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(maxstep_current(), 1e-6, 1, 0.1, sol ? 0.03 : 0.1, XLAT("max step"), "affects the precision of solving the geodesic equation in Solv");
|
||||
dialog::editNumber(maxstep_current(), 1e-6, 1, 0.1, sol ? 0.05 : 0.1, XLAT("max step"), "affects the precision of solving the geodesic equation in Solv");
|
||||
dialog::scaleLog();
|
||||
dialog::bound_low(1e-9);
|
||||
dialog::reaction = reset_raycaster;
|
||||
|
6
reg3.cpp
6
reg3.cpp
@ -122,8 +122,8 @@ EX namespace reg3 {
|
||||
vertex_distance = binsearch(0, M_PI, [&] (ld d) {
|
||||
// sometimes breaks in elliptic
|
||||
dynamicval<eGeometry> g(geometry, elliptic ? gCell120 : geometry);
|
||||
hyperpoint v2 = direct_exp(dir_v2 * d, iTable);
|
||||
hyperpoint v3 = direct_exp(dir_v3 * d, iTable);
|
||||
hyperpoint v2 = direct_exp(dir_v2 * d);
|
||||
hyperpoint v3 = direct_exp(dir_v3 * d);
|
||||
return hdist(v2, v3) >= edge_length;
|
||||
});
|
||||
}
|
||||
@ -131,7 +131,7 @@ EX namespace reg3 {
|
||||
DEBB(DF_GEOM, ("vertex_distance = ", vertex_distance));
|
||||
|
||||
/* actual vertex */
|
||||
hyperpoint v2 = direct_exp(dir_v2 * vertex_distance, iTable);
|
||||
hyperpoint v2 = direct_exp(dir_v2 * vertex_distance);
|
||||
|
||||
hyperpoint mid = Hypc;
|
||||
for(int i=0; i<face; i++) mid += cspin(1, 2, 2*i*M_PI/face) * v2;
|
||||
|
@ -395,15 +395,15 @@ void bantar_frame() {
|
||||
map<int, map<int, vector<unique_ptr<drawqueueitem>>>> xptds;
|
||||
for(int i=0; i<4; i++) for(auto& p: subscr[i])
|
||||
xptds[int(p->prio)][i].push_back(move(p));
|
||||
|
||||
|
||||
for(auto& sm: xptds) for(auto& sm2: sm.second) {
|
||||
int i = sm2.first;
|
||||
ptds.clear();
|
||||
for(auto& p: sm2.second) ptds.push_back(move(p));
|
||||
|
||||
vid.scale = .5;
|
||||
vid.xposition = (!(i&2)) ? xdst : -xdst;
|
||||
vid.yposition = (!(i&1)) ? ydst : -ydst;
|
||||
pconf.scale = .5;
|
||||
pconf.xposition = (!(i&2)) ? xdst : -xdst;
|
||||
pconf.yposition = (!(i&1)) ? ydst : -ydst;
|
||||
calcparam();
|
||||
drawqueue();
|
||||
}
|
||||
@ -436,8 +436,8 @@ void bantar_anim() {
|
||||
breakanim = true;
|
||||
}
|
||||
mapeditor::drawplayer = true;
|
||||
vid.xposition = vid.yposition = 0;
|
||||
vid.scale = 1;
|
||||
pconf.xposition = pconf.yposition = 0;
|
||||
pconf.scale = 1;
|
||||
}
|
||||
|
||||
bool bmap;
|
||||
|
@ -145,7 +145,7 @@ void collatz_video(const string &fname) {
|
||||
if(vizid == &collatz_id) {
|
||||
sightrange_bonus = 3;
|
||||
genrange_bonus = 3;
|
||||
dronemode = true; vid.camera_angle = -45; rog3 = true; patterns::whichShape = '8';
|
||||
dronemode = true; pconf.camera_angle = -45; rog3 = true; patterns::whichShape = '8';
|
||||
vid.aurastr = 512;
|
||||
|
||||
collatz::lookup(763, 60);
|
||||
|
@ -103,7 +103,7 @@ namespace flocking {
|
||||
for(int i=0; i<isize(cl.lst); i++) {
|
||||
cell *c2 = cl.lst[i];
|
||||
transmatrix T = calc_relative_matrix(c2, c1, C0);
|
||||
if(hypot_d(WDIM, inverse_exp(tC0(T), iTable, false)) <= check_range) {
|
||||
if(hypot_d(WDIM, inverse_exp(tC0(T))) <= check_range) {
|
||||
relmatrices[c1][c2] = T;
|
||||
forCellEx(c3, c2) cl.add(c3);
|
||||
}
|
||||
@ -198,7 +198,7 @@ namespace flocking {
|
||||
// at2 is like m2->at but relative to m->at
|
||||
|
||||
// m2's position relative to m (tC0 means *(0,0,1))
|
||||
hyperpoint ac = inverse_exp(tC0(at2), iTable, false);
|
||||
hyperpoint ac = inverse_exp(tC0(at2));
|
||||
if(use_rot) ac = Rot * ac;
|
||||
|
||||
// distance and azimuth to m2
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "../hyper.h"
|
||||
|
||||
#if !ISWEB
|
||||
|
||||
namespace hr {
|
||||
|
||||
eGeometry gJanko1(eGeometry(-1));
|
||||
@ -27,7 +29,7 @@ struct jmatrix : array<array<int, 7>, 7> {
|
||||
};
|
||||
|
||||
vector<jmatrix> jms;
|
||||
unordered_map<jmatrix, int> ids;
|
||||
std::unordered_map<jmatrix, int> ids;
|
||||
|
||||
jmatrix J, Z, id;
|
||||
|
||||
@ -142,3 +144,4 @@ auto shot_hooks = addHook(hooks_args, 100, [] {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -638,11 +638,11 @@ void draw_ncee() {
|
||||
nctinf2.tvertices.clear();
|
||||
|
||||
ld map_ypos = vid.yres * (mapping_split + 1) / 2 - cd->ycenter;
|
||||
ld sca2 = (vid.yres * (1-mapping_split) / 2 - 10) / vid.scale;
|
||||
ld sca2 = (vid.yres * (1-mapping_split) / 2 - 10) / pconf.scale;
|
||||
|
||||
if(show_mapping) {
|
||||
for(int iter=-10; iter<=10; iter++) {
|
||||
ld maxx = period * vid.scale / 4;
|
||||
ld maxx = period * pconf.scale / 4;
|
||||
ld scax = sca2 * maxx / 0.5;
|
||||
ld xpos = scax * 2 * iter;
|
||||
curvepoint(hpxy(xpos-scax, map_ypos-sca2));
|
||||
@ -714,7 +714,7 @@ void draw_ncee() {
|
||||
z = !z;
|
||||
for(int s=0; s<3; s++) {
|
||||
curvepoint(hc(c[s].x, c[s].y));
|
||||
nctinf.tvertices.push_back(glhr::makevertex((vx[c[s].y][c[s].x]/cscale-delta)*vid.scale/2+.5, vy[c[s].y][c[s].x]*vid.scale/2+.5, 0));
|
||||
nctinf.tvertices.push_back(glhr::makevertex((vx[c[s].y][c[s].x]/cscale-delta)*pconf.scale/2+.5, vy[c[s].y][c[s].x]*pconf.scale/2+.5, 0));
|
||||
}
|
||||
};
|
||||
|
||||
@ -800,7 +800,7 @@ void prepare_ncee_map() {
|
||||
dynamicval<int> cgl(vid.cells_generated_limit, 9999999);
|
||||
dynamicval<bool> r(rug::display_warning, false);
|
||||
// vid.consider_shader_projection = false;
|
||||
vid.scale = 0.5;
|
||||
pconf.scale = 0.5;
|
||||
rug::init();
|
||||
rug::prepareTexture();
|
||||
rug::rugged = false;
|
||||
|
@ -34,7 +34,7 @@ array<hyperpoint, 3> mts;
|
||||
|
||||
rug::rugpoint *pt(hyperpoint h, hyperpoint c, int id) {
|
||||
auto r = rug::addRugpoint(C0, -1);
|
||||
r->flat = h;
|
||||
r->native = h;
|
||||
r->x1 = (1 + c[0]) / 16 + (id/8) / 8.;
|
||||
r->y1 = (1 + c[1]) / 16 + (id%8) / 8.;
|
||||
r->valid = true;
|
||||
@ -190,7 +190,7 @@ void run_snub(int v, int w) {
|
||||
create_model();
|
||||
printf("points = %d tris = %d side = %d\n", isize(rug::points), isize(rug::triangles), isize(sideangles));
|
||||
rug::model_distance = euclid ? 4 : 2;
|
||||
rug::rug_perspective = hyperbolic;
|
||||
vid.rug_config.model = hyperbolic ? mdPerspective : mdEquidistant;
|
||||
showstartmenu = false;
|
||||
snubon = true;
|
||||
rug::invert_depth = hyperbolic;
|
||||
|
@ -30,7 +30,7 @@ hyperpoint spcoord(hyperpoint h) {
|
||||
|
||||
rug::rugpoint *pt(hyperpoint h, hyperpoint c) {
|
||||
auto r = rug::addRugpoint(C0, -1);
|
||||
r->flat = spcoord(h);
|
||||
r->native = spcoord(h);
|
||||
r->x1 = c[0];
|
||||
r->y1 = c[1];
|
||||
r->valid = true;
|
||||
@ -120,17 +120,17 @@ void make_staircase() {
|
||||
|
||||
println(hlog, "scurvature = ", scurvature, " progress = ", progress, " strafe=", strafex, ",", strafey);
|
||||
rug::renderonce = true;
|
||||
rug::rug_perspective = true;
|
||||
vid.rug_config.model = mdPerspective;
|
||||
if(scurvature > -1e-6 && scurvature < 1e-6) {
|
||||
rug::gwhere = gEuclid;
|
||||
rug::gwhere = rug::rgEuclid;
|
||||
acurvature = 1;
|
||||
}
|
||||
else if(scurvature < 0) {
|
||||
rug::gwhere = gNormal;
|
||||
rug::gwhere = rug::rgHyperbolic;
|
||||
acurvature = -scurvature;
|
||||
}
|
||||
else {
|
||||
rug::gwhere = gSphere;
|
||||
rug::gwhere = rug::rgSphere;
|
||||
acurvature = scurvature;
|
||||
}
|
||||
rug::ruggospeed = acurvature;
|
||||
|
@ -87,13 +87,9 @@ bool sunflower_cell(cell *c, transmatrix V) {
|
||||
|
||||
if(adjust_rug) {
|
||||
using namespace rug;
|
||||
if(rug_perspective)
|
||||
push_all_points(2, +model_distance);
|
||||
|
||||
model_distance = sqrt(zdensity) * distance_per_rug;
|
||||
|
||||
if(rug_perspective)
|
||||
push_all_points(2, -model_distance);
|
||||
}
|
||||
|
||||
iqty = qty;
|
||||
|
@ -113,7 +113,7 @@ int readArgs() {
|
||||
|
||||
if(0) ;
|
||||
|
||||
else if(argis("-tol")) {
|
||||
else if(argis("-tree")) {
|
||||
PHASE(3); shift(); tree::read(args());
|
||||
}
|
||||
|
||||
|
@ -111,9 +111,9 @@ struct trianglemaker {
|
||||
|
||||
// println(hlog, "uds = ", uds);
|
||||
|
||||
for(int a=0; a<3; a++) println(hlog, sqhypot_d(3, inverse_exp(start + ds[a] * ca, iTable, false)));
|
||||
for(int a=0; a<3; a++) println(hlog, sqhypot_d(3, inverse_exp(start + ds[a] * ca)));
|
||||
|
||||
for(int a=0; a<3; a++) println(hlog, sqhypot_d(3, inverse_exp(uds[a], iTable, false)));
|
||||
for(int a=0; a<3; a++) println(hlog, sqhypot_d(3, inverse_exp(uds[a])));
|
||||
|
||||
// compute cube vertices
|
||||
|
||||
|
695
screenshot.cpp
695
screenshot.cpp
@ -86,10 +86,10 @@ EX always_false in;
|
||||
|
||||
EX void circle(int x, int y, int size, color_t col, color_t fillcol, double linewidth) {
|
||||
if(!invisible(col) || !invisible(fillcol)) {
|
||||
if(vid.stretch == 1)
|
||||
if(pconf.stretch == 1)
|
||||
println(f, "<circle cx='", coord(x), "' cy='", coord(y), "' r='", coord(size), "' ", stylestr(fillcol, col, linewidth), "/>");
|
||||
else
|
||||
println(f, "<ellipse cx='", coord(x), "' cy='", coord(y), "' rx='", coord(size), "' ry='", coord(size*vid.stretch), "' ", stylestr(fillcol, col), "/>");
|
||||
println(f, "<ellipse cx='", coord(x), "' cy='", coord(y), "' rx='", coord(size), "' ry='", coord(size*pconf.stretch), "' ", stylestr(fillcol, col), "/>");
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ int read_args() {
|
||||
else if(argis("-svgshot")) {
|
||||
PHASE(3); shift(); start_game();
|
||||
printf("saving SVG screenshot to %s\n", argcs());
|
||||
shot::make_svg = true;
|
||||
shot::format = shot::screenshot_format::svg;
|
||||
shot::take(argcs());
|
||||
}
|
||||
else if(argis("-svgtwm")) {
|
||||
@ -233,6 +233,374 @@ auto ah = addHook(hooks_args, 0, read_args);
|
||||
#endif
|
||||
EX }
|
||||
|
||||
/** wrl renderer */
|
||||
EX namespace wrl {
|
||||
#if !CAP_WRL
|
||||
EX always_false in;
|
||||
#endif
|
||||
|
||||
#if CAP_WRL
|
||||
EX bool in;
|
||||
|
||||
EX bool print;
|
||||
EX bool textures = true;
|
||||
|
||||
EX ld rug_width = .01;
|
||||
|
||||
fhstream f;
|
||||
string filename;
|
||||
|
||||
string coord(ld val) {
|
||||
char buf[100];
|
||||
snprintf(buf, 100, "%f", val);
|
||||
return buf;
|
||||
}
|
||||
|
||||
string coord(const hyperpoint& v, int q) {
|
||||
char buf[100];
|
||||
if(q == 3) snprintf(buf, 100, "%f, %f, %f", v[0], v[1], v[2]);
|
||||
if(q == 2) snprintf(buf, 100, "%f, %f", v[0], v[1]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
string color(color_t col, ld v) {
|
||||
char buf[100];
|
||||
ld cols[4];
|
||||
for(int i=0; i<4; i++) {
|
||||
|
||||
cols[i] = part(col, i);
|
||||
cols[i] /= 255;
|
||||
cols[i] = pow(cols[i], shot::gamma) * shot::fade * v;
|
||||
}
|
||||
|
||||
snprintf(buf, 100, "%.3f %.3f %.3f", cols[3], cols[2], cols[1]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
typedef unsigned long long hashtype;
|
||||
hashtype hash(ld x) { return hashtype(x * 1000000 + .5); }
|
||||
|
||||
hashtype hash(hyperpoint h) {
|
||||
return hash(h[0]) + 7 * hash(h[1]) + 13 * hash(h[2]);
|
||||
}
|
||||
|
||||
EX void fatten(vector<hyperpoint>& data, vector<glvertex>& tdata) {
|
||||
map<hashtype, hyperpoint> normals;
|
||||
for(int i=0; i<isize(data); i++)
|
||||
normals[hash(data[i])] = Hypc;
|
||||
for(int i=0; i<isize(data); i++) {
|
||||
int j = i%3 ? i-1 : i+2;
|
||||
int k = j%3 ? j-1 : j+2;
|
||||
hyperpoint normal = (data[j] - data[i]) ^ (data[k] - data[i]);
|
||||
normal[3] = 0;
|
||||
if(sqhypot_d(3, normal) < 1e-6) {
|
||||
println(hlog, "bug ", tie(data[i], data[j], data[k]));
|
||||
}
|
||||
normal /= hypot_d(3, normal);
|
||||
auto& res = normals[hash(data[i])];
|
||||
ld q = res[3];
|
||||
if((res | normal) < 0) res -= normal;
|
||||
else res += normal;
|
||||
res[3] = q + 1;
|
||||
}
|
||||
for(auto& p: normals) {
|
||||
auto w = hypot_d(3, p.second);
|
||||
if(w == 0) println(hlog, "width is 0, ", p.second, " appeared ", p.second[3], " times");
|
||||
if(isnan(w)) println(hlog, "width is NAN, ", p.second, " appeared ", p.second[3], " times");
|
||||
p.second = p.second * (rug_width / w);
|
||||
}
|
||||
vector<hyperpoint> data2;
|
||||
vector<glvertex> tdata2;
|
||||
for(int i=0; i<isize(data); i+=3) {
|
||||
auto a = data[i], b = data[i+1], c = data[i+2];
|
||||
hyperpoint normal = (b-a) ^ (c-a);
|
||||
auto na = normals[hash(a)];
|
||||
auto nb = normals[hash(b)];
|
||||
auto nc = normals[hash(c)];
|
||||
if((normal | na) > 0) na = -na;
|
||||
if((normal | nb) > 0) nb = -nb;
|
||||
if((normal | nc) > 0) nc = -nc;
|
||||
bool bad = false;
|
||||
for(int i=0; i<3; i++) {
|
||||
if(isnan(na[i]) || isnan(nb[i]) || isnan(nc[i])) bad = true;
|
||||
}
|
||||
if(bad) {
|
||||
println(hlog, "bad vertex");
|
||||
continue;
|
||||
}
|
||||
data2.push_back(a+na); data2.push_back(b+nb); data2.push_back(c+nc);
|
||||
data2.push_back(b+nb); data2.push_back(a+na); data2.push_back(a-na);
|
||||
data2.push_back(b+nb); data2.push_back(a-na); data2.push_back(b-nb);
|
||||
data2.push_back(c+nc); data2.push_back(b+nb); data2.push_back(b-nb);
|
||||
data2.push_back(c+nc); data2.push_back(b-nb); data2.push_back(c-nc);
|
||||
data2.push_back(a+na); data2.push_back(c+nc); data2.push_back(c-nc);
|
||||
data2.push_back(a+na); data2.push_back(c-nc); data2.push_back(a-na);
|
||||
data2.push_back(b-nb); data2.push_back(a-na); data2.push_back(c-nc);
|
||||
if(isize(tdata)) {
|
||||
auto ta = tdata[i], tb = tdata[i+1], tc = tdata[i+2];
|
||||
for(auto p: {ta, tb, tc, tb, ta, ta, tb, ta, tb, tc, tb, tb, tc, tb, tc, ta, tc, tc, ta, tc, ta, tb, ta, tc})
|
||||
tdata2.push_back(p);
|
||||
}
|
||||
}
|
||||
data = data2;
|
||||
tdata = tdata2;
|
||||
}
|
||||
|
||||
bool used_rug;
|
||||
|
||||
map<pair<color_t, glvertex>, int> texture_position;
|
||||
map<color_t, int> gradient_position;
|
||||
|
||||
pair<color_t, glvertex> texid(dqi_poly& p) {
|
||||
return make_pair(p.color, p.tinf->tvertices[0]);
|
||||
}
|
||||
|
||||
/** 0 = no/unknown/disabled texture, 1 = rug, 2 = gradient, 3 = floor texture */
|
||||
EX int texture_type(dqi_poly& p) {
|
||||
if(!p.tinf) return 0;
|
||||
if(!CAP_PNG) return 0;
|
||||
if(!textures) return 0;
|
||||
if(p.tinf == &rug::tinf) return 1;
|
||||
#if MAXMDIM >= 4
|
||||
if(p.tinf->texture_id == (int) floor_textures->renderedTexture)
|
||||
return (p.tinf->tvertices[0][0] == 0) ? 2 : 3;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
EX void prepare(dqi_poly& p) {
|
||||
if(print && !(p.flags & POLY_PRINTABLE)) return;
|
||||
if(!(p.flags & POLY_TRIANGLES)) return;
|
||||
int tt = texture_type(p);
|
||||
if(tt == 2) gradient_position[p.color] = 0;
|
||||
if(tt == 3) texture_position[texid(p)] = 0;
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
int fts_int, fts, fts_row;
|
||||
#endif
|
||||
|
||||
map<string, pair<vector<hyperpoint>, vector<glvertex>>> all_data;
|
||||
|
||||
EX void polygon(dqi_poly& p) {
|
||||
if(print && !(p.flags & POLY_PRINTABLE)) return;
|
||||
if(!(p.flags & POLY_TRIANGLES)) return;
|
||||
int tt = texture_type(p);
|
||||
|
||||
vector<hyperpoint> data;
|
||||
vector<glvertex> tdata;
|
||||
for(int i=0; i<p.cnt; i++) {
|
||||
glvertex v = p.tab[0][p.offset+i];
|
||||
data.push_back(glhr::gltopoint(v));
|
||||
if(p.tinf)
|
||||
tdata.push_back(p.tinf->tvertices[p.offset_texture+i]);
|
||||
}
|
||||
for(auto& d: data) {
|
||||
hyperpoint h;
|
||||
h = p.V * d;
|
||||
applymodel(h, d);
|
||||
}
|
||||
if(print && (p.flags & POLY_FAT)) {
|
||||
fatten(data, tdata);
|
||||
p.cnt = isize(data);
|
||||
}
|
||||
else if(print) {
|
||||
hyperpoint ctr1;
|
||||
applymodel(p.V * p.intester, ctr1);
|
||||
println(hlog, "intester = ", p.intester);
|
||||
ld sdet = 0;
|
||||
if(1) {
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
for(int i=0; i<p.cnt; i+=3) {
|
||||
transmatrix T;
|
||||
T[0] = data[i] - ctr1;
|
||||
T[1] = data[i+1] - ctr1;
|
||||
T[2] = data[i+2] - ctr1;
|
||||
sdet += det(T);
|
||||
}
|
||||
println(hlog, "sdet = ", sdet);
|
||||
if(sdet > 0)
|
||||
for(int i=0; i<p.cnt; i+=3) {
|
||||
swap(data[i+1], data[i+2]);
|
||||
if(!tdata.empty())
|
||||
swap(tdata[i+1], tdata[i+2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shstream app;
|
||||
println(app, " material Material {");
|
||||
if(!tt) println(app, " diffuseColor ", color(p.color, .8));
|
||||
if(part(p.color, 0) != 255) println(app, " transparency ", (255 - part(p.color, 0)) / 255.);
|
||||
println(app, " }");
|
||||
if(tt == 1) {
|
||||
println(f, " texture ImageTexture {");
|
||||
println(app, " url \"", filename, "-rug.png\"");
|
||||
println(app, " }");
|
||||
used_rug = true;
|
||||
}
|
||||
if(tt == 2 || tt == 3) {
|
||||
println(app, " texture ImageTexture {");
|
||||
println(app, " url \"", filename, "-floors.png\"");
|
||||
println(app, " }");
|
||||
}
|
||||
|
||||
auto &ad = all_data[app.s];
|
||||
for(auto& d: data) ad.first.push_back(d);
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(tt == 2) {
|
||||
ld x = (fts - .5 - gradient_position[p.color]) / fts;
|
||||
for(auto& d: tdata) d[0] = x;
|
||||
}
|
||||
|
||||
if(tt == 3) {
|
||||
int tp = texture_position[texid(p)];
|
||||
auto xy = make_array<int>(tp % fts_row, tp / fts_row);
|
||||
auto zero = p.tinf->tvertices[0];
|
||||
ld sca = FLOORTEXTURESIZE*1./fts_int;
|
||||
for(auto& d: tdata)
|
||||
for(int c: {0, 1})
|
||||
d[c] = ((d[c] - zero[c])*sca + xy[c] + .5) * fts_int / fts;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(auto& d: tdata) ad.second.push_back(d);
|
||||
}
|
||||
|
||||
EX void render() {
|
||||
#if MAXMDIM >= 4
|
||||
for(auto& p: ptds) {
|
||||
auto p2 = dynamic_cast<dqi_poly*>(&*p);
|
||||
if(p2)
|
||||
prepare(*p2);
|
||||
}
|
||||
|
||||
int tps = 0;
|
||||
for(auto& p: texture_position) p.second = tps++;
|
||||
int gps = 0;
|
||||
for(auto& p: gradient_position) p.second = gps++;
|
||||
|
||||
fts_int = floor_texture_square_size * FLOORTEXTURESIZE + 4;
|
||||
fts = 64;
|
||||
|
||||
while(fts < gps || (fts-gps)/fts_int * fts/fts_int < tps)
|
||||
fts *= 2;
|
||||
|
||||
fts_row = (fts-gps)/fts_int;
|
||||
#endif
|
||||
|
||||
for(auto& p: ptds) {
|
||||
auto p2 = dynamic_cast<dqi_poly*>(&*p);
|
||||
if(p2)
|
||||
polygon(*p2);
|
||||
}
|
||||
}
|
||||
|
||||
EX void take(const string& fname, const function<void()>& what IS(shot::default_screenshot_content)) {
|
||||
dynamicval<bool> v2(in, true);
|
||||
dynamicval<bool> v3(noshadow, true);
|
||||
filename = fname;
|
||||
|
||||
ptds.clear();
|
||||
all_data.clear();
|
||||
what();
|
||||
|
||||
f.f = fopen(fname.c_str(), "wt");
|
||||
|
||||
println(f, "#VRML V2.0 utf8");
|
||||
println(f, "WorldInfo { title \"3D model exported from HyperRogue\" info [ \"3D models exported from HyperRogue are public domain\" ] }");
|
||||
|
||||
for(auto& p: all_data) {
|
||||
const string& app = p.first;
|
||||
auto& data = p.second.first;
|
||||
auto& tdata = p.second.second;
|
||||
|
||||
println(f, "Shape {");
|
||||
println(f, " appearance Appearance {");
|
||||
println(f, app);
|
||||
println(f, " }");
|
||||
// println(f, "# V = ", p.V);
|
||||
println(f, " geometry IndexedFaceSet {");
|
||||
println(f, " coord Coordinate {");
|
||||
|
||||
println(f, " point [");
|
||||
for(auto& d: data) println(f, " ", coord(d, 3), ",");
|
||||
println(f, " ]");
|
||||
println(f, " }");
|
||||
|
||||
if(!tdata.empty()) {
|
||||
println(f, " texCoord TextureCoordinate {");
|
||||
println(f, " point [");
|
||||
|
||||
for(auto& d: tdata)
|
||||
println(f, " ", coord(glhr::gltopoint(d), 2), ",");
|
||||
println(f, " ]");
|
||||
println(f, " }");
|
||||
}
|
||||
|
||||
println(f, " coordIndex [");
|
||||
for(int i=0; i<isize(data); i+=3) {
|
||||
println(f, " ", i, " ", i+1, " ", i+2, " -1,");
|
||||
}
|
||||
println(f, " ]");
|
||||
if(print)
|
||||
println(f, " creaseAngle 0.0 convex FALSE solid TRUE ccw FALSE");
|
||||
else
|
||||
println(f, " creaseAngle 0.0 convex FALSE solid FALSE");
|
||||
println(f, " }");
|
||||
println(f, " }");
|
||||
}
|
||||
|
||||
#if CAP_PNG
|
||||
if(used_rug) {
|
||||
resetbuffer rb;
|
||||
rug::glbuf->enable();
|
||||
SDL_Surface *s = rug::glbuf->render();
|
||||
dynamicval<int> dx(shot::shotx, rug::texturesize);
|
||||
dynamicval<int> dy(shot::shoty, rug::texturesize);
|
||||
shot::postprocess(filename + "-rug.png", s, s);
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(isize(texture_position) || isize(gradient_position)) {
|
||||
SDL_Surface *s = shot::empty_surface(fts, fts, false);
|
||||
for(auto& p: gradient_position) {
|
||||
int x = fts - p.second - 1;
|
||||
for(int y=0; y<fts; y++) {
|
||||
qpixel(s, x, fts-y-1) = gradient(0, p.first, 0, y, fts-1) >> 8;
|
||||
part(qpixel(s, x, y), 3) = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface *floor = floor_textures->render();
|
||||
for(auto& p: texture_position) {
|
||||
int nx = p.second % fts_row;
|
||||
int ny = p.second / fts_row;
|
||||
color_t col = p.first.first;
|
||||
int xs = p.first.second[0] * FLOORTEXTURESIZE - fts_int/2;
|
||||
int ys = p.first.second[1] * FLOORTEXTURESIZE - fts_int/2;
|
||||
swap(xs, ys); // I do not understand why
|
||||
for(int y=0; y<fts_int; y++)
|
||||
for(int x=0; x<fts_int; x++) {
|
||||
auto& tgt = qpixel(s, nx*fts_int+x, fts-1-(ny*fts_int+y));
|
||||
auto& src = qpixel(floor, xs+x, FLOORTEXTURESIZE-1-(ys+y));
|
||||
for(int p=0; p<3; p++)
|
||||
part(tgt, p) = (part(src, p) * part(col, p+1) + 127) / 255;
|
||||
part(tgt, 3) = 0xFF;
|
||||
}
|
||||
}
|
||||
IMAGESAVE(s, (filename + "-floors.png").c_str());
|
||||
SDL_FreeSurface(s);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
fclose(f.f);
|
||||
f.f = nullptr;
|
||||
}
|
||||
#endif
|
||||
EX }
|
||||
|
||||
#if CAP_PNG
|
||||
void IMAGESAVE(SDL_Surface *s, const char *fname) {
|
||||
@ -247,9 +615,13 @@ EX namespace shot {
|
||||
|
||||
purehookset hooks_hqshot;
|
||||
|
||||
#if HDR
|
||||
enum screenshot_format { png, svg, wrl };
|
||||
#endif
|
||||
|
||||
EX int shotx = 2000;
|
||||
EX int shoty = 2000;
|
||||
EX bool make_svg = false;
|
||||
EX screenshot_format format;
|
||||
EX bool transparent = true;
|
||||
EX ld gamma = 1;
|
||||
EX int shotformat = -1;
|
||||
@ -287,14 +659,18 @@ EX void default_screenshot_content() {
|
||||
drawStats();
|
||||
}
|
||||
|
||||
EX SDL_Surface *empty_surface(int x, int y, bool alpha) {
|
||||
return SDL_CreateRGBSurface(SDL_SWSURFACE,x,y,32,0xFF<<16,0xFF<<8,0xFF, (alpha) ? (0xFF<<24) : 0);
|
||||
}
|
||||
|
||||
#if CAP_PNG
|
||||
void postprocess(string fname, SDL_Surface *sdark, SDL_Surface *sbright) {
|
||||
EX void postprocess(string fname, SDL_Surface *sdark, SDL_Surface *sbright) {
|
||||
if(gamma == 1 && shot_aa == 1 && sdark == sbright) {
|
||||
IMAGESAVE(sdark, fname.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Surface *sout = SDL_CreateRGBSurface(SDL_SWSURFACE,shotx,shoty,32,0xFF<<16,0xFF<<8,0xFF, (sdark == sbright) ? 0 : (0xFF<<24));
|
||||
SDL_Surface *sout = empty_surface(shotx, shoty, sdark != sbright);
|
||||
for(int y=0; y<shoty; y++)
|
||||
for(int x=0; x<shotx; x++) {
|
||||
int val[2][4];
|
||||
@ -327,12 +703,46 @@ void postprocess(string fname, SDL_Surface *sdark, SDL_Surface *sbright) {
|
||||
|
||||
EX purehookset hooks_take;
|
||||
|
||||
#if CAP_PNG
|
||||
void render_png(string fname, const function<void()>& what) {
|
||||
resetbuffer rb;
|
||||
|
||||
renderbuffer glbuf(vid.xres, vid.yres, vid.usingGL);
|
||||
glbuf.enable();
|
||||
current_display->set_viewport(0);
|
||||
|
||||
dynamicval<color_t> v8(backcolor, transparent ? 0xFF000000 : backcolor);
|
||||
#if CAP_RUG
|
||||
if(rug::rugged && !rug::renderonce) rug::prepareTexture();
|
||||
#endif
|
||||
glbuf.clear(backcolor);
|
||||
what();
|
||||
|
||||
SDL_Surface *sdark = glbuf.render();
|
||||
|
||||
if(transparent) {
|
||||
renderbuffer glbuf1(vid.xres, vid.yres, vid.usingGL);
|
||||
backcolor = 0xFFFFFFFF;
|
||||
#if CAP_RUG
|
||||
if(rug::rugged && !rug::renderonce) rug::prepareTexture();
|
||||
#endif
|
||||
glbuf1.enable();
|
||||
glbuf1.clear(backcolor);
|
||||
current_display->set_viewport(0);
|
||||
what();
|
||||
|
||||
postprocess(fname, sdark, glbuf1.render());
|
||||
}
|
||||
else postprocess(fname, sdark, sdark);
|
||||
}
|
||||
#endif
|
||||
|
||||
EX void take(string fname, const function<void()>& what IS(default_screenshot_content)) {
|
||||
|
||||
if(cheater) doOvergenerate();
|
||||
|
||||
|
||||
#if CAP_SVG
|
||||
int multiplier = make_svg ? svg::divby : shot_aa;
|
||||
int multiplier = (format == screenshot_format::svg) ? svg::divby : shot_aa;
|
||||
#else
|
||||
int multiplier = shot_aa;
|
||||
#endif
|
||||
@ -352,45 +762,25 @@ EX void take(string fname, const function<void()>& what IS(default_screenshot_co
|
||||
models::configure();
|
||||
callhooks(hooks_take);
|
||||
|
||||
if(make_svg) {
|
||||
#if CAP_SVG
|
||||
svg::render(fname, what);
|
||||
#endif
|
||||
}
|
||||
|
||||
else {
|
||||
#if CAP_PNG
|
||||
resetbuffer rb;
|
||||
|
||||
renderbuffer glbuf(vid.xres, vid.yres, vid.usingGL);
|
||||
glbuf.enable();
|
||||
current_display->set_viewport(0);
|
||||
|
||||
dynamicval<color_t> v8(backcolor, transparent ? 0xFF000000 : backcolor);
|
||||
#if CAP_RUG
|
||||
if(rug::rugged && !rug::renderonce) rug::prepareTexture();
|
||||
#endif
|
||||
glbuf.clear(backcolor);
|
||||
what();
|
||||
|
||||
SDL_Surface *sdark = glbuf.render();
|
||||
|
||||
if(transparent) {
|
||||
renderbuffer glbuf1(vid.xres, vid.yres, vid.usingGL);
|
||||
backcolor = 0xFFFFFFFF;
|
||||
#if CAP_RUG
|
||||
if(rug::rugged && !rug::renderonce) rug::prepareTexture();
|
||||
switch(format) {
|
||||
case screenshot_format::wrl:
|
||||
#if CAP_WRL
|
||||
wrl::take(fname);
|
||||
#endif
|
||||
glbuf1.enable();
|
||||
glbuf1.clear(backcolor);
|
||||
current_display->set_viewport(0);
|
||||
what();
|
||||
|
||||
postprocess(fname, sdark, glbuf1.render());
|
||||
}
|
||||
else postprocess(fname, sdark, sdark);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
|
||||
case screenshot_format::svg:
|
||||
#if CAP_SVG
|
||||
svg::render(fname, what);
|
||||
#endif
|
||||
return;
|
||||
|
||||
case screenshot_format::png:
|
||||
#if CAP_PNG
|
||||
render_png(fname, what);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
@ -399,7 +789,7 @@ int png_read_args() {
|
||||
if(argis("-pngshot")) {
|
||||
PHASE(3); shift(); start_game();
|
||||
printf("saving PNG screenshot to %s\n", argcs());
|
||||
make_svg = false;
|
||||
format = screenshot_format::png;
|
||||
shot::take(argcs());
|
||||
}
|
||||
else if(argis("-pngsize")) {
|
||||
@ -417,6 +807,20 @@ int png_read_args() {
|
||||
else if(argis("-shotaa")) {
|
||||
shift(); shot_aa = argi();
|
||||
}
|
||||
#if CAP_WRL
|
||||
else if(argis("-modelshot")) {
|
||||
PHASE(3); shift(); start_game();
|
||||
printf("saving WRL model to %s\n", argcs());
|
||||
shot::format = screenshot_format::wrl; wrl::print = false;
|
||||
shot::take(argcs());
|
||||
}
|
||||
else if(argis("-printshot")) {
|
||||
PHASE(3); shift(); start_game();
|
||||
printf("saving 3D printable model to %s\n", argcs());
|
||||
shot::format = screenshot_format::wrl; wrl::print = true;
|
||||
shot::take(argcs());
|
||||
}
|
||||
#endif
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -424,30 +828,118 @@ int png_read_args() {
|
||||
auto ah_png = addHook(hooks_args, 0, png_read_args);
|
||||
#endif
|
||||
|
||||
EX string format_name() {
|
||||
if(format == screenshot_format::svg) return "SVG";
|
||||
if(format == screenshot_format::wrl) return "WRL";
|
||||
if(format == screenshot_format::png) return "PNG";
|
||||
return "?";
|
||||
}
|
||||
|
||||
EX string format_extension() {
|
||||
if(format == screenshot_format::svg) return ".svg";
|
||||
if(format == screenshot_format::wrl) return ".wrl";
|
||||
if(format == screenshot_format::png) return ".png";
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
EX void choose_screenshot_format() {
|
||||
cmode = sm::SIDE;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("screenshots"), iinf[itPalace].color, 150, 100);
|
||||
#if CAP_PNG
|
||||
dialog::addItem(XLAT("PNG"), 'p');
|
||||
dialog::add_action([] { format = screenshot_format::png; popScreen(); });
|
||||
#endif
|
||||
#if CAP_SVG
|
||||
dialog::addItem(XLAT("SVG"), 's');
|
||||
dialog::add_action([] { format = screenshot_format::svg; popScreen(); });
|
||||
#endif
|
||||
#if CAP_WRL
|
||||
dialog::addItem(XLAT("WRL"), 'w');
|
||||
dialog::add_action([] { format = screenshot_format::wrl; popScreen(); });
|
||||
#endif
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
EX void menu() {
|
||||
cmode = sm::SIDE;
|
||||
gamescreen(0);
|
||||
if(!CAP_SVG) make_svg = false;
|
||||
if(!CAP_PNG) make_svg = true;
|
||||
if(format == screenshot_format::svg && !CAP_SVG)
|
||||
format = screenshot_format::png;
|
||||
if(format == screenshot_format::png && !CAP_PNG)
|
||||
format = screenshot_format::svg;
|
||||
dialog::init(XLAT("screenshots"), iinf[itPalace].color, 150, 100);
|
||||
dialog::addSelItem(XLAT("format"), make_svg ? "SVG" : "PNG", 'f');
|
||||
dialog::add_action([] { make_svg = !make_svg; });
|
||||
dialog::addSelItem(XLAT("pixels (X)"), its(shotx), 'x');
|
||||
dialog::add_action([] { shotformat = -1; dialog::editNumber(shotx, 500, 8000, 100, 2000, XLAT("pixels (X)"), ""); });
|
||||
dialog::addSelItem(XLAT("pixels (Y)"), its(shoty), 'y');
|
||||
dialog::add_action([] { shotformat = -1; dialog::editNumber(shoty, 500, 8000, 100, 2000, XLAT("pixels (Y)"), ""); });
|
||||
if(make_svg) {
|
||||
#if CAP_SVG
|
||||
using namespace svg;
|
||||
dialog::addSelItem(XLAT("precision"), "1/"+its(divby), 'p');
|
||||
dialog::add_action([] { divby *= 10; if(divby > 1000000) divby = 1; });
|
||||
#endif
|
||||
dialog::addSelItem(XLAT("format"), format_name(), 'f');
|
||||
dialog::add_action_push(choose_screenshot_format);
|
||||
bool dowrl = format == screenshot_format::wrl;
|
||||
if(!dowrl) {
|
||||
dialog::addSelItem(XLAT("pixels (X)"), its(shotx), 'x');
|
||||
dialog::add_action([] { shotformat = -1; dialog::editNumber(shotx, 500, 8000, 100, 2000, XLAT("pixels (X)"), ""); });
|
||||
dialog::addSelItem(XLAT("pixels (Y)"), its(shoty), 'y');
|
||||
dialog::add_action([] { shotformat = -1; dialog::editNumber(shoty, 500, 8000, 100, 2000, XLAT("pixels (Y)"), ""); });
|
||||
}
|
||||
else {
|
||||
dialog::addSelItem(XLAT("supersampling"), its(shot_aa), 's');
|
||||
dialog::add_action([] { shot_aa *= 2; if(shot_aa > 16) shot_aa = 1; });
|
||||
|
||||
switch(format) {
|
||||
case screenshot_format::svg: {
|
||||
#if CAP_SVG
|
||||
using namespace svg;
|
||||
dialog::addSelItem(XLAT("precision"), "1/"+its(divby), 'p');
|
||||
dialog::add_action([] { divby *= 10; if(divby > 1000000) divby = 1; });
|
||||
#endif
|
||||
|
||||
if(models::is_3d(vpconf) || rug::rugged) {
|
||||
dialog::addInfo("SVG screenshots do not work in this 3D mode", 0xFF0000);
|
||||
if(GDIM == 2 && !rug::rugged) {
|
||||
dialog::addSelItem(XLAT("projection"), current_proj_name(), '1');
|
||||
dialog::add_action_push(models::model_menu);
|
||||
}
|
||||
#if CAP_WRL
|
||||
else {
|
||||
dialog::addItem(XLAT("WRL"), 'w');
|
||||
dialog::add_action([] { format = screenshot_format::wrl; });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CAP_TEXTURE
|
||||
if(texture::config.tstate == texture::tsActive)
|
||||
dialog::addInfo("SVG screenshots do not work with textures", 0xFF0000);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case screenshot_format::png: {
|
||||
#if CAP_PNG
|
||||
dialog::addSelItem(XLAT("supersampling"), its(shot_aa), 's');
|
||||
dialog::add_action([] { shot_aa *= 2; if(shot_aa > 16) shot_aa = 1; });
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case screenshot_format::wrl: {
|
||||
#if CAP_WRL
|
||||
if(!models::is_3d(vpconf) && !rug::rugged) {
|
||||
dialog::addInfo("this format is for 3D projections", 0xFF0000);
|
||||
if(GDIM == 2) {
|
||||
dialog::addItem(XLAT("hypersian rug mode"), 'u');
|
||||
dialog::add_action_push(rug::show);
|
||||
}
|
||||
}
|
||||
else if(rug::rugged ? rug::perspective() : models::is_perspective(vpconf.model)) {
|
||||
dialog::addInfo("this does not work well in perspective projections", 0xFF8000);
|
||||
dialog::addSelItem(XLAT("projection"), current_proj_name(), '1');
|
||||
dialog::add_action_push(models::model_menu);
|
||||
}
|
||||
dialog::addBoolItem_action("generate a model for 3D printing", wrl::print, 'p');
|
||||
#if CAP_PNG
|
||||
dialog::addBoolItem_action("use textures", wrl::textures, 'u');
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
dialog::addBoolItem_action(XLAT("transparent"), transparent, 't');
|
||||
if(!dowrl) dialog::addBoolItem_action(XLAT("transparent"), transparent, 't');
|
||||
|
||||
dialog::addSelItem(XLAT("gamma"), fts(gamma), 'g');
|
||||
dialog::add_action([] { dialog::editNumber(gamma, 0, 2, .1, .5, XLAT("gamma"), "higher value = darker"); });
|
||||
@ -455,10 +947,13 @@ EX void menu() {
|
||||
dialog::addSelItem(XLAT("brightness"), fts(fade), 'b');
|
||||
dialog::add_action([] { dialog::editNumber(fade, 0, 2, .1, 1, XLAT("brightness"), "higher value = lighter"); });
|
||||
|
||||
dialog::addBoolItem_action(XLAT("disable the HUD"), hide_hud, 'h');
|
||||
|
||||
dialog::addBoolItem_action_neg(XLAT("hide the player"), mapeditor::drawplayer, 'H');
|
||||
if(!dowrl) dialog::addBoolItem_action(XLAT("disable the HUD"), hide_hud, 'h');
|
||||
|
||||
dialog::addBoolItem_action_neg(XLAT("hide the player"), mapeditor::drawplayer, 'H');
|
||||
#if CAP_WRL
|
||||
if(dowrl && wrl::print) dialog::lastItem().value = XLAT("N/A");
|
||||
#endif
|
||||
|
||||
if(WDIM == 2) {
|
||||
dialog::addItem(XLAT("centering"), 'x');
|
||||
dialog::add_action([] {
|
||||
@ -483,18 +978,6 @@ EX void menu() {
|
||||
|
||||
dialog::addBreak(100);
|
||||
|
||||
#if CAP_RUG
|
||||
if(make_svg && rug::rugged)
|
||||
dialog::addInfo("SVG screenshots do not work in this 3D mode", 0xFF0000);
|
||||
else
|
||||
#endif
|
||||
#if CAP_TEXTURE
|
||||
if(make_svg && texture::config.tstate == texture::tsActive)
|
||||
dialog::addInfo("SVG screenshots do not work with textures", 0xFF0000);
|
||||
else
|
||||
#endif
|
||||
dialog::addBreak(100);
|
||||
|
||||
dialog::addItem(XLAT("take screenshot"), 'z');
|
||||
dialog::add_action([] () {
|
||||
#if ISWEB
|
||||
@ -502,8 +985,13 @@ EX void menu() {
|
||||
#else
|
||||
static string pngfile = "hqshot.png";
|
||||
static string svgfile = "svgshot.svg";
|
||||
string& file = make_svg ? svgfile : pngfile;
|
||||
dialog::openFileDialog(file, XLAT("screenshot"), make_svg ? ".svg" : ".png", [&file] () {
|
||||
static string wrlfile = "model.wrl";
|
||||
string& file =
|
||||
format == screenshot_format::png ? pngfile :
|
||||
format == screenshot_format::svg ? svgfile :
|
||||
wrlfile;
|
||||
|
||||
dialog::openFileDialog(file, XLAT("screenshot"), format_extension(), [&file] () {
|
||||
dynamicval<int> cgl(vid.cells_generated_limit, 9999999);
|
||||
shot::take(file);
|
||||
return true;
|
||||
@ -727,32 +1215,30 @@ EX void apply() {
|
||||
#if CAP_RUG
|
||||
if(rug::rugged) {
|
||||
if(rug_rotation1) {
|
||||
rug::apply_rotation(cspin(1, 2, rug_angle * degree));
|
||||
rug::apply_rotation(cspin(0, 2, rug_rotation1 * 2 * M_PI * t / period));
|
||||
rug::apply_rotation(cspin(1, 2, -rug_angle * degree));
|
||||
rug::rugView = cspin(1, 2, -rug_angle * degree) * cspin(0, 2, rug_rotation1 * 2 * M_PI * t / period) * cspin(1, 2, rug_angle * degree) * rug::rugView;
|
||||
}
|
||||
if(rug_rotation2) {
|
||||
rug::apply_rotation(rug::currentrot * cspin(0, 1, rug_rotation2 * 2 * M_PI * t / period) * inverse(rug::currentrot));
|
||||
rug::rugView = rug::rugView * cspin(0, 1, rug_rotation2 * 2 * M_PI * t / period);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
vid.skiprope += skiprope_rotation * t * 2 * M_PI / period;
|
||||
pconf.skiprope += skiprope_rotation * t * 2 * M_PI / period;
|
||||
|
||||
if(ballangle_rotation) {
|
||||
if(models::model_has_orientation())
|
||||
models::model_orientation += ballangle_rotation * 360 * t / period;
|
||||
if(models::has_orientation(vpconf.model))
|
||||
vpconf.model_orientation += ballangle_rotation * 360 * t / period;
|
||||
else
|
||||
vid.ballangle += ballangle_rotation * 360 * t / period;
|
||||
vpconf.ballangle += ballangle_rotation * 360 * t / period;
|
||||
}
|
||||
if(joukowsky_anim) {
|
||||
ld t = ticks / period;
|
||||
t = t - floor(t);
|
||||
if(pmodel == mdBand) {
|
||||
models::model_transition = t * 4 - 1;
|
||||
vpconf.model_transition = t * 4 - 1;
|
||||
}
|
||||
else {
|
||||
models::model_transition = t / 1.1;
|
||||
vid.scale = (1 - models::model_transition) / 2.;
|
||||
vpconf.model_transition = t / 1.1;
|
||||
vpconf.scale = (1 - vpconf.model_transition) / 2.;
|
||||
}
|
||||
}
|
||||
apply_animated_parameters();
|
||||
@ -779,6 +1265,7 @@ bool record_animation() {
|
||||
int newticks = i * period / noframes;
|
||||
cmode = (env_shmup ? sm::NORMAL : 0);
|
||||
while(ticks < newticks) shmup::turn(1), ticks++;
|
||||
ca::simulate();
|
||||
if(playermoved) centerpc(INF), optimizeview();
|
||||
dynamicval<bool> v2(inHighQual, true);
|
||||
apply();
|
||||
@ -1010,7 +1497,7 @@ EX void show() {
|
||||
});
|
||||
}
|
||||
#endif
|
||||
if(models::model_has_orientation())
|
||||
if(models::has_orientation(vpconf.model))
|
||||
animator(XLAT("model rotation"), ballangle_rotation, 'I');
|
||||
else if(among(pmodel, mdHyperboloid, mdHemisphere, mdBall))
|
||||
animator(XLAT("3D rotation"), ballangle_rotation, '3');
|
||||
@ -1042,7 +1529,8 @@ EX void show() {
|
||||
dialog::add_action([] () { dialog::editNumber(noframes, 0, 300, 30, 5, XLAT("frames to record"), ""); });
|
||||
dialog::addSelItem(XLAT("record to a file"), animfile, 'R');
|
||||
dialog::add_action([] () {
|
||||
dialog::openFileDialog(animfile, XLAT("record to a file"), shot::make_svg ? ".svg" : ".png", record_animation);
|
||||
dialog::openFileDialog(animfile, XLAT("record to a file"),
|
||||
shot::format_extension(), record_animation);
|
||||
});
|
||||
#endif
|
||||
dialog::addBack();
|
||||
@ -1188,9 +1676,9 @@ startanim null_animation { "", no_init, [] { gamescreen(2); }};
|
||||
|
||||
startanim joukowsky { "Joukowsky transform", no_init, [] {
|
||||
dynamicval<eModel> dm(pmodel, mdJoukowskyInverted);
|
||||
dynamicval<ld> dt(models::model_orientation, ticks / 25.);
|
||||
dynamicval<ld> dt(pconf.model_orientation, ticks / 25.);
|
||||
dynamicval<int> dv(vid.use_smart_range, 2);
|
||||
dynamicval<ld> ds(vid.scale, 1/4.);
|
||||
dynamicval<ld> ds(pconf.scale, 1/4.);
|
||||
models::configure();
|
||||
dynamicval<color_t> dc(ringcolor, 0);
|
||||
gamescreen(2);
|
||||
@ -1199,7 +1687,7 @@ startanim joukowsky { "Joukowsky transform", no_init, [] {
|
||||
|
||||
startanim bandspin { "spinning in the band model", no_init, [] {
|
||||
dynamicval<eModel> dm(pmodel, mdBand);
|
||||
dynamicval<ld> dt(models::model_orientation, ticks / 25.);
|
||||
dynamicval<ld> dt(pconf.model_orientation, ticks / 25.);
|
||||
dynamicval<int> dv(vid.use_smart_range, 2);
|
||||
models::configure();
|
||||
gamescreen(2);
|
||||
@ -1212,8 +1700,8 @@ startanim perspective { "projection distance", no_init, [] {
|
||||
x /= 2;
|
||||
x *= 1.5;
|
||||
x = tan(x);
|
||||
dynamicval<ld> da(vid.alpha, x);
|
||||
dynamicval<ld> ds(vid.scale, (1+x)/2);
|
||||
dynamicval<ld> da(pconf.alpha, x);
|
||||
dynamicval<ld> ds(pconf.scale, (1+x)/2);
|
||||
calcparam();
|
||||
gamescreen(2);
|
||||
explorable(projectionDialog);
|
||||
@ -1224,16 +1712,15 @@ startanim rug { "Hypersian Rug", [] {
|
||||
rug::init(), rug::rugged = false; }, [] {
|
||||
dynamicval<bool> b(rug::rugged, true);
|
||||
rug::physics();
|
||||
rug::apply_rotation(cspin(1, 2, ticks / 3000.));
|
||||
dynamicval<transmatrix> t(rug::rugView, cspin(1, 2, ticks / 3000.) * rug::rugView);
|
||||
gamescreen(2);
|
||||
rug::apply_rotation(cspin(1, 2, -ticks / 3000.));
|
||||
if(!rug::rugged) current = &null_animation;
|
||||
explorable([] { rug::rugged = true; pushScreen(rug::show); });
|
||||
}};
|
||||
|
||||
startanim spin_around { "spinning around", no_init, [] {
|
||||
dynamicval<ld> da(vid.alpha, 999);
|
||||
dynamicval<ld> ds(vid.scale, 500);
|
||||
dynamicval<ld> da(pconf.alpha, 999);
|
||||
dynamicval<ld> ds(pconf.scale, 500);
|
||||
ld alpha = 2 * M_PI * ticks / 10000.;
|
||||
ld circle_radius = acosh(2.);
|
||||
dynamicval<transmatrix> dv(View, spin(-cos_auto(circle_radius)*alpha) * xpush(circle_radius) * spin(alpha) * View);
|
||||
|
35
shaders.cpp
35
shaders.cpp
@ -16,8 +16,9 @@ constexpr flagtype GF_TEXTURE = 1;
|
||||
constexpr flagtype GF_VARCOLOR = 2;
|
||||
constexpr flagtype GF_LIGHTFOG = 4;
|
||||
constexpr flagtype GF_LEVELS = 8;
|
||||
constexpr flagtype GF_TEXTURE_SHADED = 16;
|
||||
|
||||
constexpr flagtype GF_which = 15;
|
||||
constexpr flagtype GF_which = 31;
|
||||
|
||||
constexpr flagtype SF_PERS3 = 256;
|
||||
constexpr flagtype SF_BAND = 512;
|
||||
@ -62,7 +63,15 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
|
||||
varying += "varying mediump vec4 vColor;\n";
|
||||
|
||||
fmain += "gl_FragColor = vColor;\n";
|
||||
if(shader_flags & GF_TEXTURE) {
|
||||
if(shader_flags & GF_TEXTURE_SHADED) {
|
||||
vsh += "attribute mediump vec3 aTexture;\n";
|
||||
varying += "varying mediump vec3 vTexCoord;\n";
|
||||
fsh += "uniform mediump sampler2D tTexture;\n";
|
||||
vmain += "vTexCoord = aTexture;\n";
|
||||
fmain += "gl_FragColor *= texture2D(tTexture, vTexCoord.xy);\n";
|
||||
fmain += "gl_FragColor.rgb *= vTexCoord.z;\n";
|
||||
}
|
||||
else if(shader_flags & GF_TEXTURE) {
|
||||
vsh += "attribute mediump vec2 aTexture;\n";
|
||||
varying += "varying mediump vec2 vTexCoord;\n";
|
||||
fsh += "uniform mediump sampler2D tTexture;\n";
|
||||
@ -359,7 +368,7 @@ void display_data::set_projection(int ed) {
|
||||
|
||||
if(pmodel == mdManual) return;
|
||||
|
||||
if(vid.stretch != 1 && (shader_flags & SF_DIRECT)) glhr::projection_multiply(glhr::scale(vid.stretch, 1, 1));
|
||||
if(pconf.stretch != 1 && (shader_flags & SF_DIRECT) && pmodel != mdPixel) glhr::projection_multiply(glhr::scale(1, pconf.stretch, 1));
|
||||
|
||||
if(vid.stereo_mode != sODS)
|
||||
eyewidth_translate(ed);
|
||||
@ -367,10 +376,8 @@ void display_data::set_projection(int ed) {
|
||||
auto ortho = [&] (ld x, ld y) {
|
||||
glhr::glmatrix M = glhr::ortho(x, y, 1);
|
||||
if(shader_flags & SF_ZFOG) {
|
||||
using models::clip_max;
|
||||
using models::clip_min;
|
||||
M[2][2] = 2 / (clip_max - clip_min);
|
||||
M[3][2] = (clip_min + clip_max) / (clip_max - clip_min);
|
||||
M[2][2] = 2 / (pconf.clip_max - pconf.clip_min);
|
||||
M[3][2] = (pconf.clip_min + pconf.clip_max) / (pconf.clip_max - pconf.clip_min);
|
||||
auto cols = glhr::acolor(darkena(backcolor, 0, 0xFF));
|
||||
glUniform4f(selected->uFogColor, cols[0], cols[1], cols[2], cols[3]);
|
||||
}
|
||||
@ -409,7 +416,7 @@ void display_data::set_projection(int ed) {
|
||||
glhr::fog_max(1/sightranges[geometry], darkena(backcolor, 0, 0xFF));
|
||||
}
|
||||
else {
|
||||
if(vid.alpha > -1) {
|
||||
if(pconf.alpha > -1) {
|
||||
// Because of the transformation from H3 to the Minkowski hyperboloid,
|
||||
// points with negative Z can be generated in some 3D settings.
|
||||
// This happens for points below the camera, but above the plane.
|
||||
@ -420,14 +427,14 @@ void display_data::set_projection(int ed) {
|
||||
GLfloat sc = current_display->radius / (cd->ysize/2.);
|
||||
glhr::projection_multiply(glhr::frustum(cd->xsize / cd->ysize, 1));
|
||||
glhr::projection_multiply(glhr::scale(sc, -sc, -1));
|
||||
glhr::projection_multiply(glhr::translate(0, 0, vid.alpha));
|
||||
glhr::projection_multiply(glhr::translate(0, 0, pconf.alpha));
|
||||
if(ed) glhr::projection_multiply(glhr::translate(vid.ipd * ed/2, 0, 0));
|
||||
}
|
||||
|
||||
if(selected->uPP != -1) {
|
||||
glhr::glmatrix pp = glhr::id;
|
||||
if(get_shader_flags() & SF_USE_ALPHA)
|
||||
pp[3][2] = GLfloat(vid.alpha);
|
||||
pp[3][2] = GLfloat(pconf.alpha);
|
||||
|
||||
if(get_shader_flags() & SF_ORIENT) {
|
||||
if(GDIM == 3) for(int a=0; a<4; a++)
|
||||
@ -440,7 +447,7 @@ void display_data::set_projection(int ed) {
|
||||
}
|
||||
|
||||
if(selected->uAlpha != -1)
|
||||
glhr::set_ualpha(vid.alpha);
|
||||
glhr::set_ualpha(pconf.alpha);
|
||||
|
||||
if(selected->uLevelLines != -1) {
|
||||
glUniform1f(selected->uLevelLines, levellines);
|
||||
@ -458,12 +465,12 @@ void display_data::set_projection(int ed) {
|
||||
if(selected->shader_flags & SF_HALFPLANE) {
|
||||
glhr::projection_multiply(glhr::translate(0, 1, 0));
|
||||
glhr::projection_multiply(glhr::scale(-1, 1, 1));
|
||||
glhr::projection_multiply(glhr::scale(models::halfplane_scale, models::halfplane_scale, GDIM == 3 ? models::halfplane_scale : 1));
|
||||
glhr::projection_multiply(glhr::scale(pconf.halfplane_scale, pconf.halfplane_scale, GDIM == 3 ? pconf.halfplane_scale : 1));
|
||||
glhr::projection_multiply(glhr::translate(0, 0.5, 0));
|
||||
}
|
||||
|
||||
if(vid.camera_angle && pmodel != mdPixel) {
|
||||
ld cam = vid.camera_angle * degree;
|
||||
if(pconf.camera_angle && pmodel != mdPixel) {
|
||||
ld cam = pconf.camera_angle * degree;
|
||||
|
||||
GLfloat cc = cos(cam);
|
||||
GLfloat ss = sin(cam);
|
||||
|
14
shmup.cpp
14
shmup.cpp
@ -815,7 +815,7 @@ void movePlayer(monster *m, int delta) {
|
||||
hyperpoint jh = hpxy(mdx/100.0, mdy/100.0);
|
||||
hyperpoint ctr = m->pat * C0;
|
||||
|
||||
if(sphere && vid.alpha > 1.001) for(int i=0; i<3; i++) ctr[i] = -ctr[i];
|
||||
if(sphere && pconf.alpha > 1.001) for(int i=0; i<3; i++) ctr[i] = -ctr[i];
|
||||
|
||||
hyperpoint h = inverse(m->pat) * rgpushxto0(ctr) * jh;
|
||||
|
||||
@ -1104,7 +1104,7 @@ void movePlayer(monster *m, int delta) {
|
||||
int i0 = i;
|
||||
for(int a=0; a<3; a++) v[a] = (i0 % 3) - 1, i0 /= 3;
|
||||
v = v * .1 / hypot_d(3, v);
|
||||
transmatrix T1 = (i == 13) ? nat : parallel_transport(nat, m->ori, v, 2);
|
||||
transmatrix T1 = (i == 13) ? nat : parallel_transport(nat, m->ori, v);
|
||||
cell *c3 = c2;
|
||||
while(true) {
|
||||
cell *c4 = findbaseAround(tC0(T1), c3, 1);
|
||||
@ -1619,10 +1619,10 @@ void moveBullet(monster *m, int delta) {
|
||||
m->dead = true;
|
||||
|
||||
if(inertia_based) {
|
||||
nat = parallel_transport(nat, m->ori, m->inertia * delta, 10);
|
||||
nat = parallel_transport(nat, m->ori, m->inertia * delta);
|
||||
}
|
||||
else
|
||||
nat = parallel_transport(nat, m->ori, fronttangent(delta * SCALE * m->vel / speedfactor()), 10);
|
||||
nat = parallel_transport(nat, m->ori, fronttangent(delta * SCALE * m->vel / speedfactor()));
|
||||
cell *c2 = m->findbase(nat, 1);
|
||||
|
||||
if(m->parent && isPlayer(m->parent) && markOrb(itOrbLava) && c2 != m->base && !isPlayerOn(m->base))
|
||||
@ -2106,14 +2106,14 @@ void moveMonster(monster *m, int delta) {
|
||||
|
||||
if(inertia_based) {
|
||||
if(igo) return;
|
||||
nat = parallel_transport(nat, m->ori, m->inertia * delta, 10);
|
||||
nat = parallel_transport(nat, m->ori, m->inertia * delta);
|
||||
}
|
||||
else if(WDIM == 3 && igo) {
|
||||
ld fspin = rand() % 1000;
|
||||
nat = parallel_transport(nat0, m->ori, cspin(1,2,fspin) * spin(igospan[igo]) * xtangent(step), 10);
|
||||
nat = parallel_transport(nat0, m->ori, cspin(1,2,fspin) * spin(igospan[igo]) * xtangent(step));
|
||||
}
|
||||
else {
|
||||
nat = parallel_transport(nat0, m->ori, spin(igospan[igo]) * xtangent(step), 10);
|
||||
nat = parallel_transport(nat0, m->ori, spin(igospan[igo]) * xtangent(step));
|
||||
}
|
||||
|
||||
if(m->type != moRagingBull && !peace::on)
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
102
surface.cpp
102
surface.cpp
@ -24,7 +24,7 @@ string shape_name[] = { "hypersian rug", "tractricoid", "Dini's surface", "Kuen
|
||||
|
||||
EX eShape sh;
|
||||
|
||||
hyperpoint unit_vector[3] = {hpxyz(1,0,0), hpxyz(0,1,0), hpxyz(0,0,1)};
|
||||
hyperpoint unit_vector[3] = {point3(1,0,0), point3(0,1,0), point3(0,0,1)};
|
||||
|
||||
ld last_int_of = 0, last_int = 0;
|
||||
|
||||
@ -67,7 +67,7 @@ hyperpoint coord(hyperpoint h) {
|
||||
ld r = 1 / cosh(t);
|
||||
ld x = t - tanh(t);
|
||||
|
||||
return hpxyz( r * sin(v), r * cos(v), x );
|
||||
return point31( r * sin(v), r * cos(v), x );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ hyperpoint coord(hyperpoint h) {
|
||||
|
||||
ld a = sqrt(1-dini_b*dini_b);
|
||||
|
||||
return hpxyz( a * sin(v) * sin(t), a * cos(v) * sin(t), a * (cos(t) + log(tan(t/2))) + dini_b * v );
|
||||
return point31( a * sin(v) * sin(t), a * cos(v) * sin(t), a * (cos(t) + log(tan(t/2))) + dini_b * v );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ hyperpoint coord(hyperpoint h) {
|
||||
|
||||
ld deno = 1 / (1 + u * u * sin(v) * sin(v));
|
||||
|
||||
return hpxyz(
|
||||
return point31(
|
||||
2 * (cos(u) + u * sin(u)) * sin(v) * deno,
|
||||
2 * (sin(u) - u * cos(u)) * sin(v) * deno,
|
||||
log(tan(v/2)) + 2 * cos(v) * deno
|
||||
@ -101,7 +101,7 @@ hyperpoint coord(hyperpoint h) {
|
||||
ld phi = hyper_b * cosh(v);
|
||||
ld psi = integral(v);
|
||||
|
||||
return hpxyz( phi * cos(u), phi * sin(u), psi );
|
||||
return point31( phi * cos(u), phi * sin(u), psi );
|
||||
}
|
||||
|
||||
default:
|
||||
@ -122,10 +122,10 @@ hyperpoint coord_derivative(hyperpoint h, int cc) {
|
||||
ld v = h[1];
|
||||
if(cc == 0) {
|
||||
ld phi = hyper_b * cosh(v);
|
||||
return hpxyz( phi * -sin(u), phi * cos(u), 0 );
|
||||
return point3( phi * -sin(u), phi * cos(u), 0 );
|
||||
}
|
||||
else {
|
||||
return hpxyz( hyper_b * sinh(v) * cos(u), hyper_b * sinh(v) * sin(u), f(v) );
|
||||
return point3( hyper_b * sinh(v) * cos(u), hyper_b * sinh(v) * sin(u), f(v) );
|
||||
}
|
||||
}
|
||||
case dsKuen: {
|
||||
@ -134,12 +134,12 @@ hyperpoint coord_derivative(hyperpoint h, int cc) {
|
||||
ld denom = pow(sin(v),2)*(u*u)+1;
|
||||
ld denom2 = denom * denom;
|
||||
if(cc == 1)
|
||||
return hpxyz (
|
||||
return point3(
|
||||
2*sin(v)/denom*u*cos(u)+-4*(sin(u)*u+cos(u))*pow(sin(v),3)/denom2*u,
|
||||
-4*pow(sin(v),3)*(sin(u)-u*cos(u))/denom2*u+2*sin(u)*sin(v)/denom*u,
|
||||
-4*pow(sin(v),2)/denom2*u*cos(v)
|
||||
);
|
||||
else return hpxyz (
|
||||
else return point3(
|
||||
2*(sin(u)*u+cos(u))/denom*cos(v)+-4*(sin(u)*u+cos(u))*pow(sin(v),2)/denom2*(u*u)*cos(v),
|
||||
2*(sin(u)-u*cos(u))/denom*cos(v)+-4*pow(sin(v),2)*(sin(u)-u*cos(u))/denom2*(u*u)*cos(v),
|
||||
-4*sin(v)/denom2*(u*u)*pow(cos(v),2)+1/tan(v/2)*(pow(tan(v/2),2)+1)/2+-2*sin(v)/denom
|
||||
@ -166,13 +166,13 @@ ld compute_curvature(hyperpoint at) {
|
||||
hyperpoint shape_origin() {
|
||||
switch(sh) {
|
||||
case dsDini:
|
||||
return hpxyz(M_PI * .82, 0, 0);
|
||||
return point31(M_PI * .82, 0, 0);
|
||||
case dsTractricoid:
|
||||
return hpxyz(1, 0, 0);
|
||||
return point31(1, 0, 0);
|
||||
case dsKuen:
|
||||
return hpxyz(M_PI * .500001, M_PI * 1, 0);
|
||||
return point31(M_PI * .500001, M_PI * 1, 0);
|
||||
case dsHyperlike:
|
||||
return hpxyz(0,0,0);
|
||||
return point31(0,0,0);
|
||||
default:
|
||||
return Hypc;
|
||||
}
|
||||
@ -284,7 +284,7 @@ transmatrix create_M_matrix(hyperpoint zero, hyperpoint v1) {
|
||||
transmatrix T = build_matrix(Te0, Te1, Hypc, C03);
|
||||
|
||||
v1 = v1 / hypot_d(3, T*v1);
|
||||
hyperpoint v2 = hpxyz(1e-3, 1e-4, 0);
|
||||
hyperpoint v2 = point3(1e-3, 1e-4, 0);
|
||||
v2 = v2 - v1 * ((T*v1) | (T*v2)) / hypot_d(3, T*v1);
|
||||
v2 = v2 / hypot_d(3, T*v2);
|
||||
|
||||
@ -307,9 +307,9 @@ dexp_origin at_zero(hyperpoint zero, transmatrix start) {
|
||||
println(hlog, "zero = ", zero);
|
||||
|
||||
println(hlog, "curvature at zero = ", compute_curvature(zero));
|
||||
println(hlog, "curvature at X1 = ", compute_curvature(zero + hpxyz(.3, 0, 0)));
|
||||
println(hlog, "curvature at X2 = ", compute_curvature(zero + hpxyz(0, .3, 0)));
|
||||
println(hlog, "curvature at X3 = ", compute_curvature(zero + hpxyz(.4, .3, 0)));
|
||||
println(hlog, "curvature at X1 = ", compute_curvature(zero + point3(.3, 0, 0)));
|
||||
println(hlog, "curvature at X2 = ", compute_curvature(zero + point3(0, .3, 0)));
|
||||
println(hlog, "curvature at X3 = ", compute_curvature(zero + point3(.4, .3, 0)));
|
||||
|
||||
return {start, create_M_matrix(zero, unit_vector[0]), zero};
|
||||
}
|
||||
@ -338,14 +338,14 @@ void addTriangleV(rug::rugpoint *t1, rug::rugpoint *t2, rug::rugpoint *t3, ld le
|
||||
}
|
||||
|
||||
hyperpoint kuen_cross(ld v, ld u) {
|
||||
auto du = coord_derivative(hpxyz(v,u,0), 0);
|
||||
auto dv = coord_derivative(hpxyz(v,u,0), 1);
|
||||
auto du = coord_derivative(point3(v,u,0), 0);
|
||||
auto dv = coord_derivative(point3(v,u,0), 1);
|
||||
return du^dv;
|
||||
}
|
||||
|
||||
ld kuen_hypot(ld v, ld u) {
|
||||
auto du = coord_derivative(hpxyz(v,u,0), 0);
|
||||
auto dv = coord_derivative(hpxyz(v,u,0), 1);
|
||||
auto du = coord_derivative(point3(v,u,0), 0);
|
||||
auto dv = coord_derivative(point3(v,u,0), 1);
|
||||
auto n = hypot_d(3, du^dv);
|
||||
return n;
|
||||
}
|
||||
@ -368,7 +368,7 @@ int dexp_comb_colors[16] = {
|
||||
};
|
||||
|
||||
int coverage_style;
|
||||
vector<pair<hyperpoint, int> > coverage;
|
||||
EX vector<pair<hyperpoint, int> > coverage;
|
||||
|
||||
#ifndef CAP_KUEN_MAP
|
||||
#define CAP_KUEN_MAP 0
|
||||
@ -385,8 +385,8 @@ void draw_kuen_map() {
|
||||
for(int h=0; h<512; h++) {
|
||||
ld v = M_PI * (r+.5) / 512;
|
||||
ld u = 2 * M_PI * (h+.5) / 512;
|
||||
auto du = coord_derivative(hpxyz(v,u,0), 0);
|
||||
auto dv = coord_derivative(hpxyz(v,u,0), 1);
|
||||
auto du = coord_derivative(point3(v,u,0), 0);
|
||||
auto dv = coord_derivative(point3(v,u,0), 1);
|
||||
auto n = hypot_d(3, du^dv);
|
||||
|
||||
if(n > nmax) nmax = n;
|
||||
@ -459,7 +459,8 @@ void run_hyperlike() {
|
||||
int sgn = y > 0 ? 1 : -1;
|
||||
ld phi = hyper_b * cosh(y);
|
||||
int pt = y * precision * sgn / hyperlike_bound();
|
||||
p->flat = hpxyz(phi * cos(x), phi * sin(x), sgn * integral_table[pt]);
|
||||
USING_NATIVE_GEOMETRY;
|
||||
p->native = point31(phi * cos(x), phi * sin(x), sgn * integral_table[pt]);
|
||||
p->valid = true;
|
||||
}
|
||||
}
|
||||
@ -520,7 +521,8 @@ void run_kuen() {
|
||||
np->inqueue = false;
|
||||
np->dist = 0;
|
||||
np->h = p->h;
|
||||
np->flat = coord(px.params);
|
||||
USING_NATIVE_GEOMETRY;
|
||||
np->native = coord(px.params);
|
||||
np->surface_point = px;
|
||||
np->dexp_id = p->dexp_id;
|
||||
coverages[p->dexp_id] |= pid[part];
|
||||
@ -534,9 +536,11 @@ void run_kuen() {
|
||||
for(int i=0; i<3; i++)
|
||||
if(!r[i]) looks_good = false;
|
||||
if(!looks_good) continue;
|
||||
for(int i=0; i<3; i++)
|
||||
if(hypot_d(3, r[i]->flat - r[(i+1)%3]->flat) > .2)
|
||||
for(int i=0; i<3; i++) {
|
||||
USING_NATIVE_GEOMETRY;
|
||||
if(hypot_d(3, r[i]->native - r[(i+1)%3]->native) > .2)
|
||||
looks_good = false;
|
||||
}
|
||||
if(looks_good)
|
||||
addTriangleV(r[0], r[1], r[2]);
|
||||
}
|
||||
@ -557,9 +561,11 @@ void run_kuen() {
|
||||
|
||||
template<class T> void run_function(T f) {
|
||||
full_mesh();
|
||||
for(auto p: rug::points)
|
||||
p->flat = f(p->h),
|
||||
for(auto p: rug::points) {
|
||||
USING_NATIVE_GEOMETRY;
|
||||
p->native = f(p->h),
|
||||
p->valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
void run_other() {
|
||||
@ -572,7 +578,10 @@ void run_other() {
|
||||
auto h = p->h;
|
||||
|
||||
p->surface_point = map_to_surface(h, dp);
|
||||
p->flat = coord(p->surface_point.params);
|
||||
if(1) {
|
||||
USING_NATIVE_GEOMETRY;
|
||||
p->native = coord(p->surface_point.params);
|
||||
}
|
||||
history::progress(XLAT("solving the geodesics on: %1, %2/%3", XLAT(shape_name[sh]), its(it), its(isize(rug::points))));
|
||||
if(p->surface_point.remaining_distance == 0)
|
||||
coverage.emplace_back(h, rchar(it) + 256 * 7);
|
||||
@ -594,10 +603,9 @@ EX void run_shape(eShape s) {
|
||||
coverage.clear();
|
||||
need_mouseh = true;
|
||||
sh = s;
|
||||
transmatrix crot = rug::rugged ? rug::currentrot : Id;
|
||||
rug::apply_rotation(inverse(crot));
|
||||
|
||||
if(rug::rugged) rug::close();
|
||||
rug::gwhere = rug::rgEuclid;
|
||||
|
||||
rug::init();
|
||||
// if(!rug::rugged) rug::reopen();
|
||||
@ -641,8 +649,8 @@ EX void run_shape(eShape s) {
|
||||
ld minx = 1e9, maxx = -1e9;
|
||||
|
||||
for(auto p: rug::points) if(p->valid) {
|
||||
minx = min(p->flat[2], minx);
|
||||
maxx = max(p->flat[2], maxx);
|
||||
minx = min(p->native[2], minx);
|
||||
maxx = max(p->native[2], maxx);
|
||||
rug::qvalid++;
|
||||
}
|
||||
|
||||
@ -650,12 +658,8 @@ EX void run_shape(eShape s) {
|
||||
|
||||
ld shift = -(minx + maxx) / 2;
|
||||
for(auto p: rug::points) if(p->valid)
|
||||
p->flat[2] += shift;
|
||||
p->native[2] += shift;
|
||||
}
|
||||
|
||||
rug::apply_rotation(crot);
|
||||
if(rug::rug_perspective)
|
||||
rug::push_all_points(2, -rug::model_distance);
|
||||
}
|
||||
|
||||
void cancel_shape() {
|
||||
@ -703,6 +707,13 @@ EX void show_surfaces() {
|
||||
if((rug::rugged && sh && sh != dsHyperboloid && sh != dsHemisphere) || coverage_style)
|
||||
dialog::addSelItem(XLAT("display coverage"), cstyles[coverage_style], 'c');
|
||||
else dialog::addBreak(100);
|
||||
|
||||
#if CAP_FILES
|
||||
if(rug::rugged)
|
||||
dialog::addItem(XLAT("save the current embedding"), 's');
|
||||
else
|
||||
dialog::addItem(XLAT("load a saved embedding"), 's');
|
||||
#endif
|
||||
|
||||
dialog::addHelp();
|
||||
dialog::addBack();
|
||||
@ -722,6 +733,15 @@ EX void show_surfaces() {
|
||||
"For convenience, you can also choose other 3D models from this menu."
|
||||
));
|
||||
|
||||
#if CAP_FILES
|
||||
else if(uni == 's') {
|
||||
static string rugname = "saved.rug";
|
||||
if(rug::rugged)
|
||||
dialog::openFileDialog(rugname, XLAT("save embedding to:"), ".rug", [] () { rug::rug_save(rugname); return true; });
|
||||
else
|
||||
dialog::openFileDialog(rugname, XLAT("load embedding from:"), ".rug", [] () { rug::init(); rug::rug_load(rugname); return true; });
|
||||
}
|
||||
#endif
|
||||
else if(uni == '1')
|
||||
run_shape(dsTractricoid);
|
||||
else if(uni == '2')
|
||||
@ -747,7 +767,7 @@ EX void show_surfaces() {
|
||||
}
|
||||
else if(uni == 'x')
|
||||
for(auto p: rug::points)
|
||||
p->flat = p->surface_point.params;
|
||||
p->native = p->surface_point.params;
|
||||
else if(uni == '#')
|
||||
dialog::editNumber(dini_b, -1, 1, .05, .15, XLAT("parameter"),
|
||||
XLAT("The larger the number, the more twisted it is.")
|
||||
|
@ -227,6 +227,10 @@
|
||||
#define CAP_SVG (CAP_FILES && !ISMOBILE && !ISMINI)
|
||||
#endif
|
||||
|
||||
#ifndef CAP_WRL
|
||||
#define CAP_WRL (CAP_FILES && !ISMOBILE && !ISMINI && !ISWEB)
|
||||
#endif
|
||||
|
||||
#ifndef CAP_POLY
|
||||
#define CAP_POLY (CAP_SDLGFX || CAP_GL || CAP_SVG)
|
||||
#endif
|
||||
|
57
system.cpp
57
system.cpp
@ -225,6 +225,9 @@ EX void initgame() {
|
||||
items[itOrbWinter] = 30;
|
||||
items[itOrbFlash] = 30;
|
||||
}
|
||||
|
||||
if(firstland == laCA)
|
||||
items[itOrbAether] = 2;
|
||||
|
||||
if(tactic::on && firstland == laCaribbean) {
|
||||
if(hiitemsMax(itRedGem) >= 25) items[itRedGem] = min(hiitemsMax(itRedGem), 50);
|
||||
@ -436,19 +439,19 @@ void applyBox(int& t) {
|
||||
}
|
||||
|
||||
/** \brief the next box should contain tb */
|
||||
void applyBoxBignum(bignum& tb) {
|
||||
void applyBoxBignum(bignum& tb, string name) {
|
||||
float tf;
|
||||
int ti;
|
||||
if(saving) tf = tb.approx_ld();
|
||||
if(saving) memcpy(&ti, &tf, 4);
|
||||
applyBox(ti);
|
||||
applyBoxNum(ti, name);
|
||||
if(loading) memcpy(&tf, &ti, 4);
|
||||
if(loading) tb = bignum(tf);
|
||||
}
|
||||
|
||||
/** \brief the next box should contain i, and possibly be named name */
|
||||
EX void applyBoxNum(int& i, string name IS("")) {
|
||||
fakebox[boxid] = (name == "");
|
||||
fakebox[boxid] = (name == "" || name[0] == '@');
|
||||
boxname[boxid] = name;
|
||||
monsbox[boxid] = false;
|
||||
applyBox(i);
|
||||
@ -572,8 +575,8 @@ EX void applyBoxes() {
|
||||
applyBoxNum(cheater, "number of cheats");
|
||||
|
||||
fakebox[boxid] = true;
|
||||
if(saving) applyBoxSave(items[itOrbSafety] ? safetyland : cwt.at->land, "");
|
||||
else if(loading) firstland = safetyland = eLand(applyBoxLoad());
|
||||
if(saving) applyBoxSave(items[itOrbSafety] ? safetyland : cwt.at->land, "@safetyland");
|
||||
else if(loading) firstland = safetyland = eLand(applyBoxLoad("@safetyland"));
|
||||
else lostin = eLand(save.box[boxid++]);
|
||||
|
||||
for(int i=itOrbLightning; i<25; i++) applyBoxOrb(eItem(i));
|
||||
@ -620,9 +623,9 @@ EX void applyBoxes() {
|
||||
applyBoxOrb(itOrbSpace);
|
||||
|
||||
int geo = geometry;
|
||||
applyBoxNum(geo, ""); geometry = eGeometry(geo);
|
||||
applyBoxNum(geo, "@geometry"); geometry = eGeometry(geo);
|
||||
applyBoxBool(hardcore, "hardcore");
|
||||
applyBoxNum(hardcoreAt, "");
|
||||
applyBoxNum(hardcoreAt, "@hardcoreAt");
|
||||
applyBoxBool(shmup::on, "shmup");
|
||||
if(saving) applyBoxSave(specialland, "euclid land");
|
||||
else if(loading) specialland = eLand(applyBoxLoad("euclid land"));
|
||||
@ -656,8 +659,8 @@ EX void applyBoxes() {
|
||||
applyBoxM(moPrincessMoved, false); // live Princess for Safety
|
||||
applyBoxM(moPrincessArmedMoved, false); // live Princess for Safety
|
||||
applyBoxM(moMouse);
|
||||
applyBoxNum(princess::saveArmedHP, "");
|
||||
applyBoxNum(princess::saveHP, "");
|
||||
applyBoxNum(princess::saveArmedHP, "@saveArmedHP");
|
||||
applyBoxNum(princess::saveHP, "@saveHP");
|
||||
|
||||
applyBoxI(itIvory);
|
||||
applyBoxI(itElemental);
|
||||
@ -687,8 +690,8 @@ EX void applyBoxes() {
|
||||
applyBoxOrb(itOrbLuck);
|
||||
applyBoxOrb(itOrbStunning);
|
||||
|
||||
applyBoxBool(tactic::on, "");
|
||||
applyBoxNum(elec::lightningfast, "");
|
||||
applyBoxBool(tactic::on, "@tactic");
|
||||
applyBoxNum(elec::lightningfast, "@lightningfast");
|
||||
|
||||
// if(save.box[boxid]) printf("lotus = %d (lost = %d)\n", save.box[boxid], isHaunted(lostin));
|
||||
if(loadingHi && isHaunted(lostin)) boxid++;
|
||||
@ -700,7 +703,7 @@ EX void applyBoxes() {
|
||||
applyBoxOrb(itMutant2);
|
||||
applyBoxOrb(itOrbFreedom);
|
||||
applyBoxM(moRedFox);
|
||||
applyBoxBool(survivalist);
|
||||
applyBoxBool(survivalist, "@survivalist");
|
||||
if(loadingHi) applyBoxI(itLotus);
|
||||
else applyBoxNum(truelotus, "lotus/escape");
|
||||
|
||||
@ -730,17 +733,17 @@ EX void applyBoxes() {
|
||||
applyBoxM(moDragonHead);
|
||||
applyBoxOrb(itOrbDomination);
|
||||
applyBoxI(itBabyTortoise);
|
||||
applyBoxNum(tortoise::seekbits, "");
|
||||
applyBoxNum(tortoise::seekbits, "@seekbits");
|
||||
applyBoxM(moTortoise);
|
||||
applyBoxOrb(itOrbShell);
|
||||
|
||||
applyBoxNum(safetyseed);
|
||||
applyBoxNum(safetyseed, "@safetyseed");
|
||||
|
||||
// (+18)
|
||||
for(int i=0; i<6; i++) {
|
||||
applyBoxNum(multi::treasures[i]);
|
||||
applyBoxNum(multi::kills[i]);
|
||||
applyBoxNum(multi::deaths[i]);
|
||||
applyBoxNum(multi::treasures[i], "@multi-treasures" + its(i));
|
||||
applyBoxNum(multi::kills[i], "@multi-kills" + its(i));
|
||||
applyBoxNum(multi::deaths[i], "@multi-deaths" + its(i));
|
||||
}
|
||||
// (+8)
|
||||
applyBoxM(moDragonTail);
|
||||
@ -757,7 +760,7 @@ EX void applyBoxes() {
|
||||
bool sph;
|
||||
sph = false; applyBoxBool(sph, "sphere"); if(sph) geometry = gSphere;
|
||||
sph = false; applyBoxBool(sph, "elliptic"); if(sph) geometry = gElliptic;
|
||||
applyBox(princess::reviveAt);
|
||||
applyBoxNum(princess::reviveAt, "@reviveAt");
|
||||
|
||||
applyBoxI(itDodeca);
|
||||
applyBoxI(itAmethyst);
|
||||
@ -780,13 +783,13 @@ EX void applyBoxes() {
|
||||
applyBoxM(moGadfly);
|
||||
|
||||
// 10.0:
|
||||
applyBoxNum(hinttoshow); // 258
|
||||
applyBoxNum(hinttoshow, "@hinttoshow"); // 258
|
||||
addinv(itOrbMirror);
|
||||
addinv(itGreenStone);
|
||||
list_invorb();
|
||||
applyBoxBool(inv::on, "inventory"); // 306
|
||||
#if CAP_INV
|
||||
applyBoxNum(inv::rseed);
|
||||
applyBoxNum(inv::rseed, "@inv-rseed");
|
||||
#else
|
||||
{ int u; applyBoxNum(u); }
|
||||
#endif
|
||||
@ -828,16 +831,16 @@ EX void applyBoxes() {
|
||||
applyBoxM(moMonk);
|
||||
|
||||
bool v2 = false;
|
||||
applyBoxBool(v2); if(loading && v2) variation = eVariation::goldberg;
|
||||
applyBox(gp::param.first);
|
||||
applyBox(gp::param.second);
|
||||
applyBoxBool(v2, "@variation"); if(loading && v2) variation = eVariation::goldberg;
|
||||
applyBoxNum(gp::param.first, "@gp-first");
|
||||
applyBoxNum(gp::param.second, "@gp-second");
|
||||
|
||||
v2 = false; applyBoxBool(v2); if(loading && v2) variation = eVariation::irregular;
|
||||
applyBox(irr::cellcount);
|
||||
applyBoxNum(irr::cellcount, "@irr-cellcount");
|
||||
|
||||
list_invorb();
|
||||
|
||||
applyBox(irr::bitruncations_performed);
|
||||
applyBoxNum(irr::bitruncations_performed, "@irr-bitruncations");
|
||||
|
||||
applyBoxI(itVarTreasure);
|
||||
applyBoxI(itBrownian);
|
||||
@ -855,8 +858,8 @@ EX void applyBoxes() {
|
||||
applyBoxM(moNarciss);
|
||||
applyBoxM(moMirrorSpirit);
|
||||
|
||||
applyBox(clearing::direct);
|
||||
applyBoxBignum(clearing::imputed);
|
||||
applyBoxNum(clearing::direct, "@clearing-direct");
|
||||
applyBoxBignum(clearing::imputed, "@clearing-imputed");
|
||||
|
||||
applyBoxOrb(itOrbImpact);
|
||||
applyBoxOrb(itOrbChaos);
|
||||
|
40
textures.cpp
40
textures.cpp
@ -65,7 +65,6 @@ struct texture_data {
|
||||
struct texture_config {
|
||||
string texturename;
|
||||
string configname;
|
||||
color_t paint_color;
|
||||
eTextureState tstate;
|
||||
eTextureState tstate_max;
|
||||
|
||||
@ -121,7 +120,6 @@ struct texture_config {
|
||||
texturename = "textures/hyperrogue-texture.png";
|
||||
configname = "textures/hyperrogue.txc";
|
||||
itt = Id;
|
||||
paint_color = 0x000000FF;
|
||||
grid_color = 0;
|
||||
mesh_color = 0;
|
||||
master_color = 0xFFFFFF30;
|
||||
@ -355,7 +353,7 @@ hyperpoint texture_config::texture_coordinates(hyperpoint h) {
|
||||
hyperpoint inmodel;
|
||||
applymodel(h, inmodel);
|
||||
inmodel[0] *= current_display->radius * 1. / current_display->scrsize;
|
||||
inmodel[1] *= current_display->radius * vid.stretch / current_display->scrsize;
|
||||
inmodel[1] *= current_display->radius * pconf.stretch / current_display->scrsize;
|
||||
inmodel[2] = 1;
|
||||
inmodel = itt * inmodel;
|
||||
inmodel[0] = (inmodel[0] + 1) / 2;
|
||||
@ -531,7 +529,7 @@ void texture_config::mark_triangles() {
|
||||
}
|
||||
}
|
||||
|
||||
static const auto current_texture_parameters = tie(geometry, variation, patterns::whichPattern, patterns::subpattern_flags, pmodel, vid.scale, vid.alpha);
|
||||
static const auto current_texture_parameters = tie(geometry, variation, patterns::whichPattern, patterns::subpattern_flags, pmodel, pconf.scale, pconf.alpha);
|
||||
|
||||
void texture_config::clear_texture_map() {
|
||||
texture_map.clear();
|
||||
@ -624,9 +622,9 @@ void texture_config::saveFullTexture(string tn) {
|
||||
addMessage(XLAT("Saving full texture to %1...", tn));
|
||||
dynamicval<color_t> dd(grid_color, 0);
|
||||
dynamicval<color_t> dm(mesh_color, 0);
|
||||
dynamicval<ld> dx(vid.xposition, 0);
|
||||
dynamicval<ld> dy(vid.yposition, 0);
|
||||
dynamicval<ld> dvs(vid.scale, (pmodel == mdDisk && !euclid) ? 1 : vid.scale);
|
||||
dynamicval<ld> dx(pconf.xposition, 0);
|
||||
dynamicval<ld> dy(pconf.yposition, 0);
|
||||
dynamicval<ld> dvs(pconf.scale, (pmodel == mdDisk && !euclid) ? 1 : pconf.scale);
|
||||
dynamicval<bool> dro(rug::rugged, false);
|
||||
dynamicval<bool> dnh(nohud, true);
|
||||
texture::saving = true;
|
||||
@ -741,9 +739,9 @@ struct magic_param {
|
||||
|
||||
void apply(ld delta) {
|
||||
if(have_mp(mpProjection))
|
||||
vid.alpha *= exp(delta * proj);
|
||||
pconf.alpha *= exp(delta * proj);
|
||||
if(have_mp(mpScale))
|
||||
vid.scale *= exp(delta * scale);
|
||||
pconf.scale *= exp(delta * scale);
|
||||
|
||||
if(do_spin) {
|
||||
if(have_mp(mpRotate))
|
||||
@ -853,7 +851,7 @@ void mousemovement() {
|
||||
// do not zoom in portrait!
|
||||
if(nonzero && !newmove) {
|
||||
View = inverse(spintox(mouseeu)) * spintox(lastmouse) * View;
|
||||
vid.scale = vid.scale * sqhypot_d(2, mouseeu) / sqhypot_d(2, lastmouse);
|
||||
pconf.scale = pconf.scale * sqhypot_d(2, mouseeu) / sqhypot_d(2, lastmouse);
|
||||
config.perform_mapping();
|
||||
}
|
||||
if(nonzero) lastmouse = mouseeu;
|
||||
@ -863,7 +861,7 @@ void mousemovement() {
|
||||
|
||||
case tpsProjection: {
|
||||
if(nonzero && !newmove) {
|
||||
vid.alpha = vid.alpha * sqhypot_d(2, mouseeu) / sqhypot_d(2, lastmouse);
|
||||
pconf.alpha = pconf.alpha * sqhypot_d(2, mouseeu) / sqhypot_d(2, lastmouse);
|
||||
}
|
||||
if(nonzero) lastmouse = mouseeu;
|
||||
newmove = false;
|
||||
@ -958,9 +956,9 @@ void init_textureconfig() {
|
||||
addsaverenum(targetgeometry, "geometry", gNormal);
|
||||
addsaverenum(pmodel, "used model", mdDisk);
|
||||
addsaver(vid.yshift, "Y shift", 0);
|
||||
addsaver(vid.yposition, "Y position", 0);
|
||||
addsaver(vid.xposition, "X position", 0);
|
||||
addsaver(vid.camera_angle, "camera angle", 0);
|
||||
addsaver(pconf.yposition, "Y position", 0);
|
||||
addsaver(pconf.xposition, "X position", 0);
|
||||
addsaver(pconf.camera_angle, "camera angle", 0);
|
||||
addsaverenum(targetvariation, "bitruncated", eVariation::bitruncated);
|
||||
// ... geometry parameters
|
||||
|
||||
@ -977,9 +975,9 @@ void init_textureconfig() {
|
||||
addsaver(config.color_alpha, "alpha color", 0);
|
||||
addsaver(config.mesh_color, "mesh color", 0);
|
||||
|
||||
addsaver(vid.alpha, "projection", 1);
|
||||
addsaver(vid.scale, "scale", 1);
|
||||
addsaver(vid.stretch, "stretch", 1);
|
||||
addsaver(pconf.alpha, "projection", 1);
|
||||
addsaver(pconf.scale, "scale", 1);
|
||||
addsaver(pconf.stretch, "stretch", 1);
|
||||
addsaver(vid.binary_width, "binary-tiling-width", 1);
|
||||
|
||||
addsaver(config.texturename, "texture filename", "");
|
||||
@ -1449,8 +1447,6 @@ array<point, 3> ptc(const array<hyperpoint, 3>& h) {
|
||||
return make_array(ptc(h[0]), ptc(h[1]), ptc(h[2]));
|
||||
}
|
||||
|
||||
EX ld penwidth = .02;
|
||||
|
||||
int texture_distance(pair<int, int> p1, pair<int, int> p2) {
|
||||
return max(abs(p1.first-p2.first), abs(p1.second - p2.second));
|
||||
}
|
||||
@ -1521,7 +1517,7 @@ void filltriangle(const array<hyperpoint, 3>& v, const array<point, 3>& p, color
|
||||
|
||||
void splitseg(const transmatrix& A, const array<ld, 2>& angles, const array<hyperpoint, 2>& h, const array<point, 2>& p, color_t col, int lev) {
|
||||
ld newangle = (angles[0] + angles[1]) / 2;
|
||||
hyperpoint nh = A * xspinpush0(newangle, penwidth);
|
||||
hyperpoint nh = A * xspinpush0(newangle, mapeditor::dtwidth);
|
||||
auto np = ptc(nh);
|
||||
|
||||
filltriangle(make_array(h[0],h[1],nh), make_array(p[0],p[1],np), col, lev);
|
||||
@ -1538,7 +1534,7 @@ void fillcircle(hyperpoint h, color_t col) {
|
||||
|
||||
ld step = M_PI * 2/3;
|
||||
|
||||
array<hyperpoint, 3> mh = make_array(A * xpush0(penwidth), A * xspinpush0(step, penwidth), A * xspinpush0(-step, penwidth));
|
||||
array<hyperpoint, 3> mh = make_array(A * xpush0(mapeditor::dtwidth), A * xspinpush0(step, mapeditor::dtwidth), A * xspinpush0(-step, mapeditor::dtwidth));
|
||||
auto mp = ptc(mh);
|
||||
|
||||
filltriangle(mh, mp, col, 0);
|
||||
@ -1596,7 +1592,7 @@ EX void drawPixel(hyperpoint h, color_t col) {
|
||||
}
|
||||
|
||||
EX void drawLine(hyperpoint h1, hyperpoint h2, color_t col, int steps IS(10)) {
|
||||
if(steps > 0 && hdist(h1, h2) > penwidth / 3) {
|
||||
if(steps > 0 && hdist(h1, h2) > mapeditor::dtwidth / 3) {
|
||||
hyperpoint h3 = mid(h1, h2);
|
||||
drawLine(h1, h3, col, steps-1);
|
||||
drawLine(h3, h2, col, steps-1);
|
||||
|
20
tour.cpp
20
tour.cpp
@ -175,7 +175,7 @@ EX void slidehelp() {
|
||||
/** \brief return from a subgame launched while in presentation */
|
||||
void return_geometry() {
|
||||
gamestack::pop();
|
||||
vid.scale = 1; vid.alpha = 1;
|
||||
pconf.scale = 1; pconf.alpha = 1;
|
||||
presentation(pmGeometryReset);
|
||||
addMessage(XLAT("Returned to your game."));
|
||||
}
|
||||
@ -262,11 +262,11 @@ bool handleKeyTour(int sym, int uni) {
|
||||
break;
|
||||
case '1':
|
||||
set_geometry(gSphere);
|
||||
vid.alpha = 1, vid.scale = .5;
|
||||
pconf.alpha = 1, pconf.scale = .5;
|
||||
break;
|
||||
case '2':
|
||||
set_geometry(gEuclid);
|
||||
vid.alpha = 1, vid.scale = .5;
|
||||
pconf.alpha = 1, pconf.scale = .5;
|
||||
break;
|
||||
}
|
||||
start_game();
|
||||
@ -288,7 +288,7 @@ bool handleKeyTour(int sym, int uni) {
|
||||
return true;
|
||||
}
|
||||
if(NUMBERKEY == '3' && sphere) {
|
||||
if(vid.alpha < 2) vid.scale = 400, vid.alpha = 400; else vid.scale = .5, vid.alpha = 1;
|
||||
if(pconf.alpha < 2) pconf.scale = 400, pconf.alpha = 400; else pconf.scale = .5, pconf.alpha = 1;
|
||||
addMessage(XLAT("Changed the projection."));
|
||||
return true;
|
||||
}
|
||||
@ -450,8 +450,8 @@ EX namespace ss {
|
||||
|
||||
EX void start() {
|
||||
currentslide = 0;
|
||||
vid.scale = 1;
|
||||
vid.alpha = 1;
|
||||
pconf.scale = 1;
|
||||
pconf.alpha = 1;
|
||||
pmodel = mdDisk;
|
||||
if(!tour::on) presentation(pmStartAll);
|
||||
else {
|
||||
@ -839,8 +839,8 @@ EX slide default_slides[] = {
|
||||
{models+"Beltrami-Klein model", 43, LEGAL::ANY | USE_SLIDE_NAME,
|
||||
"This model renders straight lines as straight, but it distorts angles.",
|
||||
[] (presmode mode) {
|
||||
if(mode == 1 || mode == pmGeometryReset || mode == pmGeometry) vid.alpha = 0;
|
||||
if(mode == 3) vid.alpha = 1;
|
||||
if(mode == 1 || mode == pmGeometryReset || mode == pmGeometry) pconf.alpha = 0;
|
||||
if(mode == 3) pconf.alpha = 1;
|
||||
}
|
||||
},
|
||||
{models+"Gans model", 44, LEGAL::ANY | USE_SLIDE_NAME,
|
||||
@ -849,8 +849,8 @@ EX slide default_slides[] = {
|
||||
"model are all obtained by looking at either the hyperboloid model or an "
|
||||
"equidistant surface from various distances.",
|
||||
[] (presmode mode) {
|
||||
if(mode == 1 || mode == pmGeometryReset || mode == pmGeometry) vid.alpha = 400, vid.scale = 150;
|
||||
if(mode == 3) vid.alpha = vid.scale = 1;
|
||||
if(mode == 1 || mode == pmGeometryReset || mode == pmGeometry) pconf.alpha = 400, pconf.scale = 150;
|
||||
if(mode == 3) pconf.alpha = pconf.scale = 1;
|
||||
}
|
||||
},
|
||||
{models+"Band model", 45, LEGAL::NONEUC | USE_SLIDE_NAME,
|
||||
|
19
util.cpp
19
util.cpp
@ -134,7 +134,13 @@ struct hr_parse_exception : hr_exception {
|
||||
struct exp_parser {
|
||||
string s;
|
||||
int at;
|
||||
exp_parser() { at = 0; }
|
||||
int line_number, last_line;
|
||||
exp_parser() { at = 0; line_number = 1; last_line = 0; }
|
||||
|
||||
string where() {
|
||||
if(s.find('\n')) return "(line " + its(line_number) + ", pos " + its(at-last_line) + ")";
|
||||
else return "(pos " + its(at) + ")";
|
||||
}
|
||||
|
||||
map<string, cld> extra_params;
|
||||
|
||||
@ -168,14 +174,21 @@ struct exp_parser {
|
||||
|
||||
void force_eat(const char *c) {
|
||||
skip_white();
|
||||
if(!eat(c)) throw hr_parse_exception("expected: " + string(c));
|
||||
if(!eat(c)) throw hr_parse_exception("expected: " + string(c) + " at " + where());
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
void exp_parser::skip_white() {
|
||||
while(next() == ' ' || next() == '\n' || next() == '\r' || next() == '\t') at++;
|
||||
while(next() == ' ' || next() == '\n' || next() == '\r' || next() == '\t') {
|
||||
if(next() == '\r') last_line++;
|
||||
if(next() == '\n') {
|
||||
println(hlog, "new line at ", at);
|
||||
line_number++, last_line = at;
|
||||
}
|
||||
at++;
|
||||
}
|
||||
}
|
||||
|
||||
string exp_parser::next_token() {
|
||||
|
Loading…
Reference in New Issue
Block a user