mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-02-22 14:00:13 +00:00
Merge branch 'master' into mymake
This commit is contained in:
commit
5ec85100e9
@ -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();
|
||||
|
@ -952,12 +952,12 @@ EX void achievement_display() {
|
||||
col /= 10; col *= 0x10101;
|
||||
displayfr(vid.xres/2, vid.yres/4, 2, vid.fsize * 2, achievementMessage[0], col & 0xFFFF00, 8);
|
||||
int w = 2 * vid.fsize;
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
while(w>3 && textwidth(w, achievementMessage[1]) > vid.xres) w--;
|
||||
#endif
|
||||
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*2, 2, w, achievementMessage[1], col, 8);
|
||||
w = vid.fsize;
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
while(w>3 && textwidth(w, achievementMessage[2]) > vid.xres) w--;
|
||||
#endif
|
||||
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*4, 2, w, achievementMessage[2], col, 8);
|
||||
|
447
arbitrile.cpp
447
arbitrile.cpp
@ -49,18 +49,74 @@ EX arbi_tiling current;
|
||||
|
||||
EX short& id_of(heptagon *h) { return h->zebraval; }
|
||||
|
||||
struct hr_polygon_error : hr_exception {
|
||||
vector<transmatrix> v;
|
||||
eGeometryClass c;
|
||||
int id;
|
||||
map<string, cld> params;
|
||||
hr_polygon_error(const vector<transmatrix>& _v, int _id) : v(_v), c(cgclass), id(_id) {}
|
||||
~hr_polygon_error() noexcept(true) {}
|
||||
};
|
||||
|
||||
struct connection_debug_request : hr_exception {
|
||||
int id;
|
||||
eGeometryClass c;
|
||||
connection_debug_request(int i): id(i), c(cgclass) {}
|
||||
};
|
||||
|
||||
void ensure_geometry(eGeometryClass c) {
|
||||
stop_game();
|
||||
if(c != cgclass) {
|
||||
if(c == gcEuclid) set_geometry(gEuclid);
|
||||
if(c == gcHyperbolic) set_geometry(gNormal);
|
||||
if(c == gcSphere) set_geometry(gSphere);
|
||||
}
|
||||
|
||||
if(specialland != laCanvas) {
|
||||
canvas_default_wall = waInvisibleFloor;
|
||||
patterns::whichCanvas = 'g';
|
||||
patterns::canvasback = 0xFFFFFF;
|
||||
firstland = specialland = laCanvas;
|
||||
}
|
||||
start_game();
|
||||
}
|
||||
|
||||
void start_poly_debugger(hr_polygon_error& err) {
|
||||
ensure_geometry(err.c);
|
||||
|
||||
drawthemap();
|
||||
|
||||
mapeditor::drawing_tool = true;
|
||||
pushScreen(mapeditor::showDrawEditor);
|
||||
mapeditor::initdraw(cwt.at);
|
||||
|
||||
int n = isize(err.v);
|
||||
|
||||
mapeditor::dtcolor = 0xFF0000FF;
|
||||
mapeditor::dtwidth = 0.02;
|
||||
for(int i=0; i<n-1; i++)
|
||||
mapeditor::dt_add_line(tC0(err.v[i]), tC0(err.v[i+1]), 0);
|
||||
|
||||
mapeditor::dtcolor = 0xFFFFFFFF;
|
||||
for(int i=0; i<n; i++)
|
||||
mapeditor::dt_add_text(tC0(err.v[i]), 0.5, its(i));
|
||||
}
|
||||
|
||||
void shape::build_from_angles_edges() {
|
||||
transmatrix at = Id;
|
||||
vertices.clear();
|
||||
int n = isize(angles);
|
||||
hyperpoint ctr = Hypc;
|
||||
vector<transmatrix> matrices;
|
||||
for(int i=0; i<n; i++) {
|
||||
matrices.push_back(at);
|
||||
println(hlog, "at = ", at);
|
||||
vertices.push_back(tC0(at));
|
||||
ctr += tC0(at);
|
||||
at = at * xpush(edges[i]) * spin(angles[i]);
|
||||
}
|
||||
if(!eqmatrix(at, Id)) throw hr_parse_exception("polygon error");
|
||||
matrices.push_back(at);
|
||||
if(!eqmatrix(at, Id)) throw hr_polygon_error(matrices, id);
|
||||
if(sqhypot_d(3, ctr) < 1e-2) {
|
||||
// this may happen for some spherical tilings
|
||||
// try to move towards the center
|
||||
@ -78,10 +134,43 @@ 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";
|
||||
|
||||
EX void load_tile(exp_parser& ep, bool unit) {
|
||||
current.shapes.emplace_back();
|
||||
auto& cc = current.shapes.back();
|
||||
cc.id = isize(current.shapes) - 1;
|
||||
cc.flags = 0;
|
||||
while(ep.next() != ')') {
|
||||
cld dist = 1;
|
||||
if(!unit) {
|
||||
dist = ep.parse(0);
|
||||
ep.force_eat(",");
|
||||
}
|
||||
cld angle = ep.parse(0);
|
||||
cc.edges.push_back(ep.validate_real(dist * ep.extra_params["distunit"]));
|
||||
cc.angles.push_back(ep.validate_real(angle * ep.extra_params["angleunit"] + ep.extra_params["angleofs"]));
|
||||
if(ep.eat(",")) continue;
|
||||
else if(ep.eat(")")) break;
|
||||
else throw hr_parse_exception("expecting , or )");
|
||||
}
|
||||
try {
|
||||
cc.build_from_angles_edges();
|
||||
}
|
||||
catch(hr_parse_exception& ex) {
|
||||
throw hr_parse_exception(ex.s + ep.where());
|
||||
}
|
||||
catch(hr_polygon_error& poly) {
|
||||
poly.params = ep.extra_params;
|
||||
throw;
|
||||
}
|
||||
cc.connections.resize(cc.size());
|
||||
for(int i=0; i<isize(cc.connections); i++)
|
||||
cc.connections[i] = make_tuple(cc.id, i, false);
|
||||
}
|
||||
|
||||
EX void load(const string& fname) {
|
||||
fhstream f(fname, "rt");
|
||||
string s;
|
||||
@ -102,7 +191,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(")");
|
||||
};
|
||||
@ -131,16 +220,19 @@ EX void load(const string& fname) {
|
||||
ginf[gArbitrary].g = giEuclid2;
|
||||
ginf[gArbitrary].sides = 7;
|
||||
set_flag(ginf[gArbitrary].flags, qBOUNDED, false);
|
||||
set_flag(ginf[gArbitrary].flags, qAFFINE, true);
|
||||
}
|
||||
else if(ep.eat("h2.")) {
|
||||
ginf[gArbitrary].g = giHyperb2;
|
||||
ginf[gArbitrary].sides = 7;
|
||||
set_flag(ginf[gArbitrary].flags, qBOUNDED, false);
|
||||
set_flag(ginf[gArbitrary].flags, qAFFINE, false);
|
||||
}
|
||||
else if(ep.eat("s2.")) {
|
||||
ginf[gArbitrary].g = giSphere2;
|
||||
ginf[gArbitrary].sides = 5;
|
||||
set_flag(ginf[gArbitrary].flags, qBOUNDED, false);
|
||||
set_flag(ginf[gArbitrary].flags, qAFFINE, false);
|
||||
}
|
||||
else if(ep.eat("angleunit(")) angleunit = real(ep.parsepar());
|
||||
else if(ep.eat("angleofs(")) angleofs = real(ep.parsepar());
|
||||
@ -157,43 +249,11 @@ EX void load(const string& fname) {
|
||||
string tok = ep.next_token();
|
||||
ep.force_eat("=");
|
||||
ep.extra_params[tok] =ep.parsepar();
|
||||
if(debugflags & DF_GEOM)
|
||||
println(hlog, "let ", tok, " = ", real(ep.extra_params[tok]));
|
||||
}
|
||||
else if(ep.eat("unittile(")) {
|
||||
c.shapes.emplace_back();
|
||||
auto& cc = c.shapes.back();
|
||||
cc.id = isize(c.shapes) - 1;
|
||||
cc.flags = 0;
|
||||
while(ep.next() != ')') {
|
||||
ld angle = ep.rparse(0);
|
||||
cc.edges.push_back(distunit);
|
||||
cc.angles.push_back(angle * angleunit + angleofs);
|
||||
if(ep.eat(",")) continue;
|
||||
else if(ep.eat(")")) break;
|
||||
else throw hr_parse_exception("expecting , or )");
|
||||
}
|
||||
cc.build_from_angles_edges();
|
||||
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("tile(")) {
|
||||
c.shapes.emplace_back();
|
||||
auto& cc = c.shapes.back();
|
||||
cc.id = isize(c.shapes) - 1;
|
||||
cc.flags = 0;
|
||||
while(ep.next() != ')') {
|
||||
ld dist = ep.rparse(0);
|
||||
ep.force_eat(",");
|
||||
ld angle = ep.rparse(0);
|
||||
cc.edges.push_back(dist * distunit);
|
||||
cc.angles.push_back(angle * angleunit + angleofs);
|
||||
if(ep.eat(",")) continue;
|
||||
else if(ep.eat(")")) break;
|
||||
else throw hr_parse_exception("expecting , or )");
|
||||
}
|
||||
cc.build_from_angles_edges();
|
||||
cc.connections.resize(cc.size());
|
||||
}
|
||||
else if(ep.eat("unittile(")) load_tile(ep, true);
|
||||
else if(ep.eat("tile(")) load_tile(ep, false);
|
||||
else if(ep.eat("conway(\"")) {
|
||||
string s = "";
|
||||
while(true) {
|
||||
@ -201,7 +261,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 +281,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,10 +312,93 @@ EX void load(const string& fname) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else throw hr_parse_exception("expecting command");
|
||||
else if(ep.eat("debug(")) {
|
||||
int i = ep.iparse(0);
|
||||
verify_index(i, c.shapes, ep);
|
||||
ep.force_eat(")");
|
||||
throw connection_debug_request(i);
|
||||
}
|
||||
else throw hr_parse_exception("expecting command, " + ep.where());
|
||||
}
|
||||
}
|
||||
|
||||
arbi_tiling debugged;
|
||||
vector<pair<transmatrix, int> > debug_polys;
|
||||
|
||||
string primes(int i) {
|
||||
string res;
|
||||
while(i--) res += "'";
|
||||
return res;
|
||||
}
|
||||
|
||||
void connection_debugger() {
|
||||
cmode = sm::SIDE | sm::DIALOG_STRICT_X;
|
||||
gamescreen(0);
|
||||
|
||||
auto& last = debug_polys.back();
|
||||
|
||||
initquickqueue();
|
||||
for(auto& p: debug_polys) {
|
||||
int id = p.second;
|
||||
|
||||
transmatrix V = gmatrix[cwt.at] * p.first;
|
||||
|
||||
auto& sh = debugged.shapes[id].vertices;
|
||||
|
||||
for(auto& v: sh)
|
||||
curvepoint(V * v);
|
||||
|
||||
curvepoint(V * sh[0]);
|
||||
|
||||
color_t col = colortables['A'][id];
|
||||
col = darkena(col, 0, 0xFF);
|
||||
|
||||
if(&p == &last) {
|
||||
vid.linewidth *= 2;
|
||||
queuecurve(0xFFFF00FF, col, PPR::LINE);
|
||||
vid.linewidth /= 2;
|
||||
for(int i=0; i<isize(sh); i++)
|
||||
queuestr(V * sh[i], vid.fsize, its(i), 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
queuecurve(0xFFFFFFFF, col, PPR::LINE);
|
||||
}
|
||||
quickqueue();
|
||||
|
||||
dialog::init(XLAT("connection debugger"));
|
||||
|
||||
dialog::addInfo(debugged.name);
|
||||
dialog::addHelp(debugged.comment);
|
||||
|
||||
dialog::addBreak(50);
|
||||
|
||||
dialog::addInfo("face index " + its(last.second));
|
||||
|
||||
dialog::addBreak(50);
|
||||
|
||||
auto& sh = debugged.shapes[last.second];
|
||||
int N = isize(sh.edges);
|
||||
for(int k=0; k<N; k++) {
|
||||
auto con = sh.connections[k];
|
||||
string cap = its(k) + primes(last.second) + " -> " + its(get<1>(con)) + primes(get<0>(con)) + (get<2>(con) ? " (m) " : "");
|
||||
dialog::addSelItem(cap, "go", '0' + k);
|
||||
|
||||
dialog::add_action([k, last, con] {
|
||||
debug_polys.emplace_back(last.first * get_adj(debugged, last.second, k, -1), get<0>(con));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
|
||||
keyhandler = [] (int sym, int uni) {
|
||||
handlePanning(sym, uni);
|
||||
dialog::handleNavigation(sym, uni);
|
||||
if(doexiton(sym, uni)) popScreen();
|
||||
};
|
||||
}
|
||||
|
||||
geometryinfo1& arbi_tiling::get_geometry() {
|
||||
return ginf[gEuclid].g;
|
||||
}
|
||||
@ -268,6 +411,56 @@ EX hrmap *current_altmap;
|
||||
|
||||
heptagon *build_child(heptspin p, pair<int, int> adj);
|
||||
|
||||
EX transmatrix get_adj(arbi_tiling& c, int t, int dl, int xdl) {
|
||||
|
||||
auto& sh = c.shapes[t];
|
||||
|
||||
int dr = gmod(dl+1, sh.size());
|
||||
|
||||
auto& co = sh.connections[dl];
|
||||
int xt = get<0>(co);
|
||||
if(xdl == -1) xdl = get<1>(co);
|
||||
int m = get<2>(co);
|
||||
|
||||
auto& xsh = c.shapes[xt];
|
||||
int xdr = gmod(xdl+1, xsh.size());
|
||||
|
||||
hyperpoint vl = sh.vertices[dl];
|
||||
hyperpoint vr = sh.vertices[dr];
|
||||
hyperpoint vm = mid(vl, vr);
|
||||
|
||||
transmatrix rm = gpushxto0(vm);
|
||||
|
||||
hyperpoint xvl = xsh.vertices[xdl];
|
||||
hyperpoint xvr = xsh.vertices[xdr];
|
||||
hyperpoint xvm = mid(xvl, xvr);
|
||||
|
||||
transmatrix xrm = gpushxto0(xvm);
|
||||
|
||||
transmatrix Res = rgpushxto0(vm) * rspintox(rm*vr);
|
||||
|
||||
if(cgflags & qAFFINE) {
|
||||
ld sca = hdist(vl, vr) / hdist(xvl, xvr);
|
||||
transmatrix Tsca = Id;
|
||||
Tsca[0][0] = Tsca[1][1] = sca;
|
||||
Res = Res * Tsca;
|
||||
}
|
||||
|
||||
if(m) Res = Res * MirrorX;
|
||||
Res = Res * spintox(xrm*xvl) * xrm;
|
||||
|
||||
if(m) swap(vl, vr);
|
||||
|
||||
if(hdist(vl, Res*xvr) + hdist(vr, Res*xvl) > .1) {
|
||||
println(hlog, "s1 = ", kz(spintox(rm*vr)), " s2 = ", kz(rspintox(xrm*xvr)));
|
||||
println(hlog, tie(t, dl), " = ", kz(Res));
|
||||
println(hlog, hdist(vl, Res * xvr), " # ", hdist(vr, Res * xvl));
|
||||
exit(3);
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
struct hrmap_arbi : hrmap {
|
||||
heptagon *origin;
|
||||
heptagon *getOrigin() override { return origin; }
|
||||
@ -309,6 +502,8 @@ struct hrmap_arbi : hrmap {
|
||||
celllister cl(origin->c7, 1000, 200, NULL);
|
||||
ginf[geometry].distlimit[0] = cgi.base_distlimit = cl.dists.back();
|
||||
if(sphere) cgi.base_distlimit = SEE_ALL;
|
||||
|
||||
if(cgflags & qAFFINE) cgi.base_distlimit = 3;
|
||||
}
|
||||
|
||||
~hrmap_arbi() {
|
||||
@ -330,58 +525,13 @@ struct hrmap_arbi : hrmap {
|
||||
void verify() override { }
|
||||
|
||||
transmatrix adj(heptagon *h, int dl) override {
|
||||
auto& c = current;
|
||||
int t = id_of(h);
|
||||
auto& sh = c.shapes[t];
|
||||
|
||||
int dr = gmod(dl+1, sh.size());
|
||||
|
||||
auto& co = sh.connections[dl];
|
||||
int xt = get<0>(co);
|
||||
int xdl = get<1>(co);
|
||||
int m = get<2>(co);
|
||||
|
||||
if(h->c.move(dl)) xdl = h->c.spin(dl);
|
||||
|
||||
auto& xsh = c.shapes[xt];
|
||||
int xdr = gmod(xdl+1, xsh.size());
|
||||
|
||||
hyperpoint vl = sh.vertices[dl];
|
||||
hyperpoint vr = sh.vertices[dr];
|
||||
hyperpoint vm = mid(vl, vr);
|
||||
|
||||
transmatrix rm = gpushxto0(vm);
|
||||
|
||||
hyperpoint xvl = xsh.vertices[xdl];
|
||||
hyperpoint xvr = xsh.vertices[xdr];
|
||||
hyperpoint xvm = mid(xvl, xvr);
|
||||
|
||||
transmatrix xrm = gpushxto0(xvm);
|
||||
|
||||
transmatrix Res = rgpushxto0(vm) * rspintox(rm*vr);
|
||||
if(m) Res = Res * MirrorX;
|
||||
Res = Res * spintox(xrm*xvl) * xrm;
|
||||
|
||||
if(m) swap(vl, vr);
|
||||
|
||||
if(hdist(vl, Res*xvr) + hdist(vr, Res*xvl) > .1) {
|
||||
println(hlog, "s1 = ", kz(spintox(rm*vr)), " s2 = ", kz(rspintox(xrm*xvr)));
|
||||
println(hlog, tie(t, dl), " = ", kz(Res));
|
||||
println(hlog, hdist(vl, Res * xvr), " # ", hdist(vr, Res * xvl));
|
||||
exit(3);
|
||||
}
|
||||
|
||||
return Res;
|
||||
return get_adj(current, id_of(h), dl, h->c.move(dl) ? h->c.spin(dl) : -1);
|
||||
}
|
||||
|
||||
heptagon *create_step(heptagon *h, int d) override {
|
||||
|
||||
int t = id_of(h);
|
||||
|
||||
const auto& p = arbi_matrix[h];
|
||||
|
||||
heptagon *alt = p.first;
|
||||
|
||||
auto& sh = current.shapes[t];
|
||||
|
||||
auto& co = sh.connections[d];
|
||||
@ -391,6 +541,48 @@ struct hrmap_arbi : hrmap {
|
||||
int m = get<2>(co);
|
||||
auto& xsh = current.shapes[xt];
|
||||
|
||||
if(cgflags & qAFFINE) {
|
||||
set<heptagon*> visited;
|
||||
|
||||
vector<pair<heptagon*, transmatrix> > v;
|
||||
|
||||
visited.insert(h);
|
||||
v.emplace_back(h, Id);
|
||||
|
||||
transmatrix goal = adj(h, d);
|
||||
|
||||
for(int i=0; i<200 && i < isize(v); i++) {
|
||||
transmatrix T = v[i].second;
|
||||
heptagon *h2 = v[i].first;
|
||||
if(eqmatrix(T, goal)) {
|
||||
h->c.connect(d, h2, e, m);
|
||||
return h2;
|
||||
}
|
||||
for(int i=0; i<h2->type; i++) {
|
||||
heptagon *h3 = h2->move(i);
|
||||
if(!h3) continue;
|
||||
if(visited.count(h3)) continue;
|
||||
visited.insert(h3);
|
||||
v.emplace_back(h3, T * adj(h2, i));
|
||||
}
|
||||
}
|
||||
|
||||
auto h1 = tailored_alloc<heptagon> (current.shapes[xt].size());
|
||||
h1->distance = h->distance + 1;
|
||||
h1->zebraval = xt;
|
||||
h1->c7 = newCell(h1->type, h1);
|
||||
h1->alt = nullptr;
|
||||
h1->cdata = nullptr;
|
||||
h1->emeraldval = h->emeraldval ^ m;
|
||||
h->c.connect(d, h1, e, m);
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
const auto& p = arbi_matrix[h];
|
||||
|
||||
heptagon *alt = p.first;
|
||||
|
||||
transmatrix T = p.second * adj(h, d);
|
||||
|
||||
if(hyperbolic) {
|
||||
@ -470,6 +662,46 @@ struct hrmap_arbi : hrmap {
|
||||
|
||||
EX hrmap *new_map() { return new hrmap_arbi; }
|
||||
|
||||
void run(string fname) {
|
||||
stop_game();
|
||||
eGeometry g = geometry;
|
||||
arbi_tiling t = current;
|
||||
auto v = variation;
|
||||
set_geometry(gArbitrary);
|
||||
try {
|
||||
load(fname);
|
||||
ginf[gArbitrary].tiling_name = current.name;
|
||||
}
|
||||
catch(hr_polygon_error& poly) {
|
||||
set_geometry(g);
|
||||
set_variation(v);
|
||||
current = t;
|
||||
start_poly_debugger(poly);
|
||||
string help = XLAT("Polygon number %1 did not close correctly. Here is the picture to help you understand the issue.\n\n", its(poly.id));
|
||||
showstartmenu = false;
|
||||
for(auto& p: poly.params)
|
||||
help += lalign(-1, p.first, " = ", p.second, "\n");
|
||||
gotoHelp(help);
|
||||
}
|
||||
catch(hr_parse_exception& ex) {
|
||||
println(hlog, "failed: ", ex.s);
|
||||
set_geometry(g);
|
||||
current = t;
|
||||
start_game();
|
||||
addMessage("failed: " + ex.s);
|
||||
}
|
||||
catch(connection_debug_request& cr) {
|
||||
set_geometry(g);
|
||||
debugged = current;
|
||||
current = t;
|
||||
ensure_geometry(cr.c);
|
||||
debug_polys.clear();
|
||||
debug_polys.emplace_back(Id, cr.id);
|
||||
pushScreen(connection_debugger);
|
||||
}
|
||||
start_game();
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
@ -477,17 +709,8 @@ int readArgs() {
|
||||
if(0) ;
|
||||
else if(argis("-arbi")) {
|
||||
PHASEFROM(2);
|
||||
stop_game();
|
||||
shift();
|
||||
set_geometry(gArbitrary);
|
||||
try {
|
||||
load(args());
|
||||
}
|
||||
catch(hr_parse_exception& ex) {
|
||||
println(hlog, "failed: ", ex.s);
|
||||
exit(3);
|
||||
}
|
||||
ginf[gArbitrary].tiling_name = current.name;
|
||||
run(args());
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
@ -498,7 +721,7 @@ auto hook = addHook(hooks_args, 100, readArgs);
|
||||
|
||||
EX bool in() { return geometry == gArbitrary; }
|
||||
|
||||
EX string tes = "tessellations/marjorie-rice.tes";
|
||||
EX string tes = "tessellations/sample/marjorie-rice.tes";
|
||||
|
||||
EX bool linespattern(cell *c) {
|
||||
return current.shapes[id_of(c->master)].flags & arcm::sfLINE;
|
||||
@ -511,20 +734,10 @@ EX bool pseudohept(cell *c) {
|
||||
EX void choose() {
|
||||
dialog::openFileDialog(tes, XLAT("open a tiling"), ".tes",
|
||||
[] () {
|
||||
stop_game();
|
||||
set_geometry(gArbitrary);
|
||||
try {
|
||||
load(tes);
|
||||
ginf[gArbitrary].tiling_name = current.name;
|
||||
}
|
||||
catch(hr_parse_exception& ex) {
|
||||
println(hlog, "failed: ", ex.s);
|
||||
set_geometry(gNormal);
|
||||
}
|
||||
start_game();
|
||||
run(tes);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
EX }
|
||||
}
|
||||
}
|
||||
|
@ -402,29 +402,27 @@ void archimedean_tiling::compute_geometry() {
|
||||
ld alpha_total = 0;
|
||||
|
||||
for(int i=0; i<N; i++) {
|
||||
ld crmin = 0, crmax = sphere ? M_PI/2 : 10;
|
||||
ld el = 0;
|
||||
for(int q=0; q<100; q++) {
|
||||
circumradius[i] = (crmin + crmax) / 2;
|
||||
hyperpoint p1 = xpush0(circumradius[i]);
|
||||
hyperpoint p2 = spin(2 * M_PI / faces[i]) * p1;
|
||||
inradius[i] = hdist0(mid(p1, p2));
|
||||
el = hdist(p1, p2);
|
||||
if(el > edgelength) crmax = circumradius[i];
|
||||
else crmin = circumradius[i];
|
||||
}
|
||||
if(el < edgelength - 1e-3) alpha_total += 100; // could not make an edge that long
|
||||
hyperpoint h = xpush(edgelength/2) * xspinpush0(M_PI/2, inradius[i]);
|
||||
ld a = atan2(-h[1], h[0]);
|
||||
if(a < 0) a += 2 * M_PI;
|
||||
|
||||
ld gamma = M_PI / faces[i];
|
||||
|
||||
auto& c = circumradius[i];
|
||||
|
||||
c = asin_auto(sin_auto(edgelength/2) / sin(gamma));
|
||||
inradius[i] = hdist0(mid(xpush0(circumradius[i]), xspinpush0(2*gamma, circumradius[i])));
|
||||
|
||||
hyperpoint h = xpush(c) * spin(M_PI - 2*gamma) * xpush0(c);
|
||||
ld a = atan2(h);
|
||||
cyclefix(a, 0);
|
||||
if(a < 0) a = -a;
|
||||
alphas[i] = a;
|
||||
// printf(" H = %s alp = %f\n", display(h), (float) atan2(-h[1], h[0]));
|
||||
alpha_total += alphas[i];
|
||||
}
|
||||
|
||||
// printf("el = %f alpha = %f\n", float(edgelength), float(alpha_total));
|
||||
|
||||
if(sphere ^ (alpha_total > M_PI)) elmin = edgelength;
|
||||
if(debugflags & DF_GEOM)
|
||||
println(hlog, "edgelength = ", edgelength, " angles = ", alphas, " inradius = ", inradius, " circumradius = ", circumradius);
|
||||
|
||||
if(isnan(alpha_total)) elmax = edgelength;
|
||||
else if(sphere ^ (alpha_total > M_PI)) elmin = edgelength;
|
||||
else elmax = edgelength;
|
||||
if(euclid) break;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ void setcameraangle(bool b) { }
|
||||
#if CAP_GL
|
||||
|
||||
#if CAP_VR
|
||||
EX hookset<bool()> *hooks_vr_eye_view, *hooks_vr_eye_projection;
|
||||
EX hookset<bool()> hooks_vr_eye_view, hooks_vr_eye_projection;
|
||||
#endif
|
||||
|
||||
EX void eyewidth_translate(int ed) {
|
||||
@ -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;
|
||||
|
@ -1332,7 +1332,7 @@ EX bool quickfind(eLand l) {
|
||||
#define I2000 (INVLUCK?600:2000)
|
||||
#define I10000 (INVLUCK?3000:10000)
|
||||
|
||||
EX hookset<int(cell*, bool)> *hooks_wallchance;
|
||||
EX hookset<int(cell*, bool)> hooks_wallchance;
|
||||
|
||||
EX int wallchance(cell *c, bool deepOcean) {
|
||||
int i = callhandlers(-1, hooks_wallchance, c, deepOcean);
|
||||
|
@ -9,11 +9,17 @@
|
||||
namespace hr {
|
||||
|
||||
EX namespace bt {
|
||||
#if CAP_BT
|
||||
|
||||
/** note: nihsolv and kd3 tilings return bt::in(). They are defined elsewhere, although some of bt:: functions are used for them */
|
||||
EX bool in() { return cgflags & qBINARY; }
|
||||
EX bool in() {
|
||||
#if CAP_BT
|
||||
return cgflags & qBINARY;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CAP_BT
|
||||
#if HDR
|
||||
enum bindir {
|
||||
bd_right = 0,
|
||||
|
@ -251,7 +251,7 @@ EX void drawArrowTraps() {
|
||||
}
|
||||
}
|
||||
|
||||
auto ccm_blizzard = addHook(clearmemory, 0, [] () {
|
||||
auto ccm_blizzard = addHook(hooks_clearmemory, 0, [] () {
|
||||
arrowtraps.clear();
|
||||
blizzardcells.clear();
|
||||
bcells.clear();
|
||||
|
8
cell.cpp
8
cell.cpp
@ -202,6 +202,9 @@ EX cell *createMov(cell *c, int d) {
|
||||
else if(kite::in())
|
||||
kite::find_cell_connection(c, d);
|
||||
#endif
|
||||
else if(fake::in()) {
|
||||
return FPIU(createMov(c, d));
|
||||
}
|
||||
#if CAP_IRR
|
||||
else if(IRREGULAR) {
|
||||
irr::link_cell(c, d);
|
||||
@ -279,7 +282,7 @@ EX void eumerge(cell* c1, int s1, cell *c2, int s2, bool mirror) {
|
||||
|
||||
// map<pair<eucoord, eucoord>, cell*> euclidean;
|
||||
|
||||
EX hookset<hrmap*()> *hooks_newmap;
|
||||
EX hookset<hrmap*()> hooks_newmap;
|
||||
|
||||
/** create a map in the current geometry */
|
||||
EX void initcells() {
|
||||
@ -287,6 +290,7 @@ EX void initcells() {
|
||||
|
||||
hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap);
|
||||
if(res) currentmap = res;
|
||||
else if(fake::in()) currentmap = fake::new_map();
|
||||
else if(asonov::in()) currentmap = asonov::new_map();
|
||||
else if(nonisotropic || hybri) currentmap = nisot::new_map();
|
||||
#if CAP_CRYSTAL
|
||||
@ -1175,7 +1179,7 @@ EX void clearCellMemory() {
|
||||
gp::gp_adj.clear();
|
||||
}
|
||||
|
||||
auto cellhooks = addHook(clearmemory, 500, clearCellMemory);
|
||||
auto cellhooks = addHook(hooks_clearmemory, 500, clearCellMemory);
|
||||
|
||||
EX bool isNeighbor(cell *c1, cell *c2) {
|
||||
for(int i=0; i<c1->type; i++) if(c1->move(i) == c2) return 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;
|
||||
|
||||
@ -831,7 +841,17 @@ void celldrawer::draw_grid() {
|
||||
if(bt::in() && !sn::in() && !among(t, 5, 6, 8)) continue;
|
||||
if(!bt::in() && c->move(t) < c) continue;
|
||||
dynamicval<color_t> g(poly_outline, gridcolor(c, c->move(t)));
|
||||
queuepoly(V, cgi.shWireframe3D[ofs + t], 0);
|
||||
if(fat_edges && reg3::in()) {
|
||||
for(int i=0; i<S7; i++) if(c < c->move(i)) {
|
||||
for(int j=0; j<cgi.face-1; j++) {
|
||||
gridline(V, cgi.cellshape[i*cgi.face+j], cgi.cellshape[i*cgi.face+j+1], gridcolor(c, c->move(t)), prec);
|
||||
}
|
||||
gridline(V, cgi.cellshape[i*cgi.face], cgi.cellshape[(i+1)*cgi.face-1], gridcolor(c, c->move(t)), prec);
|
||||
}
|
||||
}
|
||||
else {
|
||||
queuepoly(V, cgi.shWireframe3D[ofs + t], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1580,6 +1600,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;
|
||||
@ -1792,7 +1816,7 @@ void celldrawer::bookkeeping() {
|
||||
else {
|
||||
playerV = V * ddspin(c, cwt.spin, 0);
|
||||
if(cwt.mirrored) playerV = playerV * Mirror;
|
||||
if((!confusingGeometry() && !inmirrorcount) || eqmatrix(V, current_display->which_copy, 1e-2))
|
||||
if((!confusingGeometry() && !fake::in() && !inmirrorcount) || eqmatrix(V, current_display->which_copy, 1e-2))
|
||||
current_display->which_copy = V;
|
||||
if(orig) cwtV = playerV;
|
||||
}
|
||||
|
@ -3904,3 +3904,44 @@ 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
|
||||
|
||||
2020-04-22 01:46 Update 11.3k:
|
||||
- Orb of the Sword now destroys shrubs
|
||||
- more accurate mouse when in 2D projections
|
||||
- fixed horocycles in bitruncated {4,x}
|
||||
- fixed Great Walls in {5,3,4}
|
||||
- Hypersian Rug/camera improvements:
|
||||
- - camera rotation now works better in 3D scenes with gravity (including product geometries, 2D-in-3D and gravity lands)
|
||||
- - now displays geometry correctly
|
||||
- - removed outdated documentation
|
||||
- - panning enabled in the menu
|
||||
- - shift+mousewheel for zoom works in rug
|
||||
- - zoom hotkeys now change FOV in perspective modes
|
||||
- - lshift+arrows now rotate the model in rug
|
||||
- - shift+PageUp/Down now zooms
|
||||
- - rug can now be mouse-rotated with Ctrl
|
||||
- - fixed in standard binary tiling and in *.tes tilings
|
||||
|
||||
2020-05-01 18:57 Update 11.3l:
|
||||
- Tessellation files:
|
||||
- - added a debug screen if the polygon does not end correctly
|
||||
- - added a command debug(tilenumber) to debug connections
|
||||
- - if you define constants, they take precedence over predefined constants
|
||||
- - expression parser now accepts whitespace in expressions
|
||||
- fixed a bug when scrolling with arrows then moving in quotient spaces
|
||||
- fixed 'smooth scrolling' option not making scrolling very smooth
|
||||
- an option to fatten regular (isotropic non-Euclidean) honeycomb edges
|
||||
- better centering in screenshot, 'rotate PC' option
|
||||
- in animation, 'monster turns' can be configured (useful for animating CA or butterflies)
|
||||
- fixed Butterflies in non-orientable geometries
|
||||
|
12
classes.cpp
12
classes.cpp
@ -730,7 +730,7 @@ enum eGeometry {
|
||||
gTernary, gNIH, gSolN, gInfOrder, gSpace336, gSpace344, gCrystal344,
|
||||
gArnoldCat, gArbitrary, gInfOrder4, gCrystal534,
|
||||
gSpace535, gSpace536, gSeifertCover, gSeifertWeber, gHomologySphere,
|
||||
gInfOrderMixed, gSpace436,
|
||||
gInfOrderMixed, gSpace436, gFake,
|
||||
gGUARD};
|
||||
|
||||
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSolNIH, gcNil, gcProduct, gcSL2 };
|
||||
@ -798,6 +798,7 @@ static const flagtype qDEPRECATED = Flag(21);
|
||||
static const flagtype qINFMIXED = Flag(22);
|
||||
|
||||
static const flagtype qRAYONLY = Flag(23);
|
||||
static const flagtype qAFFINE = Flag(24);
|
||||
|
||||
// note: dnext assumes that x&7 equals 7
|
||||
static const int SEE_ALL = 50;
|
||||
@ -875,13 +876,13 @@ EX vector<geometryinfo> ginf = {
|
||||
{"{4,3,5}","none", "{4,3,5} hyperbolic honeycomb", "435", 6, 5, 0, giHyperb3, 0x31600, {{7, 2}}, eVariation::pure},
|
||||
{"{3,3,3}","none", "{3,3,3} 5-cell", "333", 4, 3, qsSMALLB, giSphere3, 0x38000, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,3,4}","none", "{3,3,4} 16-cell", "334", 4, 4, qsSMALLB, giSphere3, 0x38200, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,3,4}","elliptic","{3,3,4} 16-cell (elliptic)", "e334", 4, 4, qsSMALLBE, giSphere3, 0x39200, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,3,4}","elliptic","{3,3,4} 16-cell (elliptic space)", "e334", 4, 4, qsSMALLBE, giSphere3, 0x39200, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{4,3,3}","none", "{4,3,3} 8-cell", "433", 6, 4, qsSMALLB, giSphere3, 0x38400, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{4,3,3}","elliptic","{4,3,3} 8-cell (elliptic)", "e433", 6, 4, qsSMALLBE, giSphere3, 0x39400, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{4,3,3}","elliptic","{4,3,3} 8-cell (elliptic space)", "e433", 6, 4, qsSMALLBE, giSphere3, 0x39400, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,4,3}","none", "{3,4,3} 24-cell", "343", 8, 3, qsSMALLB, giSphere3, 0x38600, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,4,3}","elliptic","{3,4,3} 24-cell (elliptic)", "e343", 8, 3, qsSMALLBE, giSphere3, 0x39600, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,4,3}","elliptic","{3,4,3} 24-cell (elliptic space)", "e343", 8, 3, qsSMALLBE, giSphere3, 0x39600, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,3,5}","none", "{3,3,5} 600-cell", "335", 4, 3, qsSMALLB, giSphere3, 0x41000, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,3,5}","elliptic","{3,3,5} 600-cell (elliptic)", "e335", 4, 3, qsSMALLBE, giSphere3, 0x41200, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{3,3,5}","elliptic","{3,3,5} 600-cell (elliptic space)", "e335", 4, 3, qsSMALLBE, giSphere3, 0x41200, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"bin{3,6}", "none", "{3,6} on horospheres", "bin36", 8, 3, qBINARY, giHyperb3, 0x40000, {{7, 3}}, eVariation::pure},
|
||||
{"bin-rect", "none", "rectangles on horospheres", "bin44/2", 7, 3, qBINARY, giHyperb3, 0x40200, {{7, 3}}, eVariation::pure},
|
||||
{"bin{6,3}", "none", "{6,3} on horospheres", "bin63", 14, 3, qBINARY, giHyperb3, 0x40400, {{7, 3}}, eVariation::pure},
|
||||
@ -912,6 +913,7 @@ EX vector<geometryinfo> ginf = {
|
||||
{"{5,3,3}","SW", "Poincaré homology sphere", "533s", 12, 3, qsSINGLE, giSphere3, 0x31400, {{7, 2}}, eVariation::pure},
|
||||
{"{?,oo}", "none", "{3/4,∞} (infinite triangles and squares)", "ooxm", 3, OINF, qIDEAL | qINFMIXED, giHyperb2, 0x49400, {{6, 6}}, eVariation::pure},
|
||||
{"{4,3,6}","none", "{4,3,6} hyperbolic honeycomb", "436", 6, 6, qIDEAL, giHyperb3, 0x31400, {{7, 2}}, eVariation::pure},
|
||||
{"?", "none", "fake", "", 0, 0, qRAYONLY, giHyperb3, 0x31400, {{7, 2}}, eVariation::pure}
|
||||
};
|
||||
// bits: 9, 10, 15, 16, (reserved for later) 17, 18
|
||||
|
||||
|
@ -347,7 +347,7 @@ int arg::readCommon() {
|
||||
|
||||
EX purehookset hooks_config;
|
||||
|
||||
EX hookset<int()> *hooks_args;
|
||||
EX hookset<int()> hooks_args;
|
||||
|
||||
namespace arg {
|
||||
|
||||
@ -357,12 +357,13 @@ namespace arg {
|
||||
curphase = phase;
|
||||
callhooks(hooks_config);
|
||||
while(pos < isize(argument)) {
|
||||
for(auto& h: *hooks_args) {
|
||||
int r = h.second(); if(r == 2) return; if(r == 0) { lshift(); goto cont; }
|
||||
int r = callhandlers(1, hooks_args);
|
||||
switch (r) {
|
||||
case 0: lshift(); break;
|
||||
case 1: printf("Unknown option: %s\n", argcs()); exit(3); break;
|
||||
case 2: return;
|
||||
default: assert(false);
|
||||
}
|
||||
printf("Unknown option: %s\n", argcs());
|
||||
exit(3);
|
||||
cont: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
35
complex.cpp
35
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,13 +3429,19 @@ 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 }
|
||||
|
||||
auto ccm = addHook(clearmemory, 0, [] () {
|
||||
auto ccm = addHook(hooks_clearmemory, 0, [] () {
|
||||
heat::offscreen_heat.clear();
|
||||
heat::offscreen_fire.clear();
|
||||
princess::clear();
|
||||
@ -3825,12 +3848,12 @@ EX namespace halloween {
|
||||
}
|
||||
int id = hrand(100);
|
||||
if(items[itTreat] == 1) {
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
addMessage(XLAT("Hint: use arrow keys to scroll."));
|
||||
#endif
|
||||
}
|
||||
else if(items[itTreat] == 2) {
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
addMessage(XLAT("Hint: press 1 2 3 4 to change the projection."));
|
||||
#endif
|
||||
}
|
||||
|
16
complex2.cpp
16
complex2.cpp
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "hyper.h"
|
||||
#ifdef CAP_COMPLEX2
|
||||
#if CAP_COMPLEX2
|
||||
|
||||
namespace hr {
|
||||
|
||||
@ -198,7 +198,7 @@ EX namespace brownian {
|
||||
vector<cell*> to_remove;
|
||||
for(auto p: futures) if(is_cell_removed(p.first)) to_remove.push_back(p.first);
|
||||
for(auto r: to_remove) futures.erase(r);
|
||||
}) + addHook(clearmemory, 0, [] () { futures.clear(); })
|
||||
}) + addHook(hooks_clearmemory, 0, [] () { futures.clear(); })
|
||||
+ addHook(hooks_gamedata, 0, [] (gamedata* gd) { gd->store(futures); });
|
||||
|
||||
EX }
|
||||
@ -554,15 +554,19 @@ EX bool mightBeMine(cell *c) {
|
||||
return c->wall == waMineUnknown || c->wall == waMineMine;
|
||||
}
|
||||
|
||||
EX hookset<bool(cell*)> *hooks_mark;
|
||||
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;
|
||||
|
249
config.cpp
249
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
|
||||
@ -786,7 +800,7 @@ EX void saveConfig() {
|
||||
fprintf(f, "%s=%s\n", s->name.c_str(), s->save().c_str());
|
||||
|
||||
fclose(f);
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
addMessage(s0 + "Configuration saved to: " + conffile);
|
||||
#else
|
||||
addMessage(s0 + "Configuration saved");
|
||||
@ -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"), "");
|
||||
@ -1254,36 +1269,34 @@ EX void configureOther() {
|
||||
|
||||
// dialog::addBoolItem_action(XLAT("forget faraway cells"), memory_saving_mode, 'y');
|
||||
|
||||
#if CAP_AUDIO
|
||||
if(CAP_AUDIO) {
|
||||
dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(musicvolume, 0, 128, 10, 60, XLAT("background music volume"), "");
|
||||
dialog::reaction = [] () {
|
||||
#if CAP_SDLAUDIO
|
||||
Mix_VolumeMusic(musicvolume);
|
||||
#endif
|
||||
#if ISANDROID
|
||||
settingsChanged = true;
|
||||
#endif
|
||||
};
|
||||
dialog::bound_low(0);
|
||||
dialog::bound_up(MIX_MAX_VOLUME);
|
||||
});
|
||||
#if CAP_AUDIO
|
||||
dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(musicvolume, 0, 128, 10, 60, XLAT("background music volume"), "");
|
||||
dialog::reaction = [] () {
|
||||
#if CAP_SDLAUDIO
|
||||
Mix_VolumeMusic(musicvolume);
|
||||
#endif
|
||||
#if ISANDROID
|
||||
settingsChanged = true;
|
||||
#endif
|
||||
};
|
||||
dialog::bound_low(0);
|
||||
dialog::bound_up(MIX_MAX_VOLUME);
|
||||
});
|
||||
|
||||
dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(effvolume, 0, 128, 10, 60, XLAT("sound effects volume"), "");
|
||||
dialog::reaction = [] () {
|
||||
#if ISANDROID
|
||||
settingsChanged = true;
|
||||
#endif
|
||||
};
|
||||
dialog::bound_low(0);
|
||||
dialog::bound_up(MIX_MAX_VOLUME);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(effvolume, 0, 128, 10, 60, XLAT("sound effects volume"), "");
|
||||
dialog::reaction = [] () {
|
||||
#if ISANDROID
|
||||
settingsChanged = true;
|
||||
#endif
|
||||
};
|
||||
dialog::bound_low(0);
|
||||
dialog::bound_up(MIX_MAX_VOLUME);
|
||||
});
|
||||
#endif
|
||||
|
||||
menuitem_sightrange('r');
|
||||
|
||||
@ -1302,12 +1315,10 @@ EX void configureInterface() {
|
||||
gamescreen(3);
|
||||
dialog::init(XLAT("interface"));
|
||||
|
||||
#if CAP_TRANS
|
||||
if(CAP_TRANS) {
|
||||
dialog::addSelItem(XLAT("language"), XLAT("EN"), 'l');
|
||||
dialog::add_action_push(selectLanguageScreen);
|
||||
}
|
||||
#endif
|
||||
#if CAP_TRANS
|
||||
dialog::addSelItem(XLAT("language"), XLAT("EN"), 'l');
|
||||
dialog::add_action_push(selectLanguageScreen);
|
||||
#endif
|
||||
|
||||
dialog::addSelItem(XLAT("player character"), numplayers() > 1 ? "" : csname(vid.cs), 'g');
|
||||
dialog::add_action_push(showCustomizeChar);
|
||||
@ -1431,7 +1442,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 +1460,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 +1575,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 -- "
|
||||
@ -1627,12 +1638,12 @@ EX void show3D() {
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("3D configuration"));
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
#if MAXMDIM >= 4
|
||||
if(WDIM == 2) {
|
||||
dialog::addBoolItem(XLAT("use the full 3D models"), vid.always3, 'U');
|
||||
dialog::add_action(geom3::switch_always3);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
if(vid.use_smart_range == 0 && GDIM == 2) {
|
||||
dialog::addSelItem(XLAT("High detail range"), fts(vid.highdetail), 'n');
|
||||
dialog::addSelItem(XLAT("Mid detail range"), fts(vid.middetail), 'm');
|
||||
@ -1648,9 +1659,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 +1687,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,16 +1741,16 @@ 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);
|
||||
}
|
||||
|
||||
#if MAXMDIM >=4
|
||||
#if MAXMDIM >=4
|
||||
if(WDIM == 2) {
|
||||
dialog::addBoolItem(XLAT("configure FPP automatically"), GDIM == 3, 'F');
|
||||
dialog::add_action(geom3::switch_fpp);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(0);
|
||||
#if CAP_RUG
|
||||
@ -1902,7 +1913,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 +1970,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);
|
||||
@ -2301,11 +2308,9 @@ EX void showSettings() {
|
||||
dialog::addItem(XLAT("colors & aura"), 'c');
|
||||
dialog::add_action_push(show_color_dialog);
|
||||
|
||||
#if CAP_SHMUP
|
||||
if(CAP_SHMUP && !ISMOBILE) {
|
||||
dialog::addSelItem(XLAT("keyboard & joysticks"), "", 'k');
|
||||
dialog::add_action(multi::configure);
|
||||
}
|
||||
#if CAP_SHMUP && !ISMOBILE
|
||||
dialog::addSelItem(XLAT("keyboard & joysticks"), "", 'k');
|
||||
dialog::add_action(multi::configure);
|
||||
#endif
|
||||
|
||||
dialog::addSelItem(XLAT("mouse & touchscreen"), "", 'm');
|
||||
@ -2411,22 +2416,22 @@ EX int read_config_args() {
|
||||
PHASEFROM(2);
|
||||
nomenukey = true;
|
||||
}
|
||||
#if MAXMDIM >= 4
|
||||
#if MAXMDIM >= 4
|
||||
else if(argis("-switch-fpp")) {
|
||||
PHASEFROM(2);
|
||||
geom3::switch_fpp();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
else if(argis("-switch-tpp")) {
|
||||
PHASEFROM(2);
|
||||
geom3::switch_tpp();
|
||||
}
|
||||
#if MAXMDIM >= 4
|
||||
#if MAXMDIM >= 4
|
||||
else if(argis("-switch-3d")) {
|
||||
PHASEFROM(2);
|
||||
geom3::switch_always3();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
else if(argis("-nohelp")) {
|
||||
PHASEFROM(2);
|
||||
nohelp = true;
|
||||
@ -2465,7 +2470,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 +2478,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 +2539,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 +2587,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 +2612,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 +2639,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 +2651,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
|
||||
};
|
||||
|
10
content.cpp
10
content.cpp
@ -322,7 +322,7 @@ MONSTER( 'Y', 0xFF8000, "Yendorian Researcher", moResearcher, ZERO, RESERVED, mo
|
||||
"They have no special features, other than wearing a strange hat."
|
||||
)
|
||||
MONSTER( 'K', 0xA8A8A8, "Sparrowhawk", moSparrowhawk, CF_FACE_SIDE | CF_BIRD | CF_FLYING | CF_IGNORE_PLATE, RESERVED, moEagle,
|
||||
"A bird who hunts in the treetops of Yendorian Forest."
|
||||
"A bird who hunts in the treetops of the Yendorian Forest."
|
||||
)
|
||||
MONSTER( 'K', 0xD0A0A0, "Kraken", moKrakenH, ZERO | CF_NOGHOST | CF_NOBLOW | CF_MULTITILE | CF_KRAKEN | CF_FACING, RESERVED, moNone, krakendesc)
|
||||
MONSTER( 'K', 0xC07070, "Kraken Tentacle", moKrakenT, ZERO | CF_NOGHOST | CF_NOBLOW | CF_PART | CF_MULTITILE | CF_KRAKEN, RESERVED, moNone, krakendesc)
|
||||
@ -398,7 +398,7 @@ MONSTER( 'W', 0x202020, "Hunting Dog (regrouping)", moHunterChanging, ZERO, RESE
|
||||
"When your plan has clearly failed, it is better to abandon it and go to a safe place, to have a chance of succeeding next time. This dog clearly knows this.")
|
||||
MONSTER( 'B', 0xC00000, "North Pole", moNorthPole, ZERO | CF_MAGNETIC | CF_FACING, RESERVED, moYeti, NODESCYET)
|
||||
MONSTER( 'B', 0x0000C0, "South Pole", moSouthPole, ZERO | CF_MAGNETIC | CF_FACING, RESERVED, moYeti, NODESCYET)
|
||||
MONSTER( 'P', 0xC03000, "Red Raider", moPair, CF_FACE_UP | CF_RAIDER | CF_FACING, RESERVED, moYeti, "Red Raiders travel in pairs. They have promised to always watch another one's back. They are able to destroy walls on their way.")
|
||||
MONSTER( 'P', 0xC03000, "Red Raider", moPair, CF_FACE_UP | CF_RAIDER | CF_FACING, RESERVED, moYeti, "Red Raiders travel in pairs. They have promised to always watch each other's backs. They are able to destroy walls on their way.")
|
||||
MONSTER( 'H', 0xC0C0C0, "Gray Raider", moHexDemon, CF_FACE_UP | CF_RAIDER, RESERVED, moHexDemon, "Gray Raiders never step on gray cells.")
|
||||
MONSTER( 'A', 0x80B080, "Green Raider", moAltDemon, CF_FACE_UP | CF_RAIDER, RESERVED, moAltDemon, "Green Raiders never step from one green cell to another.")
|
||||
MONSTER( 'M', 0x904000, "Brown Raider", moMonk, CF_FACE_UP | CF_RAIDER, RESERVED, moMonk, "Brown Raiders never move adjacent to an item.")
|
||||
@ -665,7 +665,7 @@ ITEM( '%', 0x606060, "Black Lotus", itLotus, IC_TREASURE, ZERO, RESERVED, osNone
|
||||
"without preparation.\n"
|
||||
)
|
||||
ITEM( 'o', 0x505050, "Orb of Undeath", itOrbUndeath, IC_ORB, ZERO | IF_EMPATHY | IF_SHMUPLIFE | IF_REVIVAL, RESERVED, osFriend,
|
||||
"Monsters slain by you in melee are turned into friendly ghosts, "
|
||||
"Monsters slain by you in melee are turned into friendly ghosts. "
|
||||
"Does not affect plants and friends."
|
||||
)
|
||||
ITEM( '*', 0x8080FF, "White Dove Feather", itWindstone, IC_TREASURE, ZERO, RESERVED, osNone,
|
||||
@ -733,7 +733,7 @@ ITEM( 'o', 0x900000, "Orb of Domination", itOrbDomination, IC_ORB, ZERO | IF_RAN
|
||||
"Simply move onto such a creature to ride them; while riding, you are protected from dangerous terrains "
|
||||
"and partially from attacks (they cause you to lose half of your Domination power), "
|
||||
"but you cannot collect items.\n\n"
|
||||
/*When only one charge is left, "
|
||||
/*"When only one charge is left, "
|
||||
"you have to dismount this turn -- be very careful to make this possible, "
|
||||
"as your mount could attack you immediately!\n\n" */
|
||||
"While riding, "
|
||||
@ -849,7 +849,7 @@ ITEM( '*', 0xFFA860, "Tiger's Eye", itBrownian, IC_TREASURE, ZERO, RESERVED, osN
|
||||
ITEM( '$', 0xF0C0C0, "Meteorite", itWest, IC_TREASURE, ZERO, RESERVED, osNone,
|
||||
"These rocks falling from the sky have been captured to fall forever in the artificial gravity. Meteorite iron is believed to be a valuable material for magical weapons.")
|
||||
ITEM( '*', 0x30FF30, "Torbernite", itVarTreasure, IC_TREASURE, ZERO, RESERVED, osNone,
|
||||
"Crystals emiting magical radiation.")
|
||||
"Crystals emitting magical radiation.")
|
||||
ITEM( 'o', 0x703800, "Orb of Intensity", itOrbIntensity, IC_ORB, ZERO, RESERVED, osNone,
|
||||
"When you have this, initial and maximal charge amounts of all Orbs are increased by 20%."
|
||||
)
|
||||
|
342
control.cpp
342
control.cpp
@ -14,8 +14,11 @@ EX bool outoffocus = false;
|
||||
EX int mousex, mousey;
|
||||
EX hyperpoint mouseh, mouseoh;
|
||||
|
||||
EX bool leftclick, rightclick, targetclick, hiliteclick, anyshiftclick, wheelclick;
|
||||
EX bool forcetarget, lshiftclick, lctrlclick, numlock_on;
|
||||
EX bool pandora_leftclick, pandora_rightclick;
|
||||
|
||||
EX bool lshiftclick, rshiftclick, lctrlclick, rctrlclick, anyshiftclick, anyctrlclick, wheelclick;
|
||||
|
||||
EX bool targetclick, hiliteclick, forcetarget, numlock_on;
|
||||
EX bool gtouched;
|
||||
|
||||
EX bool holdmouse;
|
||||
@ -76,7 +79,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 +90,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);
|
||||
}
|
||||
@ -301,6 +304,80 @@ transmatrix zforward_push(ld z) {
|
||||
return T;
|
||||
}
|
||||
|
||||
EX void zoom_or_fov(ld t) {
|
||||
if(in_perspective()) {
|
||||
auto tanfov = tan(vid.fov * degree / 2);
|
||||
tanfov *= t;
|
||||
vid.fov = atan(tanfov) * 2 / degree;
|
||||
}
|
||||
else
|
||||
vpconf.scale *= t;
|
||||
}
|
||||
|
||||
EX void full_forward_camera(ld t) {
|
||||
if(anyshiftclick)
|
||||
zoom_or_fov(exp(-t/10.));
|
||||
else if(GDIM == 3) {
|
||||
shift_view(ctangent(2, t));
|
||||
didsomething = true;
|
||||
playermoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
EX void full_rotate_camera(int dir, ld val) {
|
||||
if(rug::rug_control() && lshiftclick) {
|
||||
hyperpoint h;
|
||||
if(nonisotropic) {
|
||||
transmatrix T2 = eupush( tC0(inverse(View)) );
|
||||
transmatrix nlp = View * T2;
|
||||
auto rV = inverse(nlp) * View;
|
||||
h = nlp * inverse_exp(tC0(rV));
|
||||
}
|
||||
else h = inverse_exp(tC0(View));
|
||||
shift_view(-h);
|
||||
rotate_view(cspin(dir, 2, val));
|
||||
shift_view(h);
|
||||
}
|
||||
else if(history::on)
|
||||
history::lvspeed += (dir?1:-1) * val / 2;
|
||||
else if(GDIM == 3 && rshiftclick)
|
||||
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) {
|
||||
if(keep_vertical()) {
|
||||
hyperpoint vv = vertical_vector();
|
||||
ld alpha = -atan2(vv[2], vv[1]);
|
||||
rotate_view(cspin(2, 1, alpha));
|
||||
ld max_angle = quarter_circle - 1e-4;
|
||||
if(dir == 1 && alpha + val > max_angle)
|
||||
val = max_angle - alpha;
|
||||
if(dir == 1 && alpha + val < -max_angle)
|
||||
val = -max_angle - alpha;
|
||||
rotate_view(cspin(dir, 2, val));
|
||||
rotate_view(cspin(1, 2, alpha));
|
||||
}
|
||||
else
|
||||
rotate_view(cspin(dir, 2, val));
|
||||
if(!rug::rug_control()) didsomething = true;
|
||||
}
|
||||
else
|
||||
shift_view(ctangent(dir, val)), playermoved = false, didsomething = true;
|
||||
}
|
||||
|
||||
EX void full_rotate_view(ld h, ld v) {
|
||||
if(history::on && !rug::rug_control())
|
||||
models::rotation += h;
|
||||
else {
|
||||
rotate_view(spin(v));
|
||||
didsomething = true;
|
||||
if(isGravityLand(cwt.at->land) && !rug::rug_control())
|
||||
playermoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
EX void handlePanning(int sym, int uni) {
|
||||
if(mousepan && dual::split([=] { handlePanning(sym, uni); })) return;
|
||||
if(GDIM == 3) {
|
||||
@ -308,71 +385,30 @@ 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) {
|
||||
shift_view(ztangent(-0.2*shiftmul)), didsomething = true, playermoved = false;
|
||||
}
|
||||
if(sym == SDLK_HOME && GDIM == 3) {
|
||||
shift_view(ztangent(+0.2*shiftmul)), didsomething = true, playermoved = false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
if(!smooth_scrolling) {
|
||||
if(sym == SDLK_END) full_forward_camera(-0.2*shiftmul);
|
||||
if(sym == SDLK_HOME) full_forward_camera(0.2*shiftmul);
|
||||
if(sym == SDLK_RIGHT) full_rotate_camera(0, -0.2*shiftmul);
|
||||
if(sym == SDLK_LEFT) full_rotate_camera(0, 0.2*shiftmul);
|
||||
if(sym == SDLK_UP) full_rotate_camera(1, 0.2*shiftmul);
|
||||
if(sym == SDLK_DOWN) full_rotate_camera(1, -0.2*shiftmul);
|
||||
}
|
||||
#endif
|
||||
if(sym == SDLK_PAGEUP) {
|
||||
if(history::on)
|
||||
models::rotation++;
|
||||
else
|
||||
rotate_view(spin(M_PI/cgi.S21/2*shiftmul)), didsomething = true;
|
||||
if(!smooth_scrolling) {
|
||||
if(sym == SDLK_PAGEUP) full_rotate_view(1, M_PI/cgi.S21/2*shiftmul);
|
||||
if(sym == SDLK_PAGEDOWN) full_rotate_view(-1, -M_PI/cgi.S21/2*shiftmul);
|
||||
if(sym == SDLK_PAGEUP || sym == SDLK_PAGEDOWN)
|
||||
if(isGravityLand(cwt.at->land) && !rug::rug_control()) playermoved = false;
|
||||
}
|
||||
if(sym == SDLK_PAGEDOWN) {
|
||||
if(history::on)
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
@ -433,8 +469,8 @@ EX void handleKeyNormal(int sym, int uni) {
|
||||
if(DEFAULTCONTROL) {
|
||||
if(sym == SDLK_RIGHT) movepckeydir(0);
|
||||
if(sym == SDLK_LEFT) movepckeydir(4);
|
||||
if(sym == SDLK_DOWN) movepckeydir(2 + (leftclick?1:0) - (rightclick?1:0));
|
||||
if(sym == SDLK_UP) movepckeydir(6 - (leftclick?1:0) + (rightclick?1:0));
|
||||
if(sym == SDLK_DOWN) movepckeydir(2 + (pandora_leftclick?1:0) - (pandora_rightclick?1:0));
|
||||
if(sym == SDLK_UP) movepckeydir(6 - (pandora_leftclick?1:0) + (pandora_rightclick?1:0));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -493,8 +529,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_F3 || sym == ' ') && DEFAULTNOR(sym)) {
|
||||
if(rug::rug_control())
|
||||
rug::reset_view();
|
||||
else
|
||||
fullcenter();
|
||||
}
|
||||
|
||||
if(sym == 'v' && DEFAULTNOR(sym))
|
||||
pushScreen(showMainMenu);
|
||||
@ -611,7 +651,7 @@ EX void mainloopiter() {
|
||||
if(cwt.mirrored) playerV = playerV * Mirror;
|
||||
}
|
||||
|
||||
mousepan = (cmode & (sm::NORMAL | sm::DRAW | sm::MAP)) && GDIM == 3 && mouseaim_sensitivity;
|
||||
mousepan = (cmode & (sm::NORMAL | sm::DRAW | sm::MAP)) && (GDIM == 3 || (rug::rugged && lctrlclick)) && mouseaim_sensitivity;
|
||||
if(mousepan != oldmousepan) {
|
||||
oldmousepan = mousepan;
|
||||
#if CAP_MOUSEGRAB
|
||||
@ -657,13 +697,20 @@ EX void mainloopiter() {
|
||||
}
|
||||
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
rightclick = keystate[SDLK_RCTRL];
|
||||
leftclick = keystate[SDLK_RSHIFT];
|
||||
lctrlclick = keystate[SDLK_LCTRL];
|
||||
|
||||
pandora_rightclick = keystate[SDLK_RCTRL];
|
||||
pandora_leftclick = keystate[SDLK_RSHIFT];
|
||||
|
||||
lshiftclick = keystate[SDLK_LSHIFT];
|
||||
forcetarget = (keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT]);
|
||||
rshiftclick = keystate[SDLK_RSHIFT];
|
||||
anyshiftclick = lshiftclick | rshiftclick;
|
||||
|
||||
lctrlclick = keystate[SDLK_LCTRL];
|
||||
rctrlclick = keystate[SDLK_RCTRL];
|
||||
anyctrlclick = lctrlclick | rctrlclick;
|
||||
|
||||
forcetarget = anyshiftclick;
|
||||
hiliteclick = keystate[SDLK_LALT] | keystate[SDLK_RALT];
|
||||
anyshiftclick = keystate[SDLK_LSHIFT] | keystate[SDLK_RSHIFT];
|
||||
wheelclick = false;
|
||||
|
||||
getcshift = 1;
|
||||
@ -674,11 +721,14 @@ EX void mainloopiter() {
|
||||
didsomething = false;
|
||||
|
||||
if(vid.shifttarget&1) {
|
||||
leftclick = false;
|
||||
#if ISPANDORA
|
||||
targetclick = pandora_leftclick | pandora_rightclick;
|
||||
pandora_leftclick = pandora_rightclick = 0;
|
||||
#else
|
||||
targetclick = keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT];
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
leftclick = keystate[SDLK_RSHIFT];
|
||||
targetclick = true;
|
||||
}
|
||||
|
||||
@ -689,42 +739,31 @@ EX void mainloopiter() {
|
||||
SDL_Event ev;
|
||||
DEBB(DF_GRAPH, ("polling for events\n"));
|
||||
|
||||
if(GDIM == 3 && !shmup::on && !rug::rugged) {
|
||||
if((GDIM == 3 && !shmup::on) || (lctrlclick && rug::rugged)) {
|
||||
#if CAP_MOUSEGRAB
|
||||
rotate_view(cspin(0, 2, -mouseaim_x) * cspin(1, 2, -mouseaim_y));
|
||||
rug::using_rugview urv;
|
||||
dynamicval<bool> ds(didsomething, didsomething);
|
||||
full_rotate_camera(0, -mouseaim_x);
|
||||
full_rotate_camera(1, -mouseaim_y);
|
||||
mouseaim_x = mouseaim_y = 0;
|
||||
#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;
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
if(keystate[SDLK_END] && GDIM == 3 && DEFAULTNOR(SDLK_END))
|
||||
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;
|
||||
if(keystate[SDLK_PAGEUP] && DEFAULTNOR(SDLK_PAGEUP)) {
|
||||
if(history::on)
|
||||
models::rotation+=t;
|
||||
else
|
||||
rotate_view(spin(t)), didsomething = true;
|
||||
}
|
||||
if(keystate[SDLK_PAGEDOWN] && DEFAULTNOR(SDLK_PAGEDOWN)) {
|
||||
if(history::on)
|
||||
models::rotation-=t;
|
||||
else
|
||||
rotate_view(spin(-t)), didsomething = true;
|
||||
}
|
||||
|
||||
if(keystate[SDLK_END] && GDIM == 3 && DEFAULTNOR(SDLK_END)) full_forward_camera(-t);
|
||||
if(keystate[SDLK_HOME] && GDIM == 3 && DEFAULTNOR(SDLK_HOME)) full_forward_camera(t);
|
||||
if(keystate[SDLK_RIGHT] && DEFAULTNOR(SDLK_RIGHT)) full_rotate_camera(0, -t);
|
||||
if(keystate[SDLK_LEFT] && DEFAULTNOR(SDLK_LEFT)) full_rotate_camera(0, t);
|
||||
if(keystate[SDLK_UP] && DEFAULTNOR(SDLK_UP)) full_rotate_camera(1, t);
|
||||
if(keystate[SDLK_DOWN] && DEFAULTNOR(SDLK_DOWN)) full_rotate_camera(1, -t);
|
||||
if(keystate[SDLK_PAGEUP] && DEFAULTNOR(SDLK_PAGEUP)) full_rotate_view(t * 180 / M_PI, t);
|
||||
if(keystate[SDLK_PAGEDOWN] && DEFAULTNOR(SDLK_PAGEDOWN)) full_rotate_view(-t * 180 / M_PI, t);
|
||||
}
|
||||
|
||||
achievement_pump();
|
||||
@ -737,8 +776,6 @@ EX void mainloopiter() {
|
||||
|
||||
EX void handle_event(SDL_Event& ev) {
|
||||
bool normal = cmode & sm::NORMAL;
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
|
||||
DEBB(DF_GRAPH, ("got event type #%d\n", ev.type));
|
||||
int sym = 0;
|
||||
int uni = 0;
|
||||
@ -833,9 +870,6 @@ EX void handle_event(SDL_Event& ev) {
|
||||
|
||||
bool rollchange = (cmode & sm::OVERVIEW) && getcstat >= 2000 && cheater;
|
||||
|
||||
bool anyctrl = keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL];
|
||||
bool anyshift = keystate[SDLK_LSHIFT] || keystate[SDLK_RSHIFT];
|
||||
|
||||
if(ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP) {
|
||||
mousepressed = ev.type == SDL_MOUSEBUTTONDOWN;
|
||||
if(mousepressed) flashMessages();
|
||||
@ -858,49 +892,47 @@ EX void handle_event(SDL_Event& ev) {
|
||||
if(was_holdmouse && ev.type == SDL_MOUSEBUTTONUP)
|
||||
sym = uni = PSEUDOKEY_RELEASE;
|
||||
|
||||
/* simulate RMB and MMB for Mac users etc. */
|
||||
if(ev.button.button == SDL_BUTTON_LEFT) {
|
||||
if(ISPANDORA ? pandora_rightclick : lctrlclick)
|
||||
ev.button.button = SDL_BUTTON_MIDDLE;
|
||||
else if((ISPANDORA ? pandora_leftclick : lshiftclick) && !(vid.shifttarget&1))
|
||||
ev.button.button = SDL_BUTTON_RIGHT;
|
||||
}
|
||||
|
||||
if(!act) ;
|
||||
|
||||
else if(ev.button.button==SDL_BUTTON_RIGHT || leftclick)
|
||||
else if(ev.button.button==SDL_BUTTON_RIGHT)
|
||||
sym = SDLK_F1;
|
||||
else if(ev.button.button==SDL_BUTTON_MIDDLE || rightclick) {
|
||||
else if(ev.button.button==SDL_BUTTON_MIDDLE)
|
||||
sym = 1, didsomething = true;
|
||||
if(anyshift)
|
||||
vid.xposition = vid.yposition = 0;
|
||||
}
|
||||
else if(ev.button.button == SDL_BUTTON_LEFT) {
|
||||
sym = getcstat, uni = getcstat, shiftmul = getcshift;
|
||||
}
|
||||
|
||||
else if(ev.button.button==SDL_BUTTON_WHEELDOWN) {
|
||||
if(anyctrl && anyshift && !rug::rugged && GDIM == 2) {
|
||||
mapeditor::scaleall(1/1.2);
|
||||
vid.alpha /= 1.2;
|
||||
else if(ev.button.button==SDL_BUTTON_WHEELDOWN || ev.button.button == SDL_BUTTON_WHEELUP) {
|
||||
ld dir = ev.button.button == SDL_BUTTON_WHEELUP ? 0.25 : -0.25;
|
||||
if(lshiftclick && rshiftclick && !rug::rugged && GDIM == 2) {
|
||||
mapeditor::scaleall(pow(2, dir), lctrlclick);
|
||||
pconf.alpha *= pow(2, dir);
|
||||
}
|
||||
else if(lshiftclick && GDIM == 2)
|
||||
mapeditor::scaleall(pow(2, dir), lctrlclick);
|
||||
else if(rshiftclick && !rug::rugged && GDIM == 2)
|
||||
pconf.alpha -= dir;
|
||||
else if(lctrlclick) {
|
||||
if(dir>0) {
|
||||
pconf.xposition += (.0 + mousex - current_display->xcenter) / vpconf.scale / current_display->scrsize;
|
||||
pconf.yposition += (.0 + mousey - current_display->ycenter) / vpconf.scale / current_display->scrsize;
|
||||
}
|
||||
else
|
||||
pconf.xposition = pconf.yposition = 0;
|
||||
}
|
||||
else if(anyctrl && !rug::rugged && GDIM == 2)
|
||||
mapeditor::scaleall(pow(2, -.25));
|
||||
else if(anyshift && !rug::rugged && GDIM == 2)
|
||||
vid.alpha -= 0.25;
|
||||
else if(rollchange) {
|
||||
sym = getcstat, uni = getcstat, shiftmul = getcshift, wheelclick = true;
|
||||
sym = getcstat, uni = getcstat, shiftmul = -dir*4*getcshift, wheelclick = true;
|
||||
}
|
||||
else {
|
||||
sym = uni = PSEUDOKEY_WHEELDOWN;
|
||||
}
|
||||
}
|
||||
if(ev.button.button==SDL_BUTTON_WHEELUP) {
|
||||
if(anyctrl && anyshift && !rug::rugged && GDIM == 2) {
|
||||
mapeditor::scaleall(1.2);
|
||||
vid.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;
|
||||
else if(rollchange) {
|
||||
sym = getcstat, uni = getcstat, shiftmul = -getcshift, wheelclick = true;
|
||||
}
|
||||
else {
|
||||
sym = uni = PSEUDOKEY_WHEELUP;
|
||||
sym = uni = dir > 0 ? PSEUDOKEY_WHEELUP : PSEUDOKEY_WHEELDOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -926,11 +958,11 @@ EX void handle_event(SDL_Event& ev) {
|
||||
|
||||
if(holdmouse && getcstat == '-') sym = uni = getcstat, fix_mouseh();
|
||||
|
||||
if((rightclick || (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MMASK)) && !mouseout2()) {
|
||||
if(((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;
|
||||
if(lctrlclick) {
|
||||
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);
|
||||
@ -959,17 +991,17 @@ EX void handle_event(SDL_Event& ev) {
|
||||
else quitmainloop = true;
|
||||
}
|
||||
|
||||
if(sym == SDLK_F4 && anyshift) {
|
||||
if(sym == SDLK_F4 && anyshiftclick) {
|
||||
nomap = !nomap;
|
||||
sym = 0;
|
||||
}
|
||||
|
||||
if(sym == SDLK_F2 && anyshift) {
|
||||
if(sym == SDLK_F2 && anyshiftclick) {
|
||||
nohud = !nohud;
|
||||
sym = 0;
|
||||
}
|
||||
|
||||
if(sym == SDLK_F3 && anyshift) {
|
||||
if(sym == SDLK_F3 && anyshiftclick) {
|
||||
nofps = !nofps;
|
||||
sym = 0;
|
||||
}
|
||||
@ -989,7 +1021,7 @@ EX void mainloop() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
EX void displayabutton(int px, int py, string s, int col) {
|
||||
// TMP
|
||||
int siz = vid.yres > vid.xres ? vid.fsize*2 : vid.fsize * 3/2;
|
||||
@ -1047,7 +1079,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 +1089,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 +1215,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 +1227,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);
|
||||
|
16
crystal.cpp
16
crystal.cpp
@ -461,7 +461,7 @@ shifttable get_canonical(coord co) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int crystal_period = 0;
|
||||
EX int crystal_period = 0;
|
||||
|
||||
struct hrmap_crystal : hrmap_standard {
|
||||
heptagon *getOrigin() override { return get_heptagon_at(c0, S7); }
|
||||
@ -745,7 +745,7 @@ EX color_t colorize(cell *c, char whichCanvas) {
|
||||
for(int a=0; a<3; a++) co[a] = i%5, i /= 5;
|
||||
}
|
||||
#endif
|
||||
else if(euclid) {
|
||||
else if(euc::in()) {
|
||||
auto tab = euc::get_ispacemap()[c->master];
|
||||
for(int a=0; a<3; a++) co[a] = tab[a];
|
||||
if(PURE) for(int a=0; a<3; a++) co[a] *= 2;
|
||||
@ -822,12 +822,12 @@ EX bool crystal_cell(cell *c, transmatrix V) {
|
||||
|
||||
if(!cryst) return false;
|
||||
|
||||
if(view_east && cheater) {
|
||||
if(view_east && allowIncreasedSight()) {
|
||||
int d = dist_alt(c);
|
||||
queuestr(V, 0.3, its(d), 0xFFFFFF, 1);
|
||||
}
|
||||
|
||||
if(view_coordinates && cheater && WDIM == 2) {
|
||||
if(view_coordinates && WDIM == 2 && allowIncreasedSight()) {
|
||||
|
||||
auto m = crystal_map();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -803,7 +803,7 @@ EX namespace dialog {
|
||||
else
|
||||
addSlider(ne.sc.direct(ne.vmin), ne.sc.direct(*ne.editwhat), ne.sc.direct(ne.vmax), 500);
|
||||
addBreak(100);
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
addHelp(XLAT("You can scroll with arrow keys -- Ctrl to fine-tune"));
|
||||
addBreak(100);
|
||||
#endif
|
||||
@ -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);
|
||||
|
148
drawing.cpp
148
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));
|
||||
@ -235,7 +239,7 @@ EX void glflush() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
SDL_Surface *aux;
|
||||
#endif
|
||||
|
||||
@ -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]));
|
||||
} */
|
||||
}
|
||||
|
||||
@ -1381,7 +1386,12 @@ EX namespace ods {
|
||||
|
||||
void dqi_poly::draw() {
|
||||
if(flags & POLY_DEBUG) debug_this();
|
||||
|
||||
if(debugflags & DF_VERTEX) {
|
||||
println(hlog, tie(band_shift, V, offset, cnt, offset_texture, outline, linewidth, flags, intester, cache), (cell*) tinf);
|
||||
for(int i=0; i<cnt; i++) print(hlog, (*tab)[i]);
|
||||
println(hlog);
|
||||
}
|
||||
|
||||
#if CAP_ODS
|
||||
if(vid.stereo_mode == sODS) {
|
||||
ods::draw_ods(this);
|
||||
@ -1430,7 +1440,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 +1468,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 +1484,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 +1540,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 +1566,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 +1584,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 +1601,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 +1630,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;
|
||||
}
|
||||
@ -1651,7 +1661,7 @@ void dqi_poly::draw() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CAP_SVG==1
|
||||
#if CAP_SVG
|
||||
if(svg::in) {
|
||||
coords_to_poly();
|
||||
color_t col = color;
|
||||
@ -1668,10 +1678,10 @@ void dqi_poly::draw() {
|
||||
|
||||
coords_to_poly();
|
||||
|
||||
#if CAP_XGD==1
|
||||
#if CAP_XGD
|
||||
gdpush(1); gdpush(color); gdpush(outline); gdpush(polyi);
|
||||
for(int i=0; i<polyi; i++) gdpush(polyx[i]), gdpush(polyy[i]);
|
||||
#elif CAP_SDLGFX==1
|
||||
#elif CAP_SDLGFX
|
||||
|
||||
if(tinf) {
|
||||
#if CAP_TEXTURE
|
||||
@ -1793,7 +1803,7 @@ void dqi_string::draw() {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
int fr = frame & 255;
|
||||
displayfrSP(x, y, shift, fr, size, str, color, align, frame >> 8);
|
||||
#else
|
||||
@ -1846,14 +1856,14 @@ ld xintval(const hyperpoint& h) {
|
||||
|
||||
EX ld backbrightness = .25;
|
||||
|
||||
purehookset hook_drawqueue;
|
||||
purehookset hooks_drawqueue;
|
||||
|
||||
constexpr int PMAX = int(PPR::MAX);
|
||||
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 +1885,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 +1937,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,7 +1977,17 @@ EX void reverse_transparent_walls() {
|
||||
}
|
||||
|
||||
EX void draw_main() {
|
||||
DEBBI(DF_GRAPH, ("draw_main"));
|
||||
if(sphere && GDIM == 3 && pmodel == mdPerspective) {
|
||||
|
||||
if(ray::in_use && !ray::comparison_mode) {
|
||||
ray::cast();
|
||||
reset_projection();
|
||||
/* currently incompatible with primitive-based renderer */
|
||||
/* also not implemented in stretch */
|
||||
return;
|
||||
}
|
||||
|
||||
for(int p: {1, 0, 2, 3}) {
|
||||
if(elliptic && p < 2) continue;
|
||||
glhr::set_depthwrite(true);
|
||||
@ -1998,17 +2021,21 @@ EX void draw_main() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBB(DF_GRAPH, ("draw_main1"));
|
||||
if(ray::in_use && !ray::comparison_mode) {
|
||||
ray::cast();
|
||||
reset_projection();
|
||||
if(stretch::in()) return; /*primitive not implemented */
|
||||
}
|
||||
|
||||
DEBB(DF_GRAPH, ("outcircle"));
|
||||
for(auto& ptd: ptds) if(ptd->prio == PPR::OUTCIRCLE)
|
||||
ptd->draw();
|
||||
|
||||
if(two_sided_model()) draw_backside();
|
||||
|
||||
for(auto& ptd: ptds) if(ptd->prio != PPR::OUTCIRCLE) {
|
||||
DEBBI(DF_VERTEX, ("prio: ", int(ptd->prio), " color ", ptd->color));
|
||||
dynamicval<int> ss(spherespecial, among(ptd->prio, PPR::MOBILE_ARROW, PPR::OUTCIRCLE, PPR::CIRCLE) ? 0 : spherespecial);
|
||||
ptd->draw();
|
||||
}
|
||||
@ -2028,11 +2055,18 @@ EX void draw_main() {
|
||||
}
|
||||
|
||||
#if CAP_VR
|
||||
EX hookset<bool()> *hooks_vr_draw_all;
|
||||
EX hookset<bool()> hooks_vr_draw_all;
|
||||
#endif
|
||||
|
||||
EX void drawqueue() {
|
||||
callhooks(hook_drawqueue);
|
||||
|
||||
DEBBI(DF_GRAPH, ("drawqueue"));
|
||||
|
||||
#if CAP_WRL
|
||||
if(wrl::in) { wrl::render(); return; }
|
||||
#endif
|
||||
|
||||
callhooks(hooks_drawqueue);
|
||||
current_display->next_shader_flags = 0;
|
||||
reset_projection();
|
||||
// reset_projection() is not sufficient here, because we need to know shaderside_projection
|
||||
@ -2045,6 +2079,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 +2389,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];
|
||||
}
|
||||
|
84
euclid.cpp
84
euclid.cpp
@ -306,10 +306,13 @@ EX namespace euc {
|
||||
};
|
||||
|
||||
hrmap_euclidean* cubemap() {
|
||||
if(fake::in()) return FPIU(cubemap());
|
||||
return ((hrmap_euclidean*) currentmap);
|
||||
}
|
||||
|
||||
hrmap_euclidean* eucmap() { return cubemap(); }
|
||||
hrmap_euclidean* eucmap() {
|
||||
return cubemap();
|
||||
}
|
||||
|
||||
EX vector<coord>& get_current_shifttable() { return cubemap()->shifttable; }
|
||||
EX map<coord, heptagon*>& get_spacemap() { return cubemap()->spacemap; }
|
||||
@ -1169,7 +1172,84 @@ EX int cyldist(gp::loc a, gp::loc b) {
|
||||
return best;
|
||||
}
|
||||
|
||||
EX bool in() { return euclid && standard_tiling(); }
|
||||
EX void generate() {
|
||||
|
||||
if(fake::in()) {
|
||||
fake::generate();
|
||||
return;
|
||||
}
|
||||
|
||||
auto v = euc::get_shifttable();
|
||||
|
||||
auto& cs = cgi.cellshape;
|
||||
|
||||
if(S7 == 6) {
|
||||
cgi.adjcheck = 1;
|
||||
cgi.face = 4;
|
||||
for(int w=0; w<6; w++) {
|
||||
for(int a=0; a<4; a++) {
|
||||
int t[3];
|
||||
t[0] = (w>=3) ? -1 : 1;
|
||||
t[1] = among(a, 0, 3) ? -1 : 1;
|
||||
t[2] = among(a, 2, 3) ? -1 : 1;
|
||||
int x = w%3;
|
||||
int y = (x+2)%3;
|
||||
int z = (y+2)%3;
|
||||
cs.push_back(hpxy3(t[x]/2., t[y]/2., t[z]/2.));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(S7 == 12) {
|
||||
cgi.adjcheck = sqrt(2);
|
||||
cgi.face = 4;
|
||||
for(int w=0; w<12; w++) {
|
||||
auto co = v[w];
|
||||
vector<int> valid;
|
||||
for(int c=0; c<3; c++) if(co[c]) valid.push_back(c);
|
||||
int third = 3 - valid[1] - valid[0];
|
||||
hyperpoint v0 = cpush0(valid[0], co[valid[0]] > 0 ? 1 : -1);
|
||||
hyperpoint v1 = cpush0(valid[1], co[valid[1]] > 0 ? 1 : -1);
|
||||
cs.push_back(v0);
|
||||
cs.push_back(v0/2 + v1/2 + cpush0(third, .5) - C0);
|
||||
cs.push_back(v1);
|
||||
cs.push_back(v0/2 + v1/2 + cpush0(third, -.5) - C0);
|
||||
}
|
||||
}
|
||||
|
||||
if(S7 == 14) {
|
||||
cgi.adjcheck = 2;
|
||||
cgi.face = 4; /* the first face */
|
||||
auto v = euc::get_shifttable();
|
||||
for(int w=0; w<14; w++) {
|
||||
if(w%7 < 3) {
|
||||
int z = w>=7?-1:1;
|
||||
cs.push_back(cpush0(w%7, z) + cpush0((w%7+1)%3, 1/2.) - C0);
|
||||
cs.push_back(cpush0(w%7, z) + cpush0((w%7+2)%3, 1/2.) - C0);
|
||||
cs.push_back(cpush0(w%7, z) + cpush0((w%7+1)%3,-1/2.) - C0);
|
||||
cs.push_back(cpush0(w%7, z) + cpush0((w%7+2)%3,-1/2.) - C0);
|
||||
}
|
||||
else {
|
||||
auto t = v[w];
|
||||
ld x = t[0], y = t[1], z = t[2];
|
||||
for(hyperpoint h: {
|
||||
hpxy3(x, y/2, 0), hpxy3(x/2, y, 0), hpxy3(0, y, z/2),
|
||||
hpxy3(0, y/2, z), hpxy3(x/2, 0, z), hpxy3(x, 0, z/2)
|
||||
}) cs.push_back(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @brief returns true if the current geometry is based on this module
|
||||
* (For example, Archimedean, kite, or fake with underlying non-Euclidean geometry returns false)
|
||||
*/
|
||||
EX bool in() {
|
||||
if(fake::in()) return FPIU(in());
|
||||
return euclid && standard_tiling();
|
||||
}
|
||||
|
||||
EX bool in(int dim) { return in() && WDIM == dim; }
|
||||
EX bool in(int dim, int s7) { return in(dim) && S7 == s7; }
|
||||
|
||||
|
@ -376,7 +376,7 @@ EX int curr_dist(cell *c) {
|
||||
case dfWorld:
|
||||
if(!mod_allowed() && !among(c->land, laOcean, laIvoryTower, laEndorian, laDungeon, laTemple, laWhirlpool, laCanvas))
|
||||
return 0;
|
||||
if(isCyclic(c->land) && (eubinary || c->master->alt)) return celldistAlt(c);
|
||||
if((isCyclic(c->land) || c->land == laCanvas) && (eubinary || c->master->alt)) return celldistAlt(c);
|
||||
return inmirror(c) ? (c->landparam & 255) : c->landparam;
|
||||
}
|
||||
return 0;
|
||||
|
385
fake.cpp
Normal file
385
fake.cpp
Normal file
@ -0,0 +1,385 @@
|
||||
#include "hyper.h"
|
||||
|
||||
// Fake non-Euclidean
|
||||
|
||||
namespace hr {
|
||||
|
||||
EX namespace fake {
|
||||
|
||||
EX ld scale;
|
||||
|
||||
EX eGeometry underlying;
|
||||
EX geometry_information *underlying_cgip;
|
||||
EX hrmap *pmap;
|
||||
EX geometry_information *pcgip;
|
||||
EX eGeometry actual_geometry;
|
||||
|
||||
EX bool in() { return geometry == gFake; }
|
||||
|
||||
// a dummy map that does nothing
|
||||
struct hrmap_fake : hrmap {
|
||||
hrmap *underlying_map;
|
||||
|
||||
template<class T> auto in_underlying(const T& t) -> decltype(t()) {
|
||||
pcgip = cgip;
|
||||
dynamicval<hrmap*> gpm(pmap, this);
|
||||
dynamicval<eGeometry> gag(actual_geometry, geometry);
|
||||
dynamicval<eGeometry> g(geometry, underlying);
|
||||
dynamicval<geometry_information*> gc(cgip, underlying_cgip);
|
||||
dynamicval<hrmap*> gu(currentmap, underlying_map);
|
||||
return t();
|
||||
}
|
||||
|
||||
heptagon *getOrigin() override { return in_underlying([this] { return underlying_map->getOrigin(); }); }
|
||||
|
||||
cell* gamestart() override { return in_underlying([this] { return underlying_map->gamestart(); }); }
|
||||
|
||||
hrmap_fake() {
|
||||
in_underlying([this] { initcells(); underlying_map = currentmap; });
|
||||
for(hrmap*& m: allmaps) if(m == underlying_map) m = NULL;
|
||||
}
|
||||
|
||||
heptagon *create_step(heptagon *parent, int d) override {
|
||||
parent->c.connect(d, parent, d, false);
|
||||
return parent;
|
||||
}
|
||||
|
||||
transmatrix adj(cell *c, int d) override {
|
||||
transmatrix S1, S2;
|
||||
ld dist;
|
||||
in_underlying([c, d, &S1, &S2, &dist] {
|
||||
transmatrix T = currentmap->adj(c, d);
|
||||
S1 = rspintox(tC0(T));
|
||||
transmatrix T1 = spintox(tC0(T)) * T;
|
||||
dist = hdist0(tC0(T1));
|
||||
S2 = xpush(-dist) * T1;
|
||||
});
|
||||
|
||||
if(WDIM == 2) {
|
||||
|
||||
hyperpoint a1, a2, b1, b2;
|
||||
|
||||
in_underlying([c, d, &a1, &a2, &b1, &b2] {
|
||||
a1 = get_corner_position(c, d);
|
||||
a2 = get_corner_position(c, (d+1) % c->type);
|
||||
|
||||
auto c1 = c->move(d);
|
||||
auto d1 = c->c.spin(d);
|
||||
b1 = get_corner_position(c1, d1);
|
||||
b2 = get_corner_position(c1, (d1+1) % c1->type);
|
||||
});
|
||||
|
||||
cgi.adjcheck = hdist0(mid(befake(a1), befake(a2))) + hdist0(mid(befake(b1), befake(b2)));
|
||||
}
|
||||
|
||||
return S1 * xpush(cgi.adjcheck) * S2;
|
||||
}
|
||||
|
||||
void draw_recursive(cell *c, const transmatrix& V, ld a0, ld a1, cell *parent, int depth) {
|
||||
band_shift = 0;
|
||||
if(!do_draw(c, V)) return;
|
||||
drawcell(c, V);
|
||||
|
||||
if(depth >= 15) return;
|
||||
|
||||
// queuestr(V, .2, fts(a0)+":"+fts(a1), 0xFFFFFFFF, 1);
|
||||
|
||||
ld d = hdist0(tC0(V));
|
||||
|
||||
if(false) {
|
||||
curvepoint(spin(-a0) * xpush0(d));
|
||||
curvepoint(spin(-a0) * xpush0(d+.2));
|
||||
curvepoint(spin(-a1) * xpush0(d+.2));
|
||||
curvepoint(spin(-a1) * xpush0(d));
|
||||
curvepoint(spin(-a0) * xpush0(d));
|
||||
queuecurve(0xFF0000FF, 0, PPR::LINE);
|
||||
}
|
||||
|
||||
|
||||
indenter id(2);
|
||||
for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i) != parent) {
|
||||
auto h0 = V * befake(FPIU(get_corner_position(c, i)));
|
||||
auto h1 = V * befake(FPIU(get_corner_position(c, (i+1) % c->type)));
|
||||
ld b0 = atan2(h0);
|
||||
ld b1 = atan2(h1);
|
||||
while(b1 < b0) b1 += 2 * M_PI;
|
||||
if(a0 == -1) {
|
||||
draw_recursive(c->move(i), V * adj(c, i), b0, b1, c, depth+1);
|
||||
}
|
||||
else {
|
||||
if(b1 - b0 > M_PI) continue;
|
||||
|
||||
if(b0 < a0 - M_PI) b0 += 2 * M_PI;
|
||||
if(b0 > a0 + M_PI) b0 -= 2 * M_PI;
|
||||
if(b0 < a0) b0 = a0;
|
||||
|
||||
if(b1 > a1 + M_PI) b1 -= 2 * M_PI;
|
||||
if(b1 < a1 - M_PI) b1 += 2 * M_PI;
|
||||
if(b1 > a1) b1 = a1;
|
||||
|
||||
if(b0 > b1) continue;
|
||||
|
||||
draw_recursive(c->move(i), V * adj(c, i), b0, b1, c, depth+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transmatrix relative_matrix(cell *h2, cell *h1, const hyperpoint& hint) override {
|
||||
if(h1 == h2) return Id;
|
||||
|
||||
for(int a=0; a<h1->type; a++) if(h1->move(a) == h2)
|
||||
return adj(h1, a);
|
||||
|
||||
return Id;
|
||||
}
|
||||
|
||||
transmatrix relative_matrix(heptagon *h2, heptagon *h1, const hyperpoint& hint) override {
|
||||
return relative_matrix(h2->c7, h1->c7, hint);
|
||||
}
|
||||
|
||||
void draw() override {
|
||||
sphereflip = Id;
|
||||
|
||||
// for(int i=0; i<S6; i++) queuepoly(ggmatrix(cwt.at), shWall3D[i], 0xFF0000FF);
|
||||
|
||||
if(pmodel == mdDisk && WDIM == 2) {
|
||||
draw_recursive(centerover, cview(), -1, -1, nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
bool bymatrix = true;
|
||||
|
||||
dq::visited_c.clear();
|
||||
dq::visited_by_matrix.clear();
|
||||
auto enqueue = (bymatrix ? dq::enqueue_by_matrix_c : dq::enqueue_c);
|
||||
enqueue(centerover, cview());
|
||||
|
||||
while(!dq::drawqueue_c.empty()) {
|
||||
auto& p = dq::drawqueue_c.front();
|
||||
cell *c = get<0>(p);
|
||||
transmatrix V = get<1>(p);
|
||||
dynamicval<ld> b(band_shift, get<2>(p));
|
||||
bandfixer bf(V);
|
||||
dq::drawqueue_c.pop();
|
||||
|
||||
if(!do_draw(c, V)) continue;
|
||||
drawcell(c, V);
|
||||
if(in_wallopt() && isWall3(c) && isize(dq::drawqueue_c) > 1000) continue;
|
||||
|
||||
for(int i=0; i<S7; i++) if(c->move(i)) {
|
||||
enqueue(c->move(i), V * adj(c, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EX hrmap* new_map() { return new hrmap_fake; };
|
||||
|
||||
EX hrmap* get_umap() { if(!dynamic_cast<hrmap_fake*>(currentmap)) return nullptr; else return ((hrmap_fake*)currentmap)->underlying_map; }
|
||||
|
||||
#if HDR
|
||||
template<class T> auto in_underlying_geometry(const T& f) -> decltype(f()) {
|
||||
if(!fake::in()) return f();
|
||||
dynamicval<eGeometry> g(geometry, underlying);
|
||||
dynamicval<eGeometry> gag(actual_geometry, geometry);
|
||||
dynamicval<geometry_information*> gc(cgip, underlying_cgip);
|
||||
dynamicval<hrmap*> gpm(pmap, currentmap);
|
||||
dynamicval<hrmap*> gm(currentmap, get_umap());
|
||||
return f();
|
||||
}
|
||||
|
||||
#define FPIU(x) hr::fake::in_underlying_geometry([&] { return (x); })
|
||||
#endif
|
||||
|
||||
EX hyperpoint befake(hyperpoint h) {
|
||||
auto h1 = h / h[WDIM] * scale;
|
||||
h1[WDIM] = 1;
|
||||
if(material(h1) > 1e-3)
|
||||
h1 = normalize(h1);
|
||||
return h1;
|
||||
}
|
||||
|
||||
EX vector<hyperpoint> befake(const vector<hyperpoint>& v) {
|
||||
vector<hyperpoint> res;
|
||||
for(auto& h: v) res.push_back(befake(h));
|
||||
return res;
|
||||
}
|
||||
|
||||
EX ld compute_around(bool setup) {
|
||||
auto &ucgi = *underlying_cgip;
|
||||
|
||||
auto fcs = befake(ucgi.cellshape);
|
||||
|
||||
if(setup) {
|
||||
cgi.cellshape = fcs;
|
||||
cgi.vertices_only = befake(ucgi.vertices_only);
|
||||
}
|
||||
|
||||
hyperpoint h = Hypc;
|
||||
for(int i=0; i<ucgi.face; i++) h += fcs[i];
|
||||
if(material(h) > 0)
|
||||
h = normalize(h);
|
||||
|
||||
if(setup)
|
||||
cgi.adjcheck = 2 * hdist0(h);
|
||||
|
||||
hyperpoint u = Hypc;
|
||||
u += fcs[0];
|
||||
u += fcs[1];
|
||||
|
||||
if(material(u) <= 0)
|
||||
return HUGE_VAL;
|
||||
|
||||
u = normalize(u);
|
||||
hyperpoint h2 = rspintox(h) * xpush0(2 * hdist0(h));
|
||||
|
||||
h2 = spintox(u) * h2;
|
||||
u = spintox(u) * u;
|
||||
|
||||
h2 = gpushxto0(u) * h2;
|
||||
u = gpushxto0(u) * u;
|
||||
|
||||
println(hlog, "h = ", hdist0(h), " ucgi = ", format("%p", &ucgi), " @ ", hyperbolic, " / ", sphere, " h2 = ", h2);
|
||||
|
||||
ld x = hypot(h2[1], h2[2]);
|
||||
ld y = h2[0];
|
||||
return 360 / (90 + atan(y/x) / degree);
|
||||
}
|
||||
|
||||
EX void generate() {
|
||||
println(hlog, "Generating fake");
|
||||
FPIU( cgi.require_basics() );
|
||||
auto &ucgi = *underlying_cgip;
|
||||
|
||||
cgi.loop = ucgi.loop;
|
||||
cgi.face = ucgi.face;
|
||||
|
||||
for(int a=0; a<16; a++)
|
||||
for(int b=0; b<16; b++) {
|
||||
cgi.dirs_adjacent[a][b] = ucgi.dirs_adjacent[a][b];
|
||||
cgi.next_dir[a][b] = ucgi.next_dir[a][b];
|
||||
}
|
||||
|
||||
for(int b=0; b<12; b++)
|
||||
cgi.spins[b] = ucgi.spins[b];
|
||||
|
||||
compute_around(true);
|
||||
}
|
||||
|
||||
int get_middle() {
|
||||
if(S7 == 20) return 5;
|
||||
if(S7 == 8) return 4;
|
||||
return 3;
|
||||
}
|
||||
|
||||
EX ld around;
|
||||
|
||||
EX void compute_scale() {
|
||||
|
||||
int middle = get_middle();
|
||||
|
||||
// the value of 'around' which makes the tiling Euclidean
|
||||
ld good = M_PI / asin(cos(M_PI/middle) / sin(M_PI/underlying_cgip->face));
|
||||
|
||||
println(hlog, "good = ", good);
|
||||
|
||||
if(abs(good - around) < 1e-6) good = around;
|
||||
|
||||
if(around == good) {
|
||||
ginf[gFake].g = WDIM == 3 ? giEuclid3 : giEuclid2;
|
||||
}
|
||||
|
||||
if(around > good) {
|
||||
ginf[gFake].g = WDIM == 3 ? giHyperb3 : giHyperb2;
|
||||
}
|
||||
|
||||
if(around < good) {
|
||||
ginf[gFake].g = WDIM == 3 ? giSphere3 : giSphere2;
|
||||
}
|
||||
|
||||
ld around_ideal = 1/(1/2. - 1./get_middle());
|
||||
println(hlog, "around_ideal = ", around_ideal);
|
||||
|
||||
if(euclid) scale = 1;
|
||||
else if(abs(around_ideal - around) < 1e-6) {
|
||||
hyperpoint h0 = underlying_cgip->cellshape[0];
|
||||
auto s = kleinize(h0);
|
||||
ld d = hypot_d(LDIM, s);
|
||||
scale = 1/d;
|
||||
|
||||
hyperpoint h = h0;
|
||||
auto h1 = h / h[WDIM] * scale;
|
||||
h1[WDIM] = 1;
|
||||
|
||||
println(hlog, "material = ", material(h1));
|
||||
}
|
||||
else {
|
||||
ld minscale = 0, maxscale = 10;
|
||||
for(int it=0; it<100; it++) {
|
||||
scale = (minscale + maxscale) / 2;
|
||||
ld ar = compute_around(false);
|
||||
println(hlog, "scale = ", scale, " ar = ", ar);
|
||||
if(sphere) {
|
||||
if(ar < around) maxscale = scale;
|
||||
else minscale = scale;
|
||||
}
|
||||
else {
|
||||
if(ar > around) maxscale = scale;
|
||||
else minscale = scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
sightranges[gFake] = sightranges[underlying] * scale;
|
||||
}
|
||||
|
||||
void set_gfake(int c, ld _around) {
|
||||
stop_game();
|
||||
cgi.require_basics();
|
||||
fake::scale = scale;
|
||||
underlying = geometry;
|
||||
underlying_cgip = cgip;
|
||||
ginf[gFake] = ginf[underlying];
|
||||
|
||||
set_geometry(gFake);
|
||||
|
||||
around = _around;
|
||||
|
||||
compute_scale();
|
||||
check_cgi();
|
||||
|
||||
compute_scale();
|
||||
check_cgi();
|
||||
}
|
||||
|
||||
EX void change_around() {
|
||||
if(around > 2) {
|
||||
ld t = sightranges[gFake] / (sightranges[underlying] * scale);
|
||||
compute_scale();
|
||||
ray::reset_raycaster();
|
||||
sightranges[gFake] *= t;
|
||||
}
|
||||
};
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-gfake")) {
|
||||
if(fake::in()) shift_arg_formula(around, change_around);
|
||||
else {
|
||||
shift(); int c = argi();
|
||||
ld around;
|
||||
shift_arg_formula(around);
|
||||
set_gfake(c, around);
|
||||
}
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto fundamentalhook = addHook(hooks_args, 100, readArgs);
|
||||
|
||||
EX }
|
||||
|
||||
}
|
||||
|
2724
fieldpattern.cpp
2724
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
|
||||
|
52
geom-exp.cpp
52
geom-exp.cpp
@ -359,6 +359,7 @@ void ge_select_tiling() {
|
||||
if(arb::in() && (ISMOBILE || ISWEB)) continue;
|
||||
if(WDIM == 3 && MAXMDIM == 3) continue;
|
||||
if(geometry == gFieldQuotient && !CAP_FIELD) continue;
|
||||
if(geometry == gFake) continue;
|
||||
if(!current_filter->test()) continue;
|
||||
if(orig_el) {
|
||||
for(int j=0; j<isize(ginf); j++)
|
||||
@ -381,21 +382,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 +406,7 @@ EX string dim_name() {
|
||||
return " (" + its(WDIM) + "D)";
|
||||
}
|
||||
|
||||
#if CAP_THREAD
|
||||
#if CAP_THREAD && MAXMDIM >= 4
|
||||
EX void showQuotientConfig3() {
|
||||
|
||||
using namespace fieldpattern;
|
||||
@ -512,6 +513,7 @@ EX void select_quotient_screen() {
|
||||
char key = 'a';
|
||||
for(int i=0; i<isize(ginf); i++) {
|
||||
auto g = eGeometry(i);
|
||||
if(ginf[g].flags & qDEPRECATED) continue;
|
||||
if(same_tiling(g)) {
|
||||
dialog::addBoolItem(
|
||||
(ginf[g].flags & qANYQ) ?
|
||||
@ -528,7 +530,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
|
||||
}
|
||||
@ -742,6 +744,16 @@ EX void showEuclideanMenu() {
|
||||
|
||||
dialog::add_action(select_quotient);
|
||||
|
||||
if(arcm::in()) {
|
||||
dialog::addItem(XLAT("advanced parameters"), '4');
|
||||
dialog::add_action_push(arcm::show);
|
||||
}
|
||||
|
||||
if(cryst) {
|
||||
dialog::addItem(XLAT("advanced parameters"), '4');
|
||||
dialog::add_action_push(crystal::show);
|
||||
}
|
||||
|
||||
#if CAP_IRR
|
||||
if(hyperbolic && IRREGULAR) {
|
||||
nom = isize(irr::cells);
|
||||
@ -813,7 +825,7 @@ EX void showEuclideanMenu() {
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(rots::underlying_scale, 0, 1, 0.05, 0.25, XLAT("view the underlying geometry"),
|
||||
XLAT(
|
||||
geometry == gRotSpace ? "The space you are currently in the space of rotations of the underlying hyperbolic or spherical geometry. "
|
||||
geometry == gRotSpace ? "The space you are currently in is the space of rotations of the underlying hyperbolic or spherical geometry. "
|
||||
: "You are currently in a product space.") +
|
||||
XLAT(
|
||||
"This option lets you see the underlying space. Lands and some walls (e.g. in the Graveyard) are based on "
|
||||
@ -826,6 +838,20 @@ EX void showEuclideanMenu() {
|
||||
});
|
||||
}
|
||||
|
||||
if(stretch::applicable()) {
|
||||
dialog::addSelItem(XLAT("stretched geometry"), fts(stretch::factor), 'S');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(stretch::factor, -1, 9, 0.1, 0, XLAT("stretched geometry"),
|
||||
XLAT(
|
||||
"Stretch the metric along the fibers. This can currently be done in rotation spaces and in 8-cell, 24-cell and 120-cell. "
|
||||
"Value of 0 means not stretched, -1 means S2xE or H2xE (works only in the limit). "
|
||||
"Only the raycaster is implemented for stretched geometry, so you will see only walls. (Must be > -1)"
|
||||
)
|
||||
);
|
||||
dialog::reaction = ray::reset_raycaster;
|
||||
});
|
||||
}
|
||||
|
||||
dialog::addBreak(100);
|
||||
dialog::addSelItem(XLAT("land"), XLAT1(linf[specialland].name), 'l');
|
||||
dialog::add_action_push(ge_land_selection);
|
||||
@ -940,7 +966,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;
|
||||
|
55
geometry.cpp
55
geometry.cpp
@ -329,7 +329,7 @@ hpcshape
|
||||
|
||||
int SD3, SD6, SD7, S12, S14, S21, S28, S42, S36, S84;
|
||||
|
||||
vector<int> walloffsets;
|
||||
vector<pair<int, cell*>> walloffsets;
|
||||
|
||||
vector<array<int, 3>> symmetriesAt;
|
||||
|
||||
@ -433,16 +433,16 @@ hpcshape
|
||||
ld alpha;
|
||||
int area;
|
||||
};
|
||||
shared_ptr<gpdata_t> gpdata;
|
||||
shared_ptr<gpdata_t> gpdata = nullptr;
|
||||
#endif
|
||||
|
||||
int state;
|
||||
int usershape_state;
|
||||
int state = 0;
|
||||
int usershape_state = 0;
|
||||
|
||||
/** contains the texture point coordinates for 3D models */
|
||||
basic_textureinfo models_texture;
|
||||
|
||||
geometry_information() { last = NULL; state = usershape_state = 0; gpdata = NULL; }
|
||||
geometry_information() { last = NULL; }
|
||||
|
||||
void require_basics() { if(state & 1) return; state |= 1; prepare_basics(); }
|
||||
void require_shapes() { if(state & 2) return; state |= 2; prepare_shapes(); }
|
||||
@ -573,6 +573,7 @@ void geometry_information::prepare_basics() {
|
||||
#endif
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::in()) reg3::generate();
|
||||
if(euc::in(3)) euc::generate();
|
||||
#endif
|
||||
|
||||
hybrid_finish:
|
||||
@ -710,24 +711,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 +852,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;
|
||||
}
|
||||
@ -926,12 +927,19 @@ EX int last_texture_step;
|
||||
|
||||
int ntimestamp;
|
||||
|
||||
EX void check_cgi() {
|
||||
EX string cgi_string() {
|
||||
string s;
|
||||
auto V = [&] (string a, string b) { s += a; s += ": "; s += b; s += "; "; };
|
||||
V("GEO", its(int(geometry)));
|
||||
V("VAR", its(int(variation)));
|
||||
|
||||
if(fake::in()) {
|
||||
if(hyperbolic) V("H", fts(fake::scale));
|
||||
if(euclid) V("E", fts(fake::scale));
|
||||
if(sphere) V("S", fts(fake::scale));
|
||||
V("G", FPIU(cgi_string()));
|
||||
}
|
||||
|
||||
if(GOLDBERG) V("GP", its(gp::param.first) + "," + its(gp::param.second));
|
||||
if(IRREGULAR) V("IRR", its(irr::irrid));
|
||||
|
||||
@ -976,9 +984,16 @@ EX void check_cgi() {
|
||||
|
||||
V("LQ", its(vid.linequality));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EX void check_cgi() {
|
||||
string s = cgi_string();
|
||||
|
||||
cgip = &cgis[s];
|
||||
cgi.timestamp = ++ntimestamp;
|
||||
if(hybri) hybrid::underlying_cgip->timestamp = ntimestamp;
|
||||
if(fake::in()) fake::underlying_cgip->timestamp = ntimestamp;
|
||||
|
||||
if(isize(cgis) > 4) {
|
||||
vector<pair<int, string>> timestamps;
|
||||
|
@ -287,6 +287,23 @@ void virtualRebase_cell(cell*& base, T& at, const U& check) {
|
||||
template<class T, class U>
|
||||
void virtualRebase(cell*& base, T& at, const U& check) {
|
||||
|
||||
if(nil) {
|
||||
hyperpoint h = check(at);
|
||||
auto step = [&] (int i) {
|
||||
at = currentmap->iadj(base, i) * at;
|
||||
base = base->cmove(i);
|
||||
h = check(at);
|
||||
};
|
||||
|
||||
while(h[1] < -0.5) step(1);
|
||||
while(h[1] >= 0.5) step(4);
|
||||
while(h[0] < -0.5) step(0);
|
||||
while(h[0] >= 0.5) step(3);
|
||||
while(h[2] < -0.5) step(2);
|
||||
while(h[2] >= 0.5) step(5);
|
||||
return;
|
||||
}
|
||||
|
||||
if(prod) {
|
||||
auto d = product_decompose(check(at)).first;
|
||||
while(d > cgi.plevel / 2) {
|
||||
|
10
glhr.cpp
10
glhr.cpp
@ -24,10 +24,6 @@ EX void glError(const char* GLcall, const char* file, const int line) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CAP_VERTEXBUFFER
|
||||
#define CAP_VERTEXBUFFER (ISWEB)
|
||||
#endif
|
||||
|
||||
#if HDR
|
||||
#if CAP_SHADER && CAP_NOSHADER
|
||||
#define WITHSHADER(x, y) if(glhr::noshaders) y else x
|
||||
@ -42,6 +38,12 @@ EX void glError(const char* GLcall, const char* file, const int line) {
|
||||
|
||||
EX namespace glhr {
|
||||
|
||||
EX string to_glsl(ld x) {
|
||||
char buf[64];
|
||||
snprintf(buf, 64, "float(%.10e)", x);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if HDR
|
||||
struct glmatrix {
|
||||
GLfloat a[4][4];
|
||||
|
62
graph.cpp
62
graph.cpp
@ -40,8 +40,8 @@ EX bool hide_player() {
|
||||
|
||||
#define ADC(V,c) for(const transmatrix& V: current_display->all_drawn_copies[c])
|
||||
|
||||
EX hookset<bool(int sym, int uni)> *hooks_handleKey;
|
||||
EX hookset<bool(cell *c, const transmatrix& V)> *hooks_drawcell;
|
||||
EX hookset<bool(int sym, int uni)> hooks_handleKey;
|
||||
EX hookset<bool(cell *c, const transmatrix& V)> hooks_drawcell;
|
||||
EX purehookset hooks_frame, hooks_markers;
|
||||
|
||||
EX ld animation_factor = 1;
|
||||
@ -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,8 +3668,8 @@ 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);
|
||||
for(hyperpoint& cpoint: clipping_planes) if((H2|cpoint) < -.4) return true;
|
||||
hyperpoint H2 = inverse_exp(H, pQUICK);
|
||||
for(hyperpoint& cpoint: clipping_planes) if((H2|cpoint) < -.6) 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
|
||||
@ -4050,7 +4052,7 @@ EX void queuecircleat(cell *c, double rad, color_t col) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
#define MOBON (clicked)
|
||||
#else
|
||||
#define MOBON true
|
||||
@ -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);
|
||||
|
||||
@ -5150,7 +5154,7 @@ EX void clearAnimations() {
|
||||
fallanims.clear();
|
||||
}
|
||||
|
||||
auto graphcm = addHook(clearmemory, 0, [] () {
|
||||
auto graphcm = addHook(hooks_clearmemory, 0, [] () {
|
||||
DEBBI(DF_MEMORY, ("clear graph memory"));
|
||||
mouseover = centerover = lmouseover = NULL;
|
||||
gmatrix.clear(); gmatrix0.clear(); current_display->all_drawn_copies.clear();
|
||||
|
85
help.cpp
85
help.cpp
@ -26,19 +26,25 @@ struct help_extension {
|
||||
|
||||
EX vector<help_extension> help_extensions;
|
||||
|
||||
vector<string> extra_keys = {
|
||||
"1 = orthogonal/Gans model",
|
||||
"2 = small Poincare model/stereographic projection",
|
||||
"3 = big Poincare model/stereographic projection",
|
||||
vector<string> quick_keys = {
|
||||
"1 = orthogonal/Gans model/FPP",
|
||||
"2 = small Poincare model/stereographic projection/SPP",
|
||||
"3 = big Poincare model/stereographic projection/TPP",
|
||||
"4 = Klein model/gnomonic projection",
|
||||
"5 = change wall display mode",
|
||||
"6 = change grid",
|
||||
"7 = change heptagon marking",
|
||||
// "8 = change background color",
|
||||
// "9 = hyperboloid model",
|
||||
"8 = monster display mode"
|
||||
};
|
||||
|
||||
vector<string> normal_keys = {
|
||||
"qweasdzxc, hjklyubn, numpad = move/skip turn",
|
||||
"arrows = panning",
|
||||
"o = world overview",
|
||||
"g = drop a Dead Orb",
|
||||
"t = use a ranged Orb (target center of the screen)"
|
||||
};
|
||||
|
||||
vector<string> extra_keys = {
|
||||
"o = world overview (or another meaning in special modes)",
|
||||
"v = menu",
|
||||
"F1 = help",
|
||||
"F5 = restart game",
|
||||
@ -46,22 +52,37 @@ vector<string> extra_keys = {
|
||||
"Esc = quest status",
|
||||
"Alt+Enter = full screen",
|
||||
"Alt = highlight interesting stuff",
|
||||
"t = use a ranged Orb (target center of the screen)",
|
||||
"g = drop a Dead Orb",
|
||||
"click left mouse button = move/skip",
|
||||
"shift+click left mouse button = use ranged Orb",
|
||||
"[shift+]click left mouse button = use ranged Orb (depending on mouse settings)",
|
||||
"click right mouse button = context help",
|
||||
"mousewheel up = panning",
|
||||
"hold middle mouse button = panning",
|
||||
"lctrl + hold middle button = move the screen",
|
||||
"mousewheel down = move/skip",
|
||||
"shift + mousewheel = change projection",
|
||||
"ctrl + mousewheel = change zoom",
|
||||
"ctrl + shift + mousewheel = change both projection and zoom",
|
||||
"ctrl + hold middle button = move the screen",
|
||||
"shift + middle button = reset position",
|
||||
"rshift + mousewheel = change projection",
|
||||
"lshift + mousewheel = change zoom (lctrl to keep center)",
|
||||
"lctrl + mousewheel = reset the map center",
|
||||
"shift + F2 = disable the HUD",
|
||||
"shift + F3 = disable the FPS",
|
||||
"shift + F4 = disable the map"
|
||||
"shift + F4 = disable the map",
|
||||
"space = recenter",
|
||||
"ctrl + <key> = more precision"
|
||||
};
|
||||
|
||||
vector<string> extra_keys_2d = {
|
||||
"arrows = panning",
|
||||
"PageUp/Down = rotate the screen",
|
||||
};
|
||||
|
||||
vector<string> extra_keys_3d = {
|
||||
"arrows = rotate the camera",
|
||||
"rshift+arrows = strafe",
|
||||
"lshift+arrows = rotate the model (in rug mode)",
|
||||
"end = move camera forward",
|
||||
"home = move camera backward",
|
||||
"shift+Home/End = zoom",
|
||||
"PageUp/Down = rotate the screen",
|
||||
"move mouse = rotate camera (in rug, only with lctrl)",
|
||||
};
|
||||
|
||||
void buildHelpText() {
|
||||
@ -147,7 +168,7 @@ void buildHelpText() {
|
||||
#else
|
||||
if(DEFAULTCONTROL)
|
||||
help += XLAT(
|
||||
"Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. "
|
||||
"Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Space. "
|
||||
"To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n"
|
||||
);
|
||||
help += XLAT(
|
||||
@ -173,7 +194,18 @@ void buildHelpText() {
|
||||
#if ISMOBILE == 0
|
||||
help_extensions.push_back(help_extension{'k', XLAT("advanced keyboard shortcuts"), [] () {
|
||||
help = "";
|
||||
for(string s: extra_keys) help += s, help += "\n\n";
|
||||
for(string s: normal_keys) help += s, help += "\n";
|
||||
for(string s: extra_keys) help += s, help += "\n";
|
||||
help += "\n\nQuick keys:\n";
|
||||
for(string s: quick_keys) help += s, help += "\n";
|
||||
if(GDIM == 3 || rug::rugged) {
|
||||
help += "\n\nIn 3D modes:\n";
|
||||
for(string s: extra_keys_3d) help += s, help += "\n";
|
||||
}
|
||||
else {
|
||||
help += "\n\nIn 2D modes:\n";
|
||||
for(string s: extra_keys_2d) help += s, help += "\n";
|
||||
}
|
||||
}});
|
||||
#endif
|
||||
}
|
||||
@ -325,7 +357,7 @@ EX string generateHelpForItem(eItem it) {
|
||||
" You need to go deep to collect lots of them.");
|
||||
}
|
||||
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
if(it == itOrbSafety)
|
||||
help += XLAT("This might be very useful for devices with limited memory.");
|
||||
#else
|
||||
@ -493,7 +525,7 @@ void addMinefieldExplanation(string& s) {
|
||||
);
|
||||
|
||||
s += "\n\n";
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
s += XLAT("Known mines may be marked by pressing 'm'. Your allies won't step on marked mines.");
|
||||
#else
|
||||
s += XLAT("Known mines may be marked by touching while in drag mode. Your allies won't step on marked mines.");
|
||||
@ -772,7 +804,7 @@ EX void appendHelp(string s) {
|
||||
unsigned char lastval;
|
||||
int windtotal;
|
||||
|
||||
EX hookset<void(cell*)> *hooks_mouseover;
|
||||
EX hookset<void(cell*)> hooks_mouseover;
|
||||
|
||||
EX void describeMouseover() {
|
||||
DEBBI(DF_GRAPH, ("describeMouseover"));
|
||||
@ -1017,7 +1049,7 @@ EX void showHelp() {
|
||||
};
|
||||
}
|
||||
|
||||
EX hookset<bool()> *hooks_default_help;
|
||||
EX hookset<bool()> hooks_default_help;
|
||||
|
||||
EX void gotoHelp(const string& h) {
|
||||
help = h;
|
||||
@ -1030,6 +1062,13 @@ EX void gotoHelp(const string& h) {
|
||||
#if CAP_RUG
|
||||
if(rug::rugged) {
|
||||
help = rug::makehelp();
|
||||
|
||||
help += "\n\n";
|
||||
|
||||
for(string s: extra_keys_3d) help += s, help += "\n";
|
||||
|
||||
help += "\n\n";
|
||||
|
||||
help_extensions.push_back(help_extension{'m', XLAT("Hypersian Rug menu"), [] () { popScreen(); rug::select(); }});
|
||||
help_extensions.push_back(help_extension{'h', XLAT("HyperRogue help"), [] () { buildHelpText(); }});
|
||||
return;
|
||||
|
40
heptagon.cpp
40
heptagon.cpp
@ -119,9 +119,16 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fix
|
||||
if(h->c.spin(0) == 2 && h->move(0)) {
|
||||
int d = h->c.spin(0);
|
||||
int d1 = (d+S7-1)%S7;
|
||||
heptagon* h1 = createStep(h->move(0), d1);
|
||||
if(h1->distance <= h->move(0)->distance)
|
||||
h->distance = h->move(0)->distance+1;
|
||||
bool missing0 = !h->move(0)->move(d1);
|
||||
if(missing0) {
|
||||
if(s == 1)
|
||||
h->distance = h->move(0)->distance + 1;
|
||||
}
|
||||
else {
|
||||
heptagon* h1 = createStep(h->move(0), d1);
|
||||
if(h1->distance <= h->move(0)->distance)
|
||||
h->distance = h->move(0)->distance+1;
|
||||
}
|
||||
}
|
||||
if((h->s == hsB && h->move(0)->s == hsB) || h->move(0)->s == hsA) {
|
||||
int d = h->c.spin(0);
|
||||
@ -129,11 +136,23 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fix
|
||||
if(h1->distance <= h->move(0)->distance)
|
||||
h->distance = h->move(0)->distance+1;
|
||||
}
|
||||
if(h->c.spin(0) == S7-1 && h->move(0)->distance != 0)
|
||||
h->distance = min(
|
||||
h->move(0)->move(0)->distance + 2,
|
||||
createStep(h, S7-1)->distance + 1
|
||||
);
|
||||
if(h->c.spin(0) == S7-1 && (h->move(0)->s != hsOrigin) && BITRUNCATED) {
|
||||
bool missing = !h->move(S7-1);
|
||||
if(missing) {
|
||||
h->distance = parent->distance;
|
||||
if(
|
||||
parent->distance - h->move(0)->move(0)->distance == 1 &&
|
||||
h->c.spin(0) == S7 - 1 &&
|
||||
h->move(0)->c.spin(0) == 2)
|
||||
h->distance++;
|
||||
}
|
||||
else {
|
||||
h->distance = min(
|
||||
h->move(0)->move(0)->distance + 2,
|
||||
createStep(h, S7-1)->distance + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(parent->s == hsOrigin) h->distance = parent->distance + gp::dist_2();
|
||||
#if CAP_GP
|
||||
@ -190,6 +209,9 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fix
|
||||
}
|
||||
else {
|
||||
h->distance = parent->distance - gp::dist_2();
|
||||
if(S3 == 4 && S7 > 5 && BITRUNCATED) {
|
||||
h->distance = parent->distance - 2;
|
||||
}
|
||||
if(S3 == 4 && S7 == 5) {
|
||||
if(h->s == hsOrigin) {
|
||||
printf("had to cheat!\n");
|
||||
@ -217,7 +239,7 @@ void addSpin(heptagon *h, int d, heptagon *from, int rot, int spin) {
|
||||
|
||||
extern int hrand(int);
|
||||
|
||||
EX hookset<void(heptagon*, int)> *hooks_createStep;
|
||||
EX hookset<void(heptagon*, int)> hooks_createStep;
|
||||
|
||||
// create h->move(d) if not created yet
|
||||
heptagon *createStep(heptagon *h, int d) {
|
||||
|
@ -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');
|
||||
|
||||
@ -689,7 +689,7 @@ EX namespace history {
|
||||
auto hookArg = addHook(hooks_args, 100, readArgs);
|
||||
#endif
|
||||
|
||||
auto hooks = addHook(clearmemory, 0, [] () {
|
||||
auto hooks = addHook(hooks_clearmemory, 0, [] () {
|
||||
history::renderAutoband();
|
||||
history::on = false;
|
||||
history::killhistory.clear();
|
||||
|
26
hprint.cpp
26
hprint.cpp
@ -25,7 +25,8 @@ EX FILE *debugfile;
|
||||
#define DF_GP 2048
|
||||
#define DF_POLY 4096
|
||||
#define DF_LOG 8192
|
||||
#define DF_KEYS "imwesxufgbtopl"
|
||||
#define DF_VERTEX 16384
|
||||
#define DF_KEYS "imwesxufgbtoplv"
|
||||
#endif
|
||||
|
||||
EX int debugflags = DF_INIT | DF_ERROR | DF_WARN | DF_MSG | DF_TIME | DF_LOG;
|
||||
@ -278,6 +279,22 @@ struct indenter_finish : indenter {
|
||||
|
||||
#endif
|
||||
|
||||
EX void print(hstream& hs, cld x) {
|
||||
int parts = 0;
|
||||
if(kz(real(x))) {
|
||||
print(hs, real(x));
|
||||
parts++;
|
||||
}
|
||||
|
||||
if(kz(imag(x))) {
|
||||
if(parts && imag(x) > 0) print(hs, "+");
|
||||
parts++;
|
||||
print(hs, imag(x), "i");
|
||||
}
|
||||
|
||||
if(!parts) print(hs, 0);
|
||||
}
|
||||
|
||||
EX string fts_fixed(ld x, int prec IS(6)) {
|
||||
std::stringstream ss;
|
||||
ss.precision(prec);
|
||||
@ -354,6 +371,13 @@ EX transmatrix kz(transmatrix h) {
|
||||
return h;
|
||||
}
|
||||
|
||||
#if HDR
|
||||
template<class T> vector<T> kz(vector<T> v) {
|
||||
for(auto& el: v) el = kz(el);
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
EX string pick123() { return cts('1' + rand() % 3); }
|
||||
EX string pick12() { return cts('1' + rand() % 2); }
|
||||
|
||||
|
16
hud.cpp
16
hud.cpp
@ -328,7 +328,7 @@ void displayglyph2(int cx, int cy, int buttonsize, int i) {
|
||||
|
||||
EX bool nohud, nomenukey;
|
||||
|
||||
EX hookset<bool()> *hooks_prestats;
|
||||
EX hookset<bool()> hooks_prestats;
|
||||
|
||||
#if CAP_SHAPES
|
||||
void drawMobileArrow(int i) {
|
||||
@ -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;
|
||||
|
@ -29,7 +29,7 @@ void moreStack() {
|
||||
#endif
|
||||
|
||||
namespace hr {
|
||||
EX hookset<bool(int argc, char** argv)> *hooks_main;
|
||||
EX hookset<bool(int argc, char** argv)> hooks_main;
|
||||
|
||||
EX int hyper_main(int argc, char **argv) {
|
||||
using namespace hr;
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "arbitrile.cpp"
|
||||
#include "euclid.cpp"
|
||||
#include "sphere.cpp"
|
||||
#include "fake.cpp"
|
||||
#include "quotient.cpp"
|
||||
#include "crystal.cpp"
|
||||
#include "reg3.cpp"
|
||||
|
122
hyper.h
122
hyper.h
@ -13,8 +13,8 @@
|
||||
#define _HYPER_H_
|
||||
|
||||
// version numbers
|
||||
#define VER "11.3i"
|
||||
#define VERNUM_HEX 0xA829
|
||||
#define VER "11.3l"
|
||||
#define VERNUM_HEX 0xA82C
|
||||
|
||||
#include "sysconfig.h"
|
||||
|
||||
@ -142,6 +142,7 @@ void addMessage(string s, char spamtype = 0);
|
||||
#define sl2 (cgclass == gcSL2)
|
||||
#define prod (cgclass == gcProduct)
|
||||
#define hybri (cgflags & qHYBRID)
|
||||
#define rotspace (geometry == gRotSpace)
|
||||
#define hyperbolic (cgclass == gcHyperbolic)
|
||||
#define nonisotropic (among(cgclass, gcSolNIH, gcNil, gcSL2))
|
||||
#define translatable (euclid || nonisotropic)
|
||||
@ -228,9 +229,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 +289,6 @@ struct videopar {
|
||||
|
||||
int xscr, yscr;
|
||||
|
||||
ld xposition, yposition;
|
||||
|
||||
bool grid;
|
||||
bool particles;
|
||||
|
||||
@ -304,8 +340,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 +353,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 +364,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 +373,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
|
||||
|
||||
@ -407,8 +439,41 @@ struct movedir {
|
||||
|
||||
// shmup
|
||||
|
||||
template<class T> class hookset : public map<int, function<T>> {};
|
||||
typedef hookset<void()> *purehookset;
|
||||
template<class T>
|
||||
class hookset {
|
||||
std::map<int, std::function<T>> *map_ = nullptr;
|
||||
|
||||
public:
|
||||
template<class U>
|
||||
int add(int prio, U&& hook) {
|
||||
if (map_ == nullptr) map_ = new std::map<int, std::function<T>>();
|
||||
while (map_->count(prio)) {
|
||||
prio++;
|
||||
}
|
||||
map_->emplace(prio, static_cast<U&&>(hook));
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class... U>
|
||||
void callhooks(U&&... args) const {
|
||||
if (map_ == nullptr) return;
|
||||
for (const auto& p : *map_) {
|
||||
p.second(static_cast<U&&>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template<class V, class... U>
|
||||
V callhandlers(V zero, U&&... args) const {
|
||||
if (map_ == nullptr) return zero;
|
||||
for (const auto& p : *map_) {
|
||||
auto z = p.second(static_cast<U&&>(args)...);
|
||||
if (z != zero) return z;
|
||||
}
|
||||
return zero;
|
||||
}
|
||||
};
|
||||
|
||||
using purehookset = hookset<void()>;
|
||||
|
||||
static const int NOHINT = -1;
|
||||
|
||||
@ -621,33 +686,24 @@ 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);
|
||||
|
||||
static const int DISTANCE_UNKNOWN = 127;
|
||||
|
||||
#include <functional>
|
||||
|
||||
template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook) {
|
||||
if(!m) m = new hookset<T> ();
|
||||
while(m->count(prio)) {
|
||||
prio++;
|
||||
}
|
||||
(*m)[prio] = hook;
|
||||
return 0;
|
||||
template<class T, class U> int addHook(hookset<T>& m, int prio, U&& hook) {
|
||||
return m.add(prio, static_cast<U&&>(hook));
|
||||
}
|
||||
|
||||
template<class T, class... U> void callhooks(hookset<T> *h, U&&... args) {
|
||||
if(h) for(auto& p: *h) p.second(std::forward<U>(args)...);
|
||||
template<class T, class... U> void callhooks(const hookset<T>& h, U&&... args) {
|
||||
return h.callhooks(static_cast<U&&>(args)...);
|
||||
}
|
||||
|
||||
template<class T, class V, class... U> V callhandlers(V zero, hookset<T> *h, U&&... args) {
|
||||
if(h) for(auto& p: *h) {
|
||||
auto z = p.second(std::forward<U>(args)...);
|
||||
if(z != zero) return z;
|
||||
}
|
||||
return zero;
|
||||
template<class T, class V, class... U> V callhandlers(V zero, const hookset<T>& h, U&&... args) {
|
||||
return h.callhandlers(zero, static_cast<U&&>(args)...);
|
||||
}
|
||||
|
||||
string XLAT(string);
|
||||
@ -670,7 +726,7 @@ struct colortable: vector<color_t> {
|
||||
|
||||
namespace scores { void load(); }
|
||||
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
namespace leader { void showMenu(); void handleKey(int sym, int uni); }
|
||||
#endif
|
||||
|
||||
@ -679,7 +735,7 @@ int textwidth(int siz, const string &str);
|
||||
int gl_width(int size, const char *s);
|
||||
#endif
|
||||
|
||||
#ifdef ISMOBILE
|
||||
#if ISMOBILE
|
||||
extern int andmode;
|
||||
extern bool longclick;
|
||||
extern bool useRangedOrb;
|
||||
|
@ -381,7 +381,14 @@ EX ld sqhypot_d(int d, const hyperpoint& h) {
|
||||
EX ld hypot_d(int d, const hyperpoint& h) {
|
||||
return sqrt(sqhypot_d(d, h));
|
||||
}
|
||||
|
||||
|
||||
/** @brief positive for a material vertex, 0 for ideal vertex, negative for ultra-ideal vertex */
|
||||
EX ld material(const hyperpoint& h) {
|
||||
if(sphere) return intval(h, Hypc);
|
||||
else if(hyperbolic) return -intval(h, Hypc);
|
||||
else return h[LDIM] - 1;
|
||||
}
|
||||
|
||||
EX ld zlevel(const hyperpoint &h) {
|
||||
if(sl2) return sqrt(-intval(h, Hypc));
|
||||
else if(translatable) return h[LDIM];
|
||||
@ -412,6 +419,14 @@ EX hyperpoint normalize(hyperpoint H) {
|
||||
return H;
|
||||
}
|
||||
|
||||
/** like normalize but makes (ultra)ideal points material */
|
||||
EX hyperpoint ultra_normalize(hyperpoint H) {
|
||||
if(material(H) <= 0) {
|
||||
H[MDIM-1] = hypot_d(MDIM-1, H) + 1e-6;
|
||||
}
|
||||
return normalize(H);
|
||||
}
|
||||
|
||||
/** normalize, and in product geometry, also flatten */
|
||||
EX hyperpoint normalize_flat(hyperpoint h) {
|
||||
if(prod) return product_decompose(h).second;
|
||||
@ -702,6 +717,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) {
|
||||
@ -742,6 +759,7 @@ EX transmatrix rgpushxto0(const hyperpoint& H) {
|
||||
|
||||
EX void fixmatrix(transmatrix& T) {
|
||||
if(nonisotropic) ; // T may be inverse... do not do that
|
||||
else if(cgflags & qAFFINE) ; // affine
|
||||
else if(prod) {
|
||||
auto z = zlevel(tC0(T));
|
||||
T = mscale(T, -z);
|
||||
@ -1030,13 +1048,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 +1169,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 +1181,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 +1210,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) {
|
||||
|
@ -30,10 +30,6 @@
|
||||
#define EMSCRIPTEN
|
||||
#endif
|
||||
|
||||
#ifndef CAP_ORIENTATION
|
||||
#define CAP_ORIENTATION 1
|
||||
#endif
|
||||
|
||||
#ifdef FAKEWEB
|
||||
namespace hr { void mainloopiter(); }
|
||||
template<class A, class B, class C> void emscripten_set_main_loop(A a, B b, C c) { while(true) mainloopiter(); }
|
||||
|
328
hypgraph.cpp
328
hypgraph.cpp
@ -8,21 +8,20 @@
|
||||
#include "hyper.h"
|
||||
namespace hr {
|
||||
|
||||
ld ghx, ghy, ghgx, ghgy;
|
||||
hyperpoint ghpm = C0;
|
||||
hyperpoint ghxy, ghgxy, 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) {
|
||||
if(hypot(ret[0]-ghx, ret[1]-ghy) < hypot(ghgx-ghx, ghgy-ghy)) {
|
||||
ghpm = H; ghgx = ret[0]; ghgy = ret[1];
|
||||
if(hypot_d(2, ret-ghxy) < hypot_d(2, ghgxy-ghxy)) {
|
||||
ghpm = H; ghgxy = ret;
|
||||
}
|
||||
}
|
||||
|
||||
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 +36,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 +58,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 +71,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 +87,49 @@ 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;
|
||||
hyperpoint hxy = point3(hx, hy, 0);
|
||||
|
||||
if(pmodel) {
|
||||
ghx = hx, ghy = hy;
|
||||
return ghpm;
|
||||
ghxy = hxy;
|
||||
|
||||
transmatrix T = rgpushxto0(ghpm);
|
||||
|
||||
auto distance_at = [&] (const transmatrix& T1) {
|
||||
hyperpoint h1;
|
||||
applymodel(tC0(T1), h1);
|
||||
return sqhypot_d(2, hxy - h1);
|
||||
};
|
||||
|
||||
ld best = distance_at(T);
|
||||
|
||||
for(int it=0; it<50; it++)
|
||||
for(int s=0; s<4; s++) {
|
||||
transmatrix T1 = T * spin(s * quarter_circle) * xpush(pow(1.2, -it));
|
||||
ld dist = distance_at(T1);
|
||||
if(dist < best) best = dist, T = T1;
|
||||
if(mdBandAny()) {
|
||||
band_shift += 2 * M_PI;
|
||||
dist = distance_at(T1);
|
||||
if(dist < best) best = dist, T = T1;
|
||||
band_shift -= 4 * M_PI;
|
||||
dist = distance_at(T1);
|
||||
if(dist < best) best = dist, T = T1;
|
||||
band_shift += 2 * M_PI;
|
||||
}
|
||||
}
|
||||
|
||||
return tC0(T);
|
||||
}
|
||||
|
||||
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 +192,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 +264,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 +291,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 +342,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 +364,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 +387,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 +413,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 +427,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 +450,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 +462,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 +513,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 +551,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 +559,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 +574,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 +592,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 +602,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 +631,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 +645,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 +656,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 +664,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 +709,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 +773,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 +796,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 +841,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 +850,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 +860,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 +880,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 +898,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 +957,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 +977,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 +1030,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 +1067,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 +1085,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 +1219,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;
|
||||
@ -1251,6 +1279,24 @@ void hrmap_standard::draw() {
|
||||
}
|
||||
}
|
||||
|
||||
EX bool keep_vertical() {
|
||||
if(CAP_ORIENTATION) return false;
|
||||
if((WDIM == 2 || prod) && GDIM == 3 && vid.fixed_yz) return true;
|
||||
if(downseek.qty) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
EX hyperpoint vertical_vector() {
|
||||
auto& ds = downseek;
|
||||
if((WDIM == 2 || prod) && GDIM == 3 && vid.fixed_yz)
|
||||
return get_view_orientation() * ztangent(1);
|
||||
else if(ds.qty && prod)
|
||||
return get_view_orientation() * product::inverse_exp(ds.point);
|
||||
else if(ds.qty)
|
||||
return ds.point;
|
||||
return C0;
|
||||
}
|
||||
|
||||
EX void spinEdge(ld aspd) {
|
||||
ld downspin = 0;
|
||||
auto& ds = downseek;
|
||||
@ -1271,33 +1317,20 @@ EX void spinEdge(ld aspd) {
|
||||
downspin = atan2(H[1], H[0]);
|
||||
downspin += vid.fixed_facing_dir * degree;
|
||||
if(flipplayer) downspin += M_PI;
|
||||
while(downspin < -M_PI) downspin += 2*M_PI;
|
||||
while(downspin > +M_PI) downspin -= 2*M_PI;
|
||||
cyclefix(downspin, 0);
|
||||
aspd = (1 + 2 * abs(downspin)) * aspd;
|
||||
}
|
||||
else if((WDIM == 2 || prod) && GDIM == 3 && vid.fixed_yz && !CAP_ORIENTATION) {
|
||||
aspd = 999999;
|
||||
auto& vo = get_view_orientation();
|
||||
// does not work well (also need change auto& to auto)
|
||||
// if(hybri && !prod) vo = vo * inverse(nisot::translate(tC0(vo)));
|
||||
else if(keep_vertical()) {
|
||||
hyperpoint h = vertical_vector();
|
||||
downspin = -atan2(h[0], h[1]);
|
||||
if(ds.qty && GDIM == 2) {
|
||||
downspin += models::rotation * degree;
|
||||
}
|
||||
if(ds.qty) {
|
||||
auto sdp = ds.point;
|
||||
if(prod) sdp = vo * product::inverse_exp(sdp);
|
||||
if(sdp[0])
|
||||
downspin = models::rotation * degree - atan2(sdp[0], sdp[1]);
|
||||
cyclefix(downspin, 0);
|
||||
downspin = downspin * min(ds.speed, (double)1);
|
||||
}
|
||||
else {
|
||||
if(vo[0][2])
|
||||
downspin = -atan2(vo[0][2], vo[1][2]);
|
||||
}
|
||||
}
|
||||
else if(ds.qty) {
|
||||
downspin = atan2(ds.point[1], ds.point[0]);
|
||||
downspin -= M_PI/2;
|
||||
downspin += models::rotation * degree;
|
||||
while(downspin < -M_PI) downspin += 2*M_PI;
|
||||
while(downspin > +M_PI) downspin -= 2*M_PI;
|
||||
downspin = downspin * min(ds.speed, (double)1);
|
||||
else aspd = 999999;
|
||||
}
|
||||
if(downspin > aspd) downspin = aspd;
|
||||
if(downspin < -aspd) downspin = -aspd;
|
||||
@ -1505,8 +1538,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 +1550,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 +1595,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 +1606,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 +1625,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 +1635,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 +1654,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 +1670,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 +1683,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 +1697,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 +1781,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 +1801,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 +1827,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 +1864,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 +1925,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 +1938,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 +1952,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 +1965,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 +2049,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 +2058,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 +2110,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 +2118,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;
|
||||
@ -2082,21 +2136,21 @@ EX transmatrix& get_view_orientation() {
|
||||
return prod ? NLP : View;
|
||||
}
|
||||
|
||||
EX hookset<bool(const transmatrix&)> *hooks_rotate_view;
|
||||
EX hookset<bool(const hyperpoint&)> *hooks_shift_view;
|
||||
EX hookset<bool(const transmatrix&)> hooks_rotate_view;
|
||||
EX hookset<bool(const hyperpoint&)> hooks_shift_view;
|
||||
|
||||
/** rotate the view using the given rotation matrix */
|
||||
EX void rotate_view(transmatrix T) {
|
||||
if(callhandlers(false, hooks_rotate_view, T)) return;
|
||||
transmatrix& which = get_view_orientation();
|
||||
which = T * which;
|
||||
if(!prod && !nonisotropic) current_display->which_copy = T * current_display->which_copy;
|
||||
if(!prod && !nonisotropic && !rug::rugged) current_display->which_copy = T * current_display->which_copy;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
if(!nonisotropic && !stretch::in()) {
|
||||
return rgpushxto0(direct_exp(lp_iapply(H))) * V;
|
||||
}
|
||||
else if(!nisot::geodesic_movement) {
|
||||
transmatrix IV = inverse(V);
|
||||
@ -2115,7 +2169,7 @@ EX void shift_view(hyperpoint H) {
|
||||
auto oView = View;
|
||||
View = get_shift_view_of(H, View);
|
||||
auto& wc = current_display->which_copy;
|
||||
if(nonisotropic) {
|
||||
if(nonisotropic || stretch::in()) {
|
||||
transmatrix ioldv = eupush(tC0(inverse(oView)));
|
||||
transmatrix newv = inverse(eupush(tC0(inverse(View))));
|
||||
wc = newv * ioldv * wc;
|
||||
@ -2132,7 +2186,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 +2195,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);
|
||||
@ -595,7 +588,7 @@ EX namespace inv {
|
||||
displaystr(vid.xres/2, vid.yres - vid.fsize*6, 2, vid.fsize, osminfo(which), icol, 8);
|
||||
}
|
||||
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
string hot = XLAT1("Hotkey: "); hot += getcstat;
|
||||
displaystr(vid.xres/2, vid.yres - vid.fsize*5, 2, vid.fsize, hot, icol, 8);
|
||||
#endif
|
||||
@ -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
|
||||
|
||||
|
@ -467,7 +467,7 @@ EX void gainItem(eItem it) {
|
||||
if(chaosmode && gold() >= 300)
|
||||
achievement_gain_once("CHAOS", rg::chaos);
|
||||
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
if(g < lastsafety + R30*3/2 && g2 >= lastsafety + R30*3/2)
|
||||
addMessage(XLAT("The Orb of Safety from the Land of Eternal Motion might save you."));
|
||||
#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:
|
||||
@ -2752,6 +2755,8 @@ EX void set_land_for_geometry(cell *c) {
|
||||
}
|
||||
|
||||
EX void setdist(cell *c, int d, cell *from) {
|
||||
|
||||
if(fake::in()) return FPIU(setdist(c, d, from));
|
||||
|
||||
if(c->mpdist <= d) return;
|
||||
if(c->mpdist > d+1 && d < BARLEV) setdist(c, d+1, from);
|
||||
@ -2911,7 +2916,7 @@ EX void setdist(cell *c, int d, cell *from) {
|
||||
|
||||
// the number of tiles in the standard geometry has about 7553 digits!
|
||||
int gdist = abs(c->master->distance);
|
||||
if(gdist > global_distance_limit) {
|
||||
if(gdist > global_distance_limit && hyperbolic) {
|
||||
gdist -= global_distance_limit;
|
||||
if(d == 8 && hrand(100) < gdist) {
|
||||
if(!isMultitile(c)) c->monst = moNone;
|
||||
|
@ -276,7 +276,7 @@ EX bool createOnSea(eLand old) {
|
||||
(old == laOcean && (chaosmode ? hrand(2) : !generatingEquidistant));
|
||||
}
|
||||
|
||||
EX hookset<eLand(eLand)> *hooks_nextland;
|
||||
EX hookset<eLand(eLand)> hooks_nextland;
|
||||
|
||||
EX eLand getNewLand(eLand old) {
|
||||
|
||||
|
34
langen.cpp
34
langen.cpp
@ -31,8 +31,13 @@ const char *escape(std::string s, const std::string& dft);
|
||||
template<class T> struct dictionary {
|
||||
std::map<std::string, T> m;
|
||||
void add(const std::string& s, T val) {
|
||||
if(m.count(s)) add(s + " [repeat]", std::move(val));
|
||||
else m[s] = std::move(val);
|
||||
auto it = m.find(s);
|
||||
if (it == m.end()) {
|
||||
m.emplace(s, std::move(val));
|
||||
}
|
||||
else if (val != it->second) {
|
||||
printf("// #warning Two translations for %s\n", escape(s, s));
|
||||
}
|
||||
}
|
||||
T& operator [] (const std::string& s) { return m[s]; }
|
||||
int count(const std::string& s) const { return m.count(s); }
|
||||
@ -53,6 +58,12 @@ struct noun {
|
||||
std::string nom, nomp, acc, abl;
|
||||
noun() = default;
|
||||
noun(const noun2& n) : genus(n.genus), nom(n.nom), nomp(n.nomp), acc(n.acc), abl(n.abl) {}
|
||||
friend bool operator==(const noun& a, const noun& b) {
|
||||
return std::tie(a.genus, a.nom, a.nomp, a.acc, a.abl) == std::tie(b.genus, b.nom, b.nomp, b.acc, b.abl);
|
||||
}
|
||||
friend bool operator!=(const noun& a, const noun& b) {
|
||||
return std::tie(a.genus, a.nom, a.nomp, a.acc, a.abl) != std::tie(b.genus, b.nom, b.nomp, b.acc, b.abl);
|
||||
}
|
||||
};
|
||||
|
||||
dictionary<noun> nouns[NUMLAN];
|
||||
@ -93,14 +104,7 @@ typedef unsigned hashcode;
|
||||
|
||||
hashcode hashval;
|
||||
|
||||
bool isrepeat(const std::string& s) {
|
||||
return s.find(" [repeat]") != std::string::npos;
|
||||
}
|
||||
|
||||
hashcode langhash(const std::string& s) {
|
||||
if(isrepeat(s)) {
|
||||
return langhash(s.substr(0, s.size() - 9)) + 1;
|
||||
}
|
||||
hashcode r = 0;
|
||||
for (char ch : s) r = hashval * r + ch;
|
||||
return r;
|
||||
@ -265,13 +269,11 @@ void compute_completeness(const T& dict)
|
||||
else
|
||||
mis1 += which;
|
||||
}
|
||||
if(mis != "" && !isrepeat(elt))
|
||||
if(mis != "")
|
||||
printf("// #warning Missing [%s/%s]: %s\n", mis.c_str(), mis1.c_str(), escape(elt, "?"));
|
||||
|
||||
if(!isrepeat(elt)) {
|
||||
completeness[0]++;
|
||||
for(int i=1; i<NUMLAN; i++) if(dict[i].count(elt)) completeness[i]++;
|
||||
}
|
||||
completeness[0]++;
|
||||
for(int i=1; i<NUMLAN; i++) if(dict[i].count(elt)) completeness[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,11 +391,9 @@ int main() {
|
||||
|
||||
for(auto&& elt : ms) {
|
||||
const std::string& s = elt.second;
|
||||
if(isrepeat(s)) printf("#if REPEATED\n");
|
||||
printf(" {0x%x, { // %s\n", elt.first, escape(s, s));
|
||||
for(int i=1; i<NUMLAN; i++) printf(" %s,\n", escape(d[i][s], s));
|
||||
printf(" }},\n");
|
||||
if(isrepeat(s)) printf("#endif\n");
|
||||
}
|
||||
printf(" };\n\n");
|
||||
|
||||
@ -401,7 +401,6 @@ int main() {
|
||||
|
||||
for(auto&& elt : mn) {
|
||||
const std::string& s = elt.second;
|
||||
if(isrepeat(s)) printf("#if REPEATED\n");
|
||||
printf(" {0x%x, %d, { // \"%s\"\n", elt.first,
|
||||
(nothe.count(s) ? 1:0) + (plural.count(s) ? 2:0),
|
||||
escape(s, s));
|
||||
@ -415,7 +414,6 @@ int main() {
|
||||
}
|
||||
|
||||
printf(" }},\n");
|
||||
if(isrepeat(s)) printf("#endif\n");
|
||||
}
|
||||
|
||||
printf(" };\n");
|
||||
|
@ -510,10 +510,10 @@ S(
|
||||
"nebo získat informace o objektech na mapě). Také se můžeš dotknout zobrazených čísel, "
|
||||
"abys zjistil jejich význam.\n")
|
||||
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. "
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Space. "
|
||||
"To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n",
|
||||
"Pohybuješ se pomocí myši, numerické klávesnice, kláves qweadzxc nebo kláves hjklyubn. Klávesy 's' nebo '.' ti umožňují čekat na místě. "
|
||||
"Šipky, klávesy PgUp/PgDn a Home nebo mezerník ti umožňují otáčet svět. Nastavení můžeš otevřít klávesou 'v', úkoly a menu klávesou ESC.\n\n")
|
||||
"Šipky, klávesy PgUp/PgDn a mezerník ti umožňují otáčet svět. Nastavení můžeš otevřít klávesou 'v', úkoly a menu klávesou ESC.\n\n")
|
||||
|
||||
S("See more on the website: ", "Více informací najdeš na webové stránce: ")
|
||||
|
||||
@ -4587,11 +4587,11 @@ S(
|
||||
"are not about points on the ground level, but "
|
||||
"about the matching points on the plane P -- "
|
||||
"divide them by the factor above to get actual "
|
||||
"distances.",
|
||||
"distances.)",
|
||||
|
||||
"(Vzdálenosti v editoru vektorové "
|
||||
"grafiky nejsou vzdálenosti bodů na úrovni země, ale odpovídajících bodů v rovině "
|
||||
"P -- skutečné vzdálenosti získáte jejich vydělením výše zmíněným faktorem.")
|
||||
"P -- skutečné vzdálenosti získáte jejich vydělením výše zmíněným faktorem.)")
|
||||
|
||||
S( "If we are viewing an equidistant g absolute units below a plane, "
|
||||
"from a point c absolute units above the plane, this corresponds "
|
||||
@ -6146,7 +6146,7 @@ S("would be destroyed in %the1", "by%l1by zničen%1 %abl1")
|
||||
S(" to go cold", " vychladnout")
|
||||
S("%The1 is destroyed by lava!", "Láva zničila %a1!")
|
||||
S("%The1 is killed by lava!", "Láva zabila %a1!")
|
||||
S("Run away from the lava!", "Utíkej od lávy!")
|
||||
S("Run away from the magma!", "Utíkej od lávy!")
|
||||
|
||||
// Terracotta Army
|
||||
//-----------------
|
||||
@ -6693,7 +6693,7 @@ N("Chrysoberyl", GEN_O, "Chryzoberyl", "Chryzoberyly", "Chryzoberyl", "Chryzober
|
||||
S("Fragment of the past glory.", "Fragment minulé slávy.")
|
||||
|
||||
N("Red Raider", GEN_M, "Èervený nájezdník", "Èervení nájezdníci", "Èerveného nájezdníka", "Èerveným nájezdníkem")
|
||||
S("Red Raiders travel in pairs. They have promised to always watch another one's back. They are able to destroy walls on their way",
|
||||
S("Red Raiders travel in pairs. They have promised to always watch each other's backs. They are able to destroy walls on their way.",
|
||||
"Èervení nájezdníci cestují ve dvojicích. Slíbili si, že si vždycky budou navzájem "
|
||||
"hlídat záda. Po cestì mohou nièit zdi.")
|
||||
|
||||
@ -7682,7 +7682,7 @@ S("A large bug native to the Brown Islands. Cannot be killed easily due to their
|
||||
|
||||
N("Acid Gull", GEN_M, "Kyselinoracek", "Kyselinorackové", "Kyselinoracka", "Kyselinorackem")
|
||||
|
||||
S("Where did this strange bird come from?...\n\n Acid Gulls dissolve the land on which they fall when they die. ",
|
||||
S("Where did this strange bird come from?...\n\nAcid Gulls dissolve the land on which they fall when they die. ",
|
||||
|
||||
"Kde se tu vzal tenhle podivný pták...?\n\nKdyž Kyselinoracek zemře, rozpustí terén, na který dopadne.")
|
||||
|
||||
@ -7767,7 +7767,7 @@ S("These guys look a bit strange, but they have no special properties.",
|
||||
|
||||
N("Torbernite", GEN_O, "Torbernit", "Torbernity", "Torbernit", "Torbernitem")
|
||||
|
||||
S("Crystals emiting magical radiation.", "Drahokamy vyzařující prospěšnou magickou radiaci.")
|
||||
S("Crystals emitting magical radiation.", "Drahokamy vyzařující prospěšnou magickou radiaci.")
|
||||
|
||||
N("fire trap", GEN_F, "ohnivá past", "ohnivé pasti", "ohnivou past", "ohnivou pastí")
|
||||
|
||||
@ -7845,7 +7845,7 @@ S(
|
||||
|
||||
N("Torbernite", GEN_O, "Torbernit", "Torbernity", "Torbernit", "Torbernitem")
|
||||
|
||||
S("Crystals emiting magical radiation.", "Krystaly vyzařující magickou radiaci.")
|
||||
S("Crystals emitting magical radiation.", "Krystaly vyzařující magickou radiaci.")
|
||||
|
||||
// other things:
|
||||
|
||||
@ -7936,7 +7936,7 @@ S("Crystal", "Krystal")
|
||||
|
||||
#define Cell(x) \
|
||||
S(x "-cell", x "-nadstěn") \
|
||||
S(x "-cell (elliptic space", x "-nadstěn (eliptický prostor)")
|
||||
S(x "-cell (elliptic space)", x "-nadstěn (eliptický prostor)")
|
||||
|
||||
Cell("{3,3,3} 5") Cell("{4,3,3} 8") Cell("{3,3,4} 16") Cell("{3,4,3} 24") Cell("{5,3,3} 120") Cell("{3,3,5} 600")
|
||||
#undef Cell
|
||||
@ -8408,7 +8408,7 @@ S("Hint: this is more playable with pure {7,3} or pure {5,4}", "Nápověda: toto
|
||||
|
||||
S("view the underlying geometry", "zobraz základní geometrii")
|
||||
|
||||
S("The space you are currently in the space of rotations of the underlying hyperbolic or spherical geometry. ",
|
||||
S("The space you are currently in is the space of rotations of the underlying hyperbolic or spherical geometry. ",
|
||||
"Prostor, ve kterém se právě nacházíš, je prostorem rotací základní hyperbolické nebo sférické geometrie. ")
|
||||
|
||||
S("This option lets you see the underlying space. Lands and some walls (e.g. in the Graveyard) are based on "
|
||||
|
@ -488,8 +488,8 @@ S("Usually, you move by touching somewhere on the map; you can also touch one "
|
||||
"vier Knöpfe in den Ecken antippen um dies zu ändern (um die Karte zu scrollen oder Infos "
|
||||
"über Objekte zu bekommen). Du kannst auch die Zahlen antippen um ihre Bedeutung zu erfahren.\n")
|
||||
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n",
|
||||
"Bewege dich mit der Maus, dem Numpad, qweadzxc, oder hjklyubn. Warte mit 's' oder '.'. Drehe die Welt mit den Pfeiltasten, Bild auf/ab und Pos1/Space. " // FIXME: Leertaste?
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Space. To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n",
|
||||
"Bewege dich mit der Maus, dem Numpad, qweadzxc, oder hjklyubn. Warte mit 's' oder '.'. Drehe die Welt mit den Pfeiltasten, Bild auf/ab und Space. " // FIXME: Leertaste?
|
||||
"Um zu speichern, benötigst du einen Orb der Geborgenheit. Drücke V für Einstellungen, ESC für den Quest-Status und das Menü.\n\n")
|
||||
|
||||
S("See more on the website: ", "Mehr auf der Website: ")
|
||||
|
@ -482,10 +482,10 @@ S(
|
||||
"zdobyć informacje). Możesz też dotknąć liczb na ekranie, by poznać ich "
|
||||
"znaczenie.\n")
|
||||
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. "
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Space. "
|
||||
"To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n",
|
||||
"Ruszasz się myszą, klawiaturą numeryczną, qweadzxc, lub hjklyubn. Czekasz naciskając 's' lub '.'. "
|
||||
"Obracasz świat strzałkami, PgUp/Dn, lub Home/Space. Naciśnij 'v' by przejść do menu (konfiguracja, tryby specjalne itd.), ESC "
|
||||
"Obracasz świat strzałkami, PgUp/Dn, lub Space. Naciśnij 'v' by przejść do menu (konfiguracja, tryby specjalne itd.), ESC "
|
||||
"by zobaczyć stan misji.\n\n")
|
||||
|
||||
S("See more on the website: ", "Więcej na stronie: ")
|
||||
@ -4501,10 +4501,10 @@ S("(Distances reported by the vector graphics editor "
|
||||
"are not about points on the ground level, but "
|
||||
"about the matching points on the plane P -- "
|
||||
"divide them by the factor above to get actual "
|
||||
"distances.",
|
||||
"distances.)",
|
||||
|
||||
"(Odległości wyświetlane przez edytor grafiki "
|
||||
"dotyczą odległości między odpowiednimi punktami na płaszczyźnie P.")
|
||||
"dotyczą odległości między odpowiednimi punktami na płaszczyźnie P.)")
|
||||
|
||||
S( "If we are viewing an equidistant g absolute units below a plane, "
|
||||
"from a point c absolute units above the plane, this corresponds "
|
||||
@ -5057,7 +5057,7 @@ S("firewall lines: Palace", "linie ścian ognia: Pałac")
|
||||
S("firewall lines: Power", "linie ścian ognia: Moc")
|
||||
|
||||
S("(ESC) tour menu", "(ESC) menu ucznia")
|
||||
S("Try the Guided tour to help with understanding the "
|
||||
S("Try the Guided Tour to help with understanding the "
|
||||
"geometry of HyperRogue (menu -> special modes).\n\n",
|
||||
"Uruchom Wycieczkę, by zrozumieć geometrię HyperRogue (menu -> tryby specjalne).\n\n")
|
||||
|
||||
@ -6037,7 +6037,7 @@ S("would be destroyed in %the1", "by%ł1by zniszczon%y1 %abl1")
|
||||
S(" to go cold", " by ostygnąć")
|
||||
S("%The1 is destroyed by lava!", "%The1 jest zniszczon%y1 przez lawę!")
|
||||
S("%The1 is killed by lava!", "%The1 jest zabit%y1 przez lawę!")
|
||||
S("Run away from the lava!", "Uciekaj od lawy!")
|
||||
S("Run away from the magma!", "Uciekaj od lawy!")
|
||||
|
||||
// Terracotta Army
|
||||
//-----------------
|
||||
@ -6535,7 +6535,7 @@ N("Chrysoberyl", GEN_O, "Chryzoberyl", "Chryzoberyle", "Chryzoberyl", "Chryzober
|
||||
S("Fragment of the past glory.", "Fragment dawnej chwały.")
|
||||
|
||||
N("Red Raider", GEN_M, "Czerwony Najeźdźca", "Czerwoni Najeźdźcy", "Czerwonego Najeźdźcę", "Czerwonym Najeźdźcą")
|
||||
S("Red Raiders travel in pairs. They have promised to always watch another one's back. They are able to destroy walls on their way",
|
||||
S("Red Raiders travel in pairs. They have promised to always watch each other's backs. They are able to destroy walls on their way.",
|
||||
"Czerwoni Najeźdźcy podróżują parami. Obiecali sobie nawzajem, że zawsze będą chronić swoje tyły. Mogą niszczyć ściany na swojej drodze.")
|
||||
|
||||
N("Gray Raider", GEN_M, "Szary Najeźdźca", "Szarzy Najeźdźcy", "Szarego Najeźdźcę", "Szarym Najeźdźcą")
|
||||
@ -7429,7 +7429,7 @@ S("A large bug native to the Brown Islands. Cannot be killed easily due to their
|
||||
|
||||
N("Acid Gull", GEN_F, "Kwaśna Mewa", "Kwaśne Mewy", "Kwaśną Mewę", "Kwaśną Mewą")
|
||||
|
||||
S("Where did this strange bird come from?...\n\n Acid Gulls dissolve the land on which they fall when they die. ",
|
||||
S("Where did this strange bird come from?...\n\nAcid Gulls dissolve the land on which they fall when they die. ",
|
||||
|
||||
"Skąd się wziął ten dziwny ptak?...\n\nKwaśne Mewy rozpuszczają ląd, na który spadają, gdy zostaną zabite. ")
|
||||
|
||||
@ -7572,7 +7572,7 @@ S(
|
||||
|
||||
N("Torbernite", GEN_O, "Torbernit", "Torbernity", "Torbernit", "Torbernitem")
|
||||
|
||||
S("Crystals emiting magical radiation.", "Te kryształy emitują magiczne promieniowanie.")
|
||||
S("Crystals emitting magical radiation.", "Te kryształy emitują magiczne promieniowanie.")
|
||||
|
||||
// other things:
|
||||
|
||||
@ -7661,7 +7661,7 @@ S("Crystal", "Kryształ")
|
||||
|
||||
#define Cell(x) \
|
||||
S(x "-cell", x "-komórka") \
|
||||
S(x "-cell (elliptic space", x "-komórka (przestrzeń eliptyczna)")
|
||||
S(x "-cell (elliptic space)", x "-komórka (przestrzeń eliptyczna)")
|
||||
|
||||
Cell("{3,3,3} 5") Cell("{4,3,3} 8") Cell("{3,3,4} 16") Cell("{3,4,3} 24") Cell("{5,3,3} 120") Cell("{3,3,5} 600")
|
||||
#undef Cell
|
||||
|
@ -4579,7 +4579,7 @@ S("Ground level is actually an equidistant surface, "
|
||||
"are not about points on the ground level, but "
|
||||
"about the matching points on the plane P -- "
|
||||
"divide them by the factor above to get actual "
|
||||
"distances.",
|
||||
"distances.)",
|
||||
|
||||
"Poziom podłoża jest w rzeczywistości ekwidystantną powierzchnią "
|
||||
"%1 jednostek pod płaszczyzną P. Teoretycznie, ta wartość "
|
||||
@ -4587,7 +4587,7 @@ S("Ground level is actually an equidistant surface, "
|
||||
"szybciej latając powyżej poziomu podłoża, na wysokości płaszczyzny "
|
||||
"P -- ale nie wpływa to na mechanikę gry w żaden sposób. "
|
||||
"(Odległości wyświetlane przez edytor grafiki "
|
||||
"dotyczą odległości między odpowiednimi punktami na płaszczyźnie P.")
|
||||
"dotyczą odległości między odpowiednimi punktami na płaszczyźnie P.)")
|
||||
|
||||
S( "If we are viewing an equidistant g absolute units below a plane, "
|
||||
"from a point c absolute units above the plane, this corresponds "
|
||||
|
@ -484,10 +484,10 @@ S(
|
||||
"информацию про объекты. Кликая по изображаемым числам, можно смотреть, "
|
||||
"что они означают.\n")
|
||||
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. "
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Space. "
|
||||
"To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n",
|
||||
"Двигайтесь с помощью мышки, нумпада, qweadzxc или hjklyubn. Ждите, нажимая 's' или '.'. "
|
||||
"Поворачивайте карту стрелками, PageUp/Down или Home/Space. "
|
||||
"Поворачивайте карту стрелками, PageUp/Down или Space. "
|
||||
"Чтобы сохраниться, Вам нужна сфера безопасности. Нажмите 'v' для настроек, Esc для статуса квеста или меню.")
|
||||
|
||||
S("See more on the website: ", "Смотрите далее на сайте: ")
|
||||
@ -4676,7 +4676,7 @@ S("(Distances reported by the vector graphics editor "
|
||||
"are not about points on the ground level, but "
|
||||
"about the matching points on the plane P -- "
|
||||
"divide them by the factor above to get actual "
|
||||
"distances.",
|
||||
"distances.)",
|
||||
|
||||
"(Расстояния в редакторе векторной графики относятся"
|
||||
"не к точкам на поверхности, а к их проекциям на плоскость P.)")
|
||||
@ -6220,7 +6220,7 @@ S("would be destroyed in %the1", "будет уничтожено %abl1")
|
||||
S(" to go cold", " чтобы остыть")
|
||||
S("%The1 is destroyed by lava!", "%1 уничтожен%E1 лавой!")
|
||||
S("%The1 is killed by lava!", "%1 убит%E1 лавой!")
|
||||
S("Run away from the lava!", "Беги из лавы!")
|
||||
S("Run away from the magma!", "Беги из лавы!")
|
||||
|
||||
// Terracotta Army
|
||||
//-----------------
|
||||
@ -6760,7 +6760,7 @@ N("Chrysoberyl", GEN_O, "Хризоберилл", "Хризобериллы", "
|
||||
S("Fragment of the past glory.", "Фрагмент былой славы.")
|
||||
|
||||
N("Red Raider", GEN_M, "Красный Рейдер", "Красные Рейдеры", "Красного Рейдера", "Красным Рейдером")
|
||||
S("Red Raiders travel in pairs. They have promised to always watch another one's back. They are able to destroy walls on their way",
|
||||
S("Red Raiders travel in pairs. They have promised to always watch each other's backs. They are able to destroy walls on their way.",
|
||||
"Красные рейдеры путешествуют парами. Они обещали, что будут защищать спины друг друга. Они могут разрушать стены на своем пути.")
|
||||
|
||||
N("Gray Raider", GEN_M, "Серый Рейдер", "Серые Рейдеры", "Серого Рейдера", "Серым Рейдером")
|
||||
|
@ -459,10 +459,10 @@ S(
|
||||
"Normalde haritada bir yere dokunarak hareket edersin, haritanın dört köşesindeki tuşlara dokunarak bunu değiştirebilirsin."
|
||||
" (haritayı çevirmek ya da haritadaki nesneler hakkında bilgi almak için). Gösterilen numaralara dokunarak da anlamlarını görebilirsin. \n")
|
||||
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. "
|
||||
S("Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Space. "
|
||||
"To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n",
|
||||
"Fareyle, sayı tuşlarıyla, qweadzxc ile, veya hjklyubn ile hareket et. 's' ya da '.' ile bekle. "
|
||||
"Oklarla, PageUp/Down ile veya Home/Space ile dünyayı çevirebilirsin. Oyunu kaydetmek için Güvenlik Küresine ihtiyacın var. Ayarlar için 'v'ye görev durumu ve menü için 'ESC'ye bas.\n\n")
|
||||
"Oklarla, PageUp/Down ile veya Space ile dünyayı çevirebilirsin. Oyunu kaydetmek için Güvenlik Küresine ihtiyacın var. Ayarlar için 'v'ye görev durumu ve menü için 'ESC'ye bas.\n\n")
|
||||
|
||||
S("See more on the website: ", "Daha fazlasını websitesinde görüntüleyin: ")
|
||||
|
||||
|
@ -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;
|
||||
|
552
mapeditor.cpp
552
mapeditor.cpp
@ -10,12 +10,288 @@ 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 dttext : dtshape {
|
||||
hyperpoint where;
|
||||
ld size;
|
||||
string caption;
|
||||
|
||||
void rotate(const transmatrix& T) override {
|
||||
where = T * where;
|
||||
}
|
||||
|
||||
void save(hstream& hs) override {
|
||||
hs.write<char>(4);
|
||||
hs.write(where);
|
||||
hs.write(size);
|
||||
hs.write(caption);
|
||||
}
|
||||
|
||||
dtshape *load(hstream& hs) override {
|
||||
hs.read(where);
|
||||
hs.read(size);
|
||||
hs.read(caption);
|
||||
return this;
|
||||
}
|
||||
|
||||
void draw(const transmatrix& V) override {
|
||||
queuestr(V * rgpushxto0(where), size, caption, col);
|
||||
}
|
||||
|
||||
ld distance(hyperpoint h) override {
|
||||
return hdist(h, where);
|
||||
}
|
||||
};
|
||||
|
||||
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 clear_dtshapes() { dtshapes.clear(); }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
EX void dt_add_text(hyperpoint h, ld size, string cap) {
|
||||
cell *b = centerover;
|
||||
|
||||
h = inverse(ggmatrix(b)) * h;
|
||||
virtualRebase(b, h);
|
||||
|
||||
auto l = new dttext;
|
||||
l->where = h;
|
||||
l->size = size;
|
||||
l->caption = cap;
|
||||
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 };
|
||||
@ -33,26 +309,20 @@ EX namespace mapeditor {
|
||||
EX editwhat ew, ewsearch;
|
||||
EX bool autochoose = ISMOBILE;
|
||||
|
||||
EX void scaleall(ld z) {
|
||||
EX void scaleall(ld z, bool keep_mouse) {
|
||||
|
||||
// (mx,my) = (xcb,ycb) + ss * (xpos,ypos) + (mrx,mry) * scale
|
||||
|
||||
// (mrx,mry) * (scale-scale') =
|
||||
// ss * ((xpos',ypos')-(xpos,ypos))
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
if(keep_mouse) {
|
||||
ld mrx = (.0 + mousex - current_display->xcenter) / vpconf.scale;
|
||||
ld mry = (.0 + mousey - current_display->ycenter) / vpconf.scale;
|
||||
|
||||
if(vid.xres > vid.yres) {
|
||||
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 +371,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 +628,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 +812,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 +1037,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 +1290,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 +1416,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 +1500,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 +1515,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 +1544,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 +1559,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 +1676,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 +1687,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 +1735,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 +1782,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 +1818,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 +1844,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 +2253,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 +2344,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 +2402,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 +2427,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;
|
||||
@ -2128,7 +2504,7 @@ namespace mapeditor {
|
||||
}
|
||||
#endif
|
||||
|
||||
auto hooks = addHook(clearmemory, 0, [] () {
|
||||
auto hooks = addHook(hooks_clearmemory, 0, [] () {
|
||||
if(mapeditor::painttype == 4)
|
||||
mapeditor::painttype = 0, mapeditor::paintwhat = 0,
|
||||
mapeditor::paintwhat_str = "clear monster";
|
||||
@ -2137,6 +2513,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 +2539,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 +2549,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 +2588,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2408,6 +2786,14 @@ int read_editor_args() {
|
||||
if(argis("-lev")) { shift(); levelfile = args(); }
|
||||
else if(argis("-pic")) { shift(); picfile = args(); }
|
||||
else if(argis("-load")) { PHASE(3); shift(); mapstream::loadMap(args()); }
|
||||
else if(argis("-d:draw")) { PHASE(3);
|
||||
#if CAP_EDIT
|
||||
start_game();
|
||||
mapeditor::drawing_tool = true;
|
||||
mapeditor::initdraw(cwt.at);
|
||||
launch_dialog(mapeditor::showDrawEditor);
|
||||
#endif
|
||||
}
|
||||
#if CAP_POLY
|
||||
else if(argis("-picload")) { PHASE(3); shift(); mapeditor::loadPicFile(args()); }
|
||||
#endif
|
||||
|
66
menus.cpp
66
menus.cpp
@ -230,7 +230,7 @@ EX void showMainMenu() {
|
||||
dialog::addItem(XLAT(inSpecialMode() ? "reset special modes" : "back to the start menu"), 'R');
|
||||
|
||||
string q;
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
dialog::addItem(XLAT("visit the website"), 'q');
|
||||
#else
|
||||
q = quitsaves() ? "save" : "quit";
|
||||
@ -248,7 +248,7 @@ EX void showMainMenu() {
|
||||
if(inv::on)
|
||||
dialog::addItem(XLAT("inventory"), 'i');
|
||||
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
#if CAP_ACHIEVE
|
||||
dialog::addItem(XLAT("leaderboards/achievements"), '3');
|
||||
#endif
|
||||
@ -305,7 +305,7 @@ EX void showMainMenu() {
|
||||
#endif
|
||||
else if(sym == SDLK_ESCAPE)
|
||||
showMissionScreen();
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
else if(NUMBERKEY == '3') {
|
||||
achievement_final(false);
|
||||
@ -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');
|
||||
@ -382,7 +382,7 @@ EX void enable_cheat() {
|
||||
else if(!cheater) dialog::cheat_if_confirmed([] {
|
||||
cheater++;
|
||||
addMessage(XLAT("You activate your demonic powers!"));
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
addMessage(XLAT("Shift+F, Shift+O, Shift+T, Shift+L, Shift+U, etc."));
|
||||
#endif
|
||||
popScreen();
|
||||
@ -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;
|
||||
}
|
||||
@ -947,18 +959,22 @@ EX void showStartMenu() {
|
||||
// -- overview --
|
||||
|
||||
#if HDR
|
||||
typedef pair<string, reaction_t> named_functionality;
|
||||
struct named_functionality {
|
||||
std::string first;
|
||||
reaction_t second;
|
||||
explicit named_functionality() = default;
|
||||
explicit named_functionality(std::string s, reaction_t r) : first(std::move(s)), second(std::move(r)) {}
|
||||
friend bool operator==(const named_functionality& a, const named_functionality& b) { return a.first == b.first; }
|
||||
friend bool operator!=(const named_functionality& a, const named_functionality& b) { return a.first != b.first; }
|
||||
};
|
||||
inline named_functionality named_dialog(string x, reaction_t dialog) { return named_functionality(x, [dialog] () { pushScreen(dialog); }); }
|
||||
#endif
|
||||
|
||||
EX hookset<named_functionality()> *hooks_o_key;
|
||||
EX hookset<named_functionality()> hooks_o_key;
|
||||
|
||||
EX named_functionality get_o_key() {
|
||||
|
||||
if(hooks_o_key) for(auto& h: *hooks_o_key) {
|
||||
auto res = h.second();
|
||||
if(res.first != "") return res;
|
||||
}
|
||||
auto res = callhandlers(named_functionality(), hooks_o_key);
|
||||
if (res != named_functionality()) return res;
|
||||
|
||||
#if CAP_DAILY
|
||||
if(daily::on)
|
||||
|
@ -44,7 +44,7 @@ string buildScoreDescription() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
|
||||
int andmode;
|
||||
|
||||
|
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);
|
||||
|
@ -354,8 +354,9 @@ EX int angledist(int t, int d1, int d2) {
|
||||
return dd;
|
||||
}
|
||||
|
||||
EX int angledistButterfly(int t, int d1, int d2) {
|
||||
EX int angledistButterfly(int t, int d1, int d2, bool mirrored) {
|
||||
int dd = d1 - d2;
|
||||
if(mirrored) dd = -dd;
|
||||
while(dd<0) dd += t;
|
||||
return dd;
|
||||
}
|
||||
@ -485,7 +486,7 @@ EX int moveval(cell *c1, cell *c2, int d, flagtype mf) {
|
||||
if(m == moBat && batsAfraid(c2)) return 790;
|
||||
|
||||
if(m == moButterfly)
|
||||
return 1500 + angledistButterfly(c1->type, c1->mondir, d);
|
||||
return 1500 + angledistButterfly(c1->type, c1->mondir, d, c1->monmirror);
|
||||
|
||||
if(m == moRagingBull && c1->mondir != NODIR)
|
||||
return 1500 - bulldist(c2);
|
||||
@ -1410,7 +1411,7 @@ EX cell *lastmountpos[MAXPLAYER];
|
||||
EX void clearshadow() {
|
||||
shpos.resize(SHSIZE);
|
||||
for(int i=0; i<SHSIZE; i++) for(int p=0; p<MAXPLAYER; p++)
|
||||
shpos[p][i] = NULL;
|
||||
shpos[i][p] = NULL;
|
||||
}
|
||||
|
||||
EX void moveshadow() {
|
||||
|
@ -549,7 +549,7 @@ EX void initConfig() {
|
||||
t[(int)'s'] = 16 + 6;
|
||||
t[(int)'a'] = 16 + 7;
|
||||
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
t[SDLK_KP8] = 16 + 4;
|
||||
t[SDLK_KP6] = 16 + 5;
|
||||
t[SDLK_KP2] = 16 + 6;
|
||||
@ -572,7 +572,7 @@ EX void initConfig() {
|
||||
t[(int)'p'] = 32 + 10;
|
||||
t[(int)'['] = 32 + pcCenter;
|
||||
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
t[SDLK_UP] = 48 ;
|
||||
t[SDLK_RIGHT] = 48 + 1;
|
||||
t[SDLK_DOWN] = 48 + 2;
|
||||
@ -973,4 +973,4 @@ EX void handleInput(int delta) {
|
||||
|
||||
EX }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ void gamedata::restoregame() {
|
||||
gamedata_all(*this);
|
||||
}
|
||||
|
||||
EX hookset<void(gamedata*)> *hooks_gamedata;
|
||||
EX hookset<void(gamedata*)> hooks_gamedata;
|
||||
|
||||
EX namespace gamestack {
|
||||
|
||||
|
455
mymake.cpp
455
mymake.cpp
@ -1,223 +1,232 @@
|
||||
// HyperRogue: alternative build system
|
||||
// This reads the file 'hyper.cpp' and compiles the cpp files it includes into separate object files, and then links them.
|
||||
// Tested in Linux, should work in other systems with some changes.
|
||||
|
||||
// Options:
|
||||
// -O2 -- optimize
|
||||
// -O3 -- optimize
|
||||
// -D... -- change compilation flags
|
||||
// [file.cpp] -- add a module to the build (e.g. ./mymake rogueviz)
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string opts;
|
||||
|
||||
string default_standard = " -std=c++11";
|
||||
string standard = default_standard;
|
||||
|
||||
string preprocessor;
|
||||
string compiler;
|
||||
string linker;
|
||||
string libs;
|
||||
|
||||
void set_linux() {
|
||||
preprocessor = "g++ -E";
|
||||
compiler = "g++ -Wall -Wextra -Wno-maybe-uninitialized -Wno-unused-parameter -Wno-implicit-fallthrough -rdynamic -fdiagnostics-color=always -c";
|
||||
linker = "g++ -rdynamic -o hyper";
|
||||
opts = "-DFHS -DLINUX -I/usr/include/SDL";
|
||||
libs = " savepng.o -lSDL -lSDL_ttf -lSDL_mixer -lSDL_gfx -lGLEW -lGL -lpng -rdynamic -lpthread -lz";
|
||||
}
|
||||
|
||||
void set_mac() {
|
||||
preprocessor = "g++ -E";
|
||||
compiler = "g++ -march=native -W -Wall -Wextra -pedantic -Wno-unused-parameter -Wno-implicit-fallthrough -c";
|
||||
linker = "g++ -o hyper";
|
||||
opts = "-DMAC -I/usr/local/include";
|
||||
libs = " savepng.o -L/usr/local/lib -framework AppKit -framework OpenGL -lSDL -lSDLMain -lSDL_gfx -lSDL_mixer -lSDL_ttf -lpng -lpthread -lz";
|
||||
}
|
||||
|
||||
void set_win() {
|
||||
preprocessor = "g++ -E";
|
||||
compiler = "runbat bwin-g.bat -c";
|
||||
linker = "runbat bwin-linker.bat";
|
||||
opts = "-DFHS -DLINUX -I/usr/include/SDL";
|
||||
libs = "";
|
||||
|
||||
standard = "";
|
||||
}
|
||||
|
||||
vector<string> modules;
|
||||
|
||||
time_t get_file_time(const string s) {
|
||||
struct stat attr;
|
||||
if(stat(s.c_str(), &attr)) return 0;
|
||||
return attr.st_mtime;
|
||||
}
|
||||
|
||||
int optimized = 0;
|
||||
|
||||
string obj_dir = "mymake_files";
|
||||
string setdir = "../";
|
||||
|
||||
int system(string cmdline) {
|
||||
return system(cmdline.c_str());
|
||||
}
|
||||
|
||||
bool file_exists(string fname) {
|
||||
return access(fname.c_str(), F_OK) != -1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if defined(MAC)
|
||||
set_mac();
|
||||
#elif defined(WINDOWS)
|
||||
set_win();
|
||||
#else
|
||||
set_linux();
|
||||
#endif
|
||||
for(string fname: {"Makefile.loc", "Makefile.simple", "Makefile"})
|
||||
if(file_exists(fname))
|
||||
system("make -f " + fname + " language-data.cpp autohdr.h savepng.o");
|
||||
for(int i=1; i<argc; i++) {
|
||||
string s = argv[i];
|
||||
if(s.substr(0, 2) == "-D") {
|
||||
opts += " " + s;
|
||||
obj_dir += "/";
|
||||
setdir += "../";
|
||||
for(char c: s)
|
||||
if(c == '=' || c == '-' || c == '/') obj_dir += "_";
|
||||
else obj_dir += c;
|
||||
}
|
||||
else if(s == "-win") {
|
||||
set_win();
|
||||
obj_dir += "/win";
|
||||
setdir += "../";
|
||||
}
|
||||
else if(s == "-mac") {
|
||||
set_mac();
|
||||
obj_dir += "/mac";
|
||||
setdir += "../";
|
||||
}
|
||||
else if(s == "-linux") {
|
||||
set_linux();
|
||||
obj_dir += "/linux";
|
||||
setdir += "../";
|
||||
}
|
||||
else if(s == "-O2")
|
||||
optimized = 2, compiler += " -O2", obj_dir += "/O2", setdir += "../";
|
||||
else if(s == "-O3")
|
||||
optimized = 3, compiler += " -O3", obj_dir += "/O3", setdir += "../";
|
||||
else if(s.substr(0, 4) == "-std")
|
||||
standard = s;
|
||||
else if(s.substr(0, 2) == "-l")
|
||||
linker += " " + s;
|
||||
else if(s == "-I") {
|
||||
opts += " " + s + " " + argv[i+1];
|
||||
i++;
|
||||
}
|
||||
else if(s.substr(0, 2) == "-I")
|
||||
opts += " " + s;
|
||||
else if(s == "-rv") {
|
||||
|
||||
if(standard == default_standard) {
|
||||
standard = "-std=c++17";
|
||||
}
|
||||
ifstream ifs("rogueviz/rogueviz-all.cpp");
|
||||
string s;
|
||||
while(getline(ifs, s)) {
|
||||
if(s.substr(0, 10) == "#include \"") {
|
||||
string t = s.substr(10);
|
||||
t = t.substr(0, t.find(".cpp\""));
|
||||
modules.push_back("rogueviz/" + t);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(s.size() >= 5 && s.substr(s.size() - 4) == ".cpp")
|
||||
s = s.substr(0, s.size() - 4);
|
||||
modules.push_back(s);
|
||||
}
|
||||
}
|
||||
if(!optimized)
|
||||
compiler += " -g3";
|
||||
preprocessor += " " + standard;
|
||||
compiler += " " + standard;
|
||||
ifstream fs("hyper.cpp");
|
||||
|
||||
system("mkdir -p " + obj_dir);
|
||||
|
||||
ofstream fsm(obj_dir + "/hyper.cpp");
|
||||
fsm << "#if REM\n#define INCLUDE(x)\n#endif\n";
|
||||
string s;
|
||||
while(getline(fs, s)) {
|
||||
if(s.substr(0, 8) == "#include") {
|
||||
string t;
|
||||
bool in = false;
|
||||
bool ext = false;
|
||||
string iext = "";
|
||||
for(char c: s) if(c == '"') in = !in; else if(!in) ; else if(c == '.') ext = !ext; else if(!ext) t += c; else iext += c;
|
||||
if(iext == "h") { fsm << "#include \"" + setdir + "hyper.h\"\n"; continue; }
|
||||
if(iext != "cpp") printf("unknown extension: %s\n", iext.c_str());
|
||||
fsm << "INCLUDE(\"" << t << "\")\n";
|
||||
continue;
|
||||
}
|
||||
fsm << s << "\n";
|
||||
}
|
||||
fsm.close();
|
||||
|
||||
printf("preprocessing...\n");
|
||||
if(system(preprocessor + " " + opts + " "+obj_dir+"/hyper.cpp -o "+obj_dir+"/hyper.E")) { printf("preprocessing error\n"); exit(1); }
|
||||
|
||||
if(true) {
|
||||
ifstream fs2(obj_dir+"/hyper.E");
|
||||
while(getline(fs2, s)) {
|
||||
if(s.substr(0, 7) == "INCLUDE") {
|
||||
s = s.substr(9);
|
||||
s = s.substr(0,s.size() - 2);
|
||||
modules.push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(get_file_time(obj_dir + "/hyper.o") < get_file_time("hyper.cpp")) {
|
||||
printf("compiling hyper...\n");
|
||||
if(system(compiler + " -DREM " + opts + " " + obj_dir + "/hyper.cpp -c -o " + obj_dir + "/hyper.o")) { printf("error\n"); exit(1); }
|
||||
}
|
||||
|
||||
string allobj = " " + obj_dir + "/hyper.o";
|
||||
|
||||
int id = 0;
|
||||
for(string m: modules) {
|
||||
id++;
|
||||
string src = m + ".cpp";
|
||||
string m2 = m;
|
||||
for(char& c: m2) if(c == '/') c = '_';
|
||||
string obj = obj_dir + "/" + m2 + ".o";
|
||||
time_t src_time = get_file_time(src);
|
||||
if(!src_time) {
|
||||
printf("file not found: %s\n", src.c_str());
|
||||
exit(1);
|
||||
}
|
||||
time_t obj_time = get_file_time(obj);
|
||||
if(src_time > obj_time) {
|
||||
printf("compiling %s... [%d/%d]\n", m.c_str(), id, int(modules.size()));
|
||||
if(system(compiler + " " + opts + " " + src + " -o " + obj)) { printf("error\n"); exit(1); }
|
||||
}
|
||||
else {
|
||||
printf("ok: %s\n", m.c_str());
|
||||
}
|
||||
allobj += " ";
|
||||
allobj += obj;
|
||||
}
|
||||
|
||||
printf("linking...\n");
|
||||
system(linker + allobj + libs);
|
||||
return 0;
|
||||
}
|
||||
// HyperRogue: alternative build system
|
||||
// This reads the file 'hyper.cpp' and compiles the cpp files it includes into separate object files, and then links them.
|
||||
// Tested in Linux, should work in other systems with some changes.
|
||||
|
||||
// Options:
|
||||
// -O2 -- optimize
|
||||
// -O3 -- optimize
|
||||
// -D... -- change compilation flags
|
||||
// [file.cpp] -- add a module to the build (e.g. ./mymake rogueviz)
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string opts;
|
||||
|
||||
string default_standard = " -std=c++11";
|
||||
string standard = default_standard;
|
||||
|
||||
string preprocessor;
|
||||
string compiler;
|
||||
string linker;
|
||||
string libs;
|
||||
|
||||
void set_linux() {
|
||||
preprocessor = "g++ -E";
|
||||
compiler = "g++ -Wall -Wextra -Wno-maybe-uninitialized -Wno-unused-parameter -Wno-implicit-fallthrough -rdynamic -fdiagnostics-color=always -c";
|
||||
linker = "g++ -rdynamic -o hyper";
|
||||
opts = "-DFHS -DLINUX -I/usr/include/SDL";
|
||||
libs = " savepng.o -lSDL -lSDL_ttf -lSDL_mixer -lSDL_gfx -lGLEW -lGL -lpng -rdynamic -lpthread -lz";
|
||||
}
|
||||
|
||||
void set_mac() {
|
||||
preprocessor = "g++ -E";
|
||||
compiler = "g++ -march=native -W -Wall -Wextra -pedantic -Wno-unused-parameter -Wno-implicit-fallthrough -c";
|
||||
linker = "g++ -o hyper";
|
||||
opts = "-DMAC -I/usr/local/include";
|
||||
libs = " savepng.o -L/usr/local/lib -framework AppKit -framework OpenGL -lSDL -lSDLMain -lSDL_gfx -lSDL_mixer -lSDL_ttf -lpng -lpthread -lz";
|
||||
}
|
||||
|
||||
void set_win() {
|
||||
preprocessor = "g++ -E";
|
||||
compiler = "runbat bwin-g.bat -c";
|
||||
linker = "runbat bwin-linker.bat";
|
||||
opts = "-DFHS -DLINUX -I/usr/include/SDL";
|
||||
libs = "";
|
||||
|
||||
standard = "";
|
||||
}
|
||||
|
||||
vector<string> modules;
|
||||
|
||||
time_t get_file_time(const string s) {
|
||||
struct stat attr;
|
||||
if(stat(s.c_str(), &attr)) return 0;
|
||||
return attr.st_mtime;
|
||||
}
|
||||
|
||||
int optimized = 0;
|
||||
|
||||
string obj_dir = "mymake_files";
|
||||
string setdir = "../";
|
||||
|
||||
int system(string cmdline) {
|
||||
return system(cmdline.c_str());
|
||||
}
|
||||
|
||||
bool file_exists(string fname) {
|
||||
return access(fname.c_str(), F_OK) != -1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if defined(MAC)
|
||||
set_mac();
|
||||
#elif defined(WINDOWS)
|
||||
set_win();
|
||||
#else
|
||||
set_linux();
|
||||
#endif
|
||||
for(string fname: {"Makefile.loc", "Makefile.simple", "Makefile"})
|
||||
if(file_exists(fname))
|
||||
system("make -f " + fname + " language-data.cpp autohdr.h savepng.o");
|
||||
for(int i=1; i<argc; i++) {
|
||||
string s = argv[i];
|
||||
if(s.substr(0, 2) == "-D") {
|
||||
opts += " " + s;
|
||||
obj_dir += "/";
|
||||
setdir += "../";
|
||||
for(char c: s)
|
||||
if(c == '=' || c == '-' || c == '/') obj_dir += "_";
|
||||
else obj_dir += c;
|
||||
}
|
||||
else if(s == "-win") {
|
||||
set_win();
|
||||
obj_dir += "/win";
|
||||
setdir += "../";
|
||||
}
|
||||
else if(s == "-mac") {
|
||||
set_mac();
|
||||
obj_dir += "/mac";
|
||||
setdir += "../";
|
||||
}
|
||||
else if(s == "-linux") {
|
||||
set_linux();
|
||||
obj_dir += "/linux";
|
||||
setdir += "../";
|
||||
}
|
||||
else if(s.substr(0, 2) == "-f") {
|
||||
opts += " " + s;
|
||||
obj_dir += "/";
|
||||
setdir += "../";
|
||||
for(char c: s)
|
||||
if(c == '=' || c == '-' || c == '/') obj_dir += "_";
|
||||
else obj_dir += c;
|
||||
linker += " " + s;
|
||||
}
|
||||
else if(s == "-O2")
|
||||
optimized = 2, compiler += " -O2", obj_dir += "/O2", setdir += "../";
|
||||
else if(s == "-O3")
|
||||
optimized = 3, compiler += " -O3", obj_dir += "/O3", setdir += "../";
|
||||
else if(s.substr(0, 4) == "-std")
|
||||
standard = s;
|
||||
else if(s.substr(0, 2) == "-l")
|
||||
linker += " " + s;
|
||||
else if(s == "-I") {
|
||||
opts += " " + s + " " + argv[i+1];
|
||||
i++;
|
||||
}
|
||||
else if(s.substr(0, 2) == "-I")
|
||||
opts += " " + s;
|
||||
else if(s == "-rv") {
|
||||
|
||||
if(standard == default_standard) {
|
||||
standard = "-std=c++17";
|
||||
}
|
||||
ifstream ifs("rogueviz/rogueviz-all.cpp");
|
||||
string s;
|
||||
while(getline(ifs, s)) {
|
||||
if(s.substr(0, 10) == "#include \"") {
|
||||
string t = s.substr(10);
|
||||
t = t.substr(0, t.find(".cpp\""));
|
||||
modules.push_back("rogueviz/" + t);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(s.size() >= 5 && s.substr(s.size() - 4) == ".cpp")
|
||||
s = s.substr(0, s.size() - 4);
|
||||
modules.push_back(s);
|
||||
}
|
||||
}
|
||||
if(!optimized)
|
||||
compiler += " -g3";
|
||||
preprocessor += " " + standard;
|
||||
compiler += " " + standard;
|
||||
ifstream fs("hyper.cpp");
|
||||
|
||||
system("mkdir -p " + obj_dir);
|
||||
|
||||
ofstream fsm(obj_dir + "/hyper.cpp");
|
||||
fsm << "#if REM\n#define INCLUDE(x)\n#endif\n";
|
||||
string s;
|
||||
while(getline(fs, s)) {
|
||||
if(s.substr(0, 8) == "#include") {
|
||||
string t;
|
||||
bool in = false;
|
||||
bool ext = false;
|
||||
string iext = "";
|
||||
for(char c: s) if(c == '"') in = !in; else if(!in) ; else if(c == '.') ext = !ext; else if(!ext) t += c; else iext += c;
|
||||
if(iext == "h") { fsm << "#include \"" + setdir + "hyper.h\"\n"; continue; }
|
||||
if(iext != "cpp") printf("unknown extension: %s\n", iext.c_str());
|
||||
fsm << "INCLUDE(\"" << t << "\")\n";
|
||||
continue;
|
||||
}
|
||||
fsm << s << "\n";
|
||||
}
|
||||
fsm.close();
|
||||
|
||||
printf("preprocessing...\n");
|
||||
if(system(preprocessor + " " + opts + " "+obj_dir+"/hyper.cpp -o "+obj_dir+"/hyper.E")) { printf("preprocessing error\n"); exit(1); }
|
||||
|
||||
if(true) {
|
||||
ifstream fs2(obj_dir+"/hyper.E");
|
||||
while(getline(fs2, s)) {
|
||||
if(s.substr(0, 7) == "INCLUDE") {
|
||||
s = s.substr(9);
|
||||
s = s.substr(0,s.size() - 2);
|
||||
modules.push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(get_file_time(obj_dir + "/hyper.o") < get_file_time("hyper.cpp")) {
|
||||
printf("compiling hyper...\n");
|
||||
if(system(compiler + " -DREM " + opts + " " + obj_dir + "/hyper.cpp -c -o " + obj_dir + "/hyper.o")) { printf("error\n"); exit(1); }
|
||||
}
|
||||
|
||||
string allobj = " " + obj_dir + "/hyper.o";
|
||||
|
||||
int id = 0;
|
||||
for(string m: modules) {
|
||||
id++;
|
||||
string src = m + ".cpp";
|
||||
string m2 = m;
|
||||
for(char& c: m2) if(c == '/') c = '_';
|
||||
string obj = obj_dir + "/" + m2 + ".o";
|
||||
time_t src_time = get_file_time(src);
|
||||
if(!src_time) {
|
||||
printf("file not found: %s\n", src.c_str());
|
||||
exit(1);
|
||||
}
|
||||
time_t obj_time = get_file_time(obj);
|
||||
if(src_time > obj_time) {
|
||||
printf("compiling %s... [%d/%d]\n", m.c_str(), id, int(modules.size()));
|
||||
if(system(compiler + " " + opts + " " + src + " -o " + obj)) { printf("error\n"); exit(1); }
|
||||
}
|
||||
else {
|
||||
printf("ok: %s\n", m.c_str());
|
||||
}
|
||||
allobj += " ";
|
||||
allobj += obj;
|
||||
}
|
||||
|
||||
printf("linking...\n");
|
||||
system(linker + allobj + libs);
|
||||
return 0;
|
||||
}
|
||||
|
@ -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;
|
||||
|
344
nonisotropic.cpp
344
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 +
|
||||
@ -609,9 +607,25 @@ EX namespace sn {
|
||||
"float cz = iz*(1.-1./PRECZ) + .5/PRECZ;"
|
||||
|
||||
// "if(ix > .5 && iy > .6 && ix < iy + .05 && iz < .2 && iz < (iy - 0.5) * 0.6)"
|
||||
"if(ix > .65 + iz * .25 && iy > .55) res = vec4(0.,0.,0.,1.); "
|
||||
|
||||
"else "
|
||||
"\n#ifndef SOLV_ALL\n"
|
||||
|
||||
"bool ok = true;"
|
||||
|
||||
// hard to tell which triangles fall on the other sides
|
||||
"if(iz < .03 && ix > .65 && iy > .65) ok = false;"
|
||||
"if(iz < .013 && ix > .55 && iy > .55) ok = false;"
|
||||
"if(iz < .0075 && ix > .45 && iy > .45) ok = false;"
|
||||
"if(iz > 0.004 && ix > 0.4 && iy > 0.4 && ix < .6 && iy < .6) ok = true;"
|
||||
"if(iz > 0.000004 && ix > 0.4 && ix < 0.7 && iy > 0.4 && iy < 0.7) ok = true;"
|
||||
"if(iz < 0.04 && ix > 0.70 && ix < 0.8 && iy > 0.5 && iy < 0.7) ok = false;"
|
||||
"if(iz < 0.05 && ix > .45 && iy > .75 && ix < .55 && iy < .95) ok = false;"
|
||||
"if(iz < 0.05 && ix > .85 && iy > .45 && iy < .75) ok = false;"
|
||||
"if(iz < 0.025 && ix > .65 && iy > .65 && ix < .8 && iy < .8) ok = false;"
|
||||
|
||||
"if(!ok) res = vec4(0,0,0,1);"
|
||||
"else "
|
||||
|
||||
"\n#endif\n"
|
||||
|
||||
"res = texture3D(tInvExpTable, vec3(cx, cy, cz));"
|
||||
|
||||
@ -745,7 +759,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 +783,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 +983,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);
|
||||
}
|
||||
|
||||
@ -1048,6 +1064,26 @@ EX namespace hybrid {
|
||||
EX geometry_information *underlying_cgip;
|
||||
|
||||
EX eGeometryClass under_class() { return ginf[hybrid::underlying].cclass; }
|
||||
|
||||
EX transmatrix ray_iadj(cell *c, int i) {
|
||||
if(prod && i == c->type-2) return (mscale(Id, +cgi.plevel));
|
||||
if(prod && i == c->type-1) return (mscale(Id, -cgi.plevel));
|
||||
if(prod) {
|
||||
transmatrix T;
|
||||
cell *cw = hybrid::get_where(c).first;
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
hyperpoint h0 = get_corner_position(cw, i);
|
||||
hyperpoint h1 = get_corner_position(cw, (i+1));
|
||||
hyperpoint hm = mid(h0, h1);
|
||||
ld d = hdist0(hm);
|
||||
d *= 2;
|
||||
T = xpush(-d) * spintox(hm);
|
||||
});
|
||||
return T;
|
||||
}
|
||||
if(rotspace) return inverse(rots::ray_adj(c, i));
|
||||
return currentmap->iadj(c, i);
|
||||
}
|
||||
|
||||
EX void configure(eGeometry g) {
|
||||
if(WDIM == 3) return;
|
||||
@ -1243,8 +1279,10 @@ EX namespace hybrid {
|
||||
|
||||
EX int wall_offset(cell *c) {
|
||||
int id = hybrid::underlying == gArchimedean ? arcm::id_of(c->master) + 20 * arcm::parent_index_of(c->master) : shvid(c);
|
||||
if(isize(cgi.walloffsets) <= id) cgi.walloffsets.resize(id+1, -1);
|
||||
int &wo = cgi.walloffsets[id];
|
||||
if(isize(cgi.walloffsets) <= id) cgi.walloffsets.resize(id+1, {-1, nullptr});
|
||||
auto &wop = cgi.walloffsets[id];
|
||||
int &wo = wop.first;
|
||||
if(!wop.second) wop.second = c;
|
||||
if(wo == -1) {
|
||||
cell *c1 = hybrid::get_where(c).first;
|
||||
wo = isize(cgi.shWall3D);
|
||||
@ -1296,6 +1334,20 @@ EX namespace hybrid {
|
||||
return wo;
|
||||
}
|
||||
|
||||
auto clear_samples = addHook(hooks_clearmemory, 40, [] () {
|
||||
for(auto& c: cgis) for(auto& v: c.second.walloffsets)
|
||||
v.second = nullptr;
|
||||
});
|
||||
|
||||
EX vector<pair<int, cell*>> gen_sample_list() {
|
||||
if(!hybri) return {make_pair(0, centerover), make_pair(centerover->type, nullptr)};
|
||||
vector<pair<int, cell*>> result;
|
||||
for(auto& v: cgi.walloffsets) if(v.first >= 0) result.push_back(v);
|
||||
sort(result.begin(), result.end());
|
||||
result.emplace_back(isize(cgi.wallstart)-1, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<cell*> to_link;
|
||||
|
||||
EX void will_link(cell *c) { if(pmap && ((hrmap_hybrid*) pmap)->twisted) to_link.push_back(c); }
|
||||
@ -1822,7 +1874,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]);
|
||||
@ -1831,6 +1883,34 @@ EX namespace rots {
|
||||
return spin(beta) * uxpush(distance/2) * spin(-beta+alpha);
|
||||
}
|
||||
|
||||
std::unordered_map<int, transmatrix> saved_matrices_ray;
|
||||
|
||||
EX transmatrix ray_adj(cell *c1, int i) {
|
||||
if(i == c1->type-2) return uzpush(-cgi.plevel) * spin(-2*cgi.plevel);
|
||||
if(i == c1->type-1) return uzpush(+cgi.plevel) * spin(+2*cgi.plevel);
|
||||
cell *c2 = c1->cmove(i);
|
||||
int id1 = hybrid::underlying == gArchimedean ? arcm::id_of(c1->master) + 20 * arcm::parent_index_of(c1->master) : shvid(c1);
|
||||
int id2 = hybrid::underlying == gArchimedean ? arcm::id_of(c2->master) + 20 * arcm::parent_index_of(c2->master) : shvid(c2);
|
||||
int j = c1->c.spin(i);
|
||||
int id = id1 + (id2 << 10) + (i << 20) + (j << 26);
|
||||
auto &M = saved_matrices_ray[id];
|
||||
if(M[3][3]) return M;
|
||||
|
||||
cell *cw = hybrid::get_where(c1).first;
|
||||
|
||||
transmatrix T;
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
hyperpoint h0 = get_corner_position(cw, i);
|
||||
hyperpoint h1 = get_corner_position(cw, (i+1));
|
||||
hyperpoint hm = mid(h0, h1);
|
||||
ld d = hdist0(hm);
|
||||
d *= 2;
|
||||
T = rspintox(hm) * xpush(d);
|
||||
});
|
||||
|
||||
return M = lift_matrix(T);
|
||||
}
|
||||
|
||||
struct hrmap_rotation_space : hybrid::hrmap_hybrid {
|
||||
|
||||
std::unordered_map<int, transmatrix> saved_matrices;
|
||||
@ -1862,6 +1942,7 @@ EX namespace rots {
|
||||
|
||||
/** reinterpret the given point of rotspace as a rotation matrix in the underlying geometry */
|
||||
EX transmatrix qtm(hyperpoint h) {
|
||||
|
||||
ld& x = h[0];
|
||||
ld& y = h[1];
|
||||
ld& z = h[2];
|
||||
@ -1894,6 +1975,16 @@ EX namespace rots {
|
||||
M[1][2] = -2 * (yz + xw);
|
||||
M[2][1] = -2 * (yz - xw);
|
||||
|
||||
if(hyperbolic) {
|
||||
swap(M[0][2], M[1][2]);
|
||||
swap(M[2][0], M[2][1]);
|
||||
M[1][2] *= -1;
|
||||
M[2][0] *= -1;
|
||||
M[2][2] = xx + yy + zz + ww;
|
||||
return M;
|
||||
}
|
||||
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
@ -1930,13 +2021,18 @@ EX namespace rots {
|
||||
dynamicval<bool> pf(playerfound, true);
|
||||
dynamicval<cell*> m5(centerover, co);
|
||||
dynamicval<transmatrix> m2(View, inprod ? pView : ypush(0) * qtm(h));
|
||||
if(PURE) View = View * pispin;
|
||||
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);
|
||||
|
||||
dynamicval<int> psx(vid.use_smart_range, 2);
|
||||
dynamicval<ld> psy(vid.smart_range_detail, 1);
|
||||
|
||||
calcparam();
|
||||
reset_projection(); current_display->set_all(0);
|
||||
ptds.clear();
|
||||
@ -1953,6 +2049,86 @@ EX namespace rots {
|
||||
|
||||
EX }
|
||||
|
||||
/** stretched rotation space (S3 or SLR) */
|
||||
EX namespace stretch {
|
||||
|
||||
EX ld factor;
|
||||
|
||||
EX bool applicable() {
|
||||
return rotspace || among(geometry, gCell120, gECell120, gCell24, gECell24, gCell8, gECell8);
|
||||
}
|
||||
|
||||
EX bool in() {
|
||||
return factor && applicable();
|
||||
}
|
||||
|
||||
EX transmatrix translate(hyperpoint h) {
|
||||
if(!sphere) return slr::translate(h);
|
||||
return matrix4(
|
||||
h[3], -h[2], h[1], h[0],
|
||||
h[2], h[3], -h[0], h[1],
|
||||
-h[1], h[0], h[3], h[2],
|
||||
-h[0], -h[1], -h[2], h[3]
|
||||
);
|
||||
}
|
||||
|
||||
EX transmatrix itranslate(hyperpoint h) {
|
||||
h[0] = -h[0];
|
||||
h[1] = -h[1];
|
||||
h[2] = -h[2];
|
||||
if(!sphere) return slr::translate(h);
|
||||
return translate(h);
|
||||
}
|
||||
|
||||
hyperpoint mulz(const hyperpoint at, const hyperpoint velocity, ld factor) {
|
||||
auto vel = itranslate(at) * velocity;
|
||||
vel[2] *= factor;
|
||||
return translate(at) * vel;
|
||||
}
|
||||
|
||||
EX ld squared() {
|
||||
return abs(1 + factor);
|
||||
}
|
||||
|
||||
EX ld not_squared() {
|
||||
return sqrt(squared());
|
||||
}
|
||||
|
||||
hyperpoint isometric_to_actual(const hyperpoint at, const hyperpoint velocity) {
|
||||
return mulz(at, velocity, 1/not_squared());
|
||||
}
|
||||
|
||||
hyperpoint actual_to_isometric(const hyperpoint at, const hyperpoint velocity) {
|
||||
return mulz(at, velocity, not_squared());
|
||||
}
|
||||
|
||||
hyperpoint christoffel(const hyperpoint at, const hyperpoint velocity, const hyperpoint transported) {
|
||||
|
||||
auto vel = itranslate(at) * velocity;
|
||||
auto tra = itranslate(at) * transported;
|
||||
|
||||
hyperpoint c;
|
||||
|
||||
auto K = factor;
|
||||
|
||||
if(!sphere) K = -2 - K;
|
||||
|
||||
c[0] = -K * (vel[1] * tra[2] + vel[2] * tra[1]);
|
||||
c[1] = K * (vel[0] * tra[2] + vel[2] * tra[0]);
|
||||
c[2] = 0;
|
||||
c[3] = 0;
|
||||
|
||||
return translate(at) * c;
|
||||
}
|
||||
|
||||
EX ld sqnorm(hyperpoint at, hyperpoint h) {
|
||||
if(sphere)
|
||||
return sqhypot_d(4, h);
|
||||
h = itranslate(at) * h;
|
||||
return h[0] * h[0] + h[1] * h[1] + h[2] * h[2];
|
||||
}
|
||||
EX }
|
||||
|
||||
EX namespace nisot {
|
||||
|
||||
EX hyperpoint christoffel(const hyperpoint at, const hyperpoint velocity, const hyperpoint transported) {
|
||||
@ -1960,6 +2136,7 @@ EX namespace nisot {
|
||||
#if CAP_SOLV
|
||||
else if(sn::in()) return sn::christoffel(at, velocity, transported);
|
||||
#endif
|
||||
else if(stretch::in()) return stretch::christoffel(at, velocity, transported);
|
||||
else if(sl2) return slr::christoffel(at, velocity, transported);
|
||||
else return point3(0, 0, 0);
|
||||
}
|
||||
@ -1970,37 +2147,43 @@ 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;
|
||||
}
|
||||
|
||||
EX transmatrix parallel_transport_bare(transmatrix Pos, hyperpoint h) {
|
||||
|
||||
bool stretch = stretch::in();
|
||||
|
||||
h[3] = 0;
|
||||
|
||||
auto tPos = transpose(Pos);
|
||||
|
||||
const ld eps = 1e-4;
|
||||
|
||||
if(sl2) {
|
||||
|
||||
if(sl2 && !stretch) {
|
||||
hyperpoint p = slr::to_phigans(tPos[3]);
|
||||
for(int i=0; i<3; i++)
|
||||
tPos[i] = (slr::to_phigans(tPos[3] + tPos[i] * eps) - p) / eps;
|
||||
@ -2009,16 +2192,70 @@ EX namespace nisot {
|
||||
}
|
||||
else h = Pos * h;
|
||||
|
||||
int steps = 100;
|
||||
int steps = rk_steps;
|
||||
h /= steps;
|
||||
|
||||
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& at = tPos[3];
|
||||
auto& vel = h;
|
||||
|
||||
array<ld, 4> ms;
|
||||
|
||||
if(stretch) {
|
||||
for(int i=0; i<3; i++) {
|
||||
ms[i] = stretch::sqnorm(at, tPos[i]);
|
||||
tPos[i] = stretch::isometric_to_actual(at, tPos[i]);
|
||||
}
|
||||
ms[3] = stretch::sqnorm(at, vel);
|
||||
if(!ms[3]) return Pos;
|
||||
vel = stretch::isometric_to_actual(at, vel);
|
||||
}
|
||||
|
||||
if(sl2) {
|
||||
|
||||
for(int i=0; i<steps; i++) {
|
||||
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(stretch) {
|
||||
at = normalize(at);
|
||||
|
||||
auto fix = [&] (hyperpoint& h, ld& m) {
|
||||
h = stretch::itranslate(at) * h;
|
||||
h[3] = 0;
|
||||
ld m1 = h[0] * h[0] + h[1] * h[1] + h[2] * h[2] * stretch::squared();
|
||||
h /= sqrt(m1/m);
|
||||
h = stretch::translate(at) * h;
|
||||
};
|
||||
|
||||
for(int i=0; i<3; i++) fix(tPos[i], ms[i]);
|
||||
fix(vel, ms[3]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(stretch) {
|
||||
vel = stretch::actual_to_isometric(at, vel);
|
||||
for(int i=0; i<3; i++) tPos[i] = stretch::actual_to_isometric(at, tPos[i]);
|
||||
}
|
||||
|
||||
else if(sl2) {
|
||||
hyperpoint p = slr::from_phigans(tPos[3]);
|
||||
for(int i=0; i<3; i++)
|
||||
tPos[i] = (slr::from_phigans(tPos[3] + tPos[i] * eps) - p) / eps;
|
||||
@ -2029,6 +2266,7 @@ EX namespace nisot {
|
||||
}
|
||||
|
||||
EX void fixmatrix(transmatrix& T) {
|
||||
if(sphere) return hr::fixmatrix(T);
|
||||
transmatrix push = eupush( tC0(T) );
|
||||
transmatrix push_back = inverse(push);
|
||||
transmatrix gtl = push_back * T;
|
||||
@ -2043,12 +2281,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 +2369,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();
|
||||
@ -2153,6 +2396,11 @@ EX namespace nisot {
|
||||
hybrid::reconfigure();
|
||||
return 0;
|
||||
}
|
||||
else if(argis("-rot-stretch")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(stretch::factor, ray::reset_raycaster);
|
||||
return 0;
|
||||
}
|
||||
else if(argis("-prodturn")) {
|
||||
PHASEFROM(2);
|
||||
if(prod) stop_game();
|
||||
|
55
pattern2.cpp
55
pattern2.cpp
@ -58,14 +58,14 @@ int eupattern4(cell *c) {
|
||||
|
||||
EX bool ishept(cell *c) {
|
||||
// EUCLIDEAN
|
||||
if(euclid && PURE) return eupattern(c) == 0;
|
||||
if(euc::in() && PURE) return eupattern(c) == 0;
|
||||
else if(hybri) { cell *c1 = hybrid::get_where(c).first; return c1 == c1->master->c7; }
|
||||
else return c == c->master->c7;
|
||||
}
|
||||
|
||||
EX bool ishex1(cell *c) {
|
||||
// EUCLIDEAN
|
||||
if(euclid && PURE) return eupattern(c) == 1;
|
||||
if(euc::in() && PURE) return eupattern(c) == 1;
|
||||
#if CAP_GP
|
||||
else if(GOLDBERG) return c->master->c7 != c && !pseudohept(c->move(0));
|
||||
#endif
|
||||
@ -74,14 +74,14 @@ EX bool ishex1(cell *c) {
|
||||
|
||||
bool ishex2(cell *c) {
|
||||
// EUCLIDEAN
|
||||
if(euclid && PURE) return eupattern(c) == 1;
|
||||
if(euc::in() && PURE) return eupattern(c) == 1;
|
||||
#if CAP_GP
|
||||
else if(GOLDBERG) return c->master->c7 != c && gp::pseudohept_val(c) == 1;
|
||||
#endif
|
||||
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);
|
||||
@ -372,6 +372,7 @@ EX pair<int, bool> fieldval(cell *c) {
|
||||
}
|
||||
|
||||
EX int fieldval_uniq(cell *c) {
|
||||
if(fake::in()) return FPIU(fieldval_uniq(c));
|
||||
if(experimental) return 0;
|
||||
else if(hybri) {
|
||||
auto c1 = hybrid::get_where(c).first;
|
||||
@ -388,7 +389,7 @@ EX int fieldval_uniq(cell *c) {
|
||||
if(ctof(c)) return c->master->fieldval;
|
||||
else return createMov(c, 0)->master->fieldval + 256 * createMov(c,2)->master->fieldval + (1<<16) * createMov(c,4)->master->fieldval;
|
||||
}
|
||||
else if(euclid && !kite::in() && !arcm::in()) {
|
||||
else if(euc::in()) {
|
||||
auto p = euc2_coordinates(c);
|
||||
if(bounded) return p.first + (p.second << 16);
|
||||
return gmod(p.first - 22 * p.second, 3*127);
|
||||
@ -1405,7 +1406,7 @@ EX bool pseudohept(cell *c) {
|
||||
#if MAXMDIM == 4
|
||||
if(WDIM == 3) {
|
||||
if(geometry == gField435) return false;
|
||||
else if(euclid) return euc::pseudohept(c);
|
||||
else if(euc::in()) return euc::pseudohept(c);
|
||||
else return reg3::pseudohept(c);
|
||||
}
|
||||
#endif
|
||||
@ -1666,7 +1667,11 @@ EX namespace patterns {
|
||||
}
|
||||
}
|
||||
|
||||
EX hookset<int(cell*)> *hooks_generate_canvas;
|
||||
EX hookset<int(cell*)> hooks_generate_canvas;
|
||||
|
||||
EX int jhole = 0;
|
||||
EX int jblock = 0;
|
||||
EX int rwalls = 50;
|
||||
|
||||
EX int generateCanvas(cell *c) {
|
||||
|
||||
@ -1737,7 +1742,8 @@ EX namespace patterns {
|
||||
case 'g':
|
||||
return canvasback;
|
||||
case 'r': {
|
||||
color_t r = hrand(0x1FFFFFF + 1);
|
||||
color_t r = hrand(0xFFFFFF + 1);
|
||||
if(hrand(100) < rwalls) r |= 0x1000000;
|
||||
if(c == cwt.at) r &= 0xFFFFFF;
|
||||
return r;
|
||||
}
|
||||
@ -1786,6 +1792,8 @@ EX namespace patterns {
|
||||
return colortables['x'][zebra3(c)];
|
||||
case 'w':
|
||||
return colortables['w'][randpattern(c, subcanvas) ? 1 : 0];
|
||||
case 'H':
|
||||
return colortables['c'][c->master->c7 == c ? 0 : 1];
|
||||
case 'l':
|
||||
return random_landscape(c, 3, 1, 17, 0x808080);
|
||||
case 'd':
|
||||
@ -1801,16 +1809,24 @@ EX namespace patterns {
|
||||
case 'v':
|
||||
return colortables['v'][sevenval(c)];
|
||||
case 'j': {
|
||||
if(c == currentmap->gamestart()) return canvasback;
|
||||
int d = c->master->distance;
|
||||
if(geometry == gNil) d = c->master->zebraval;
|
||||
if(d % 2 == 0 || d < -5 || d > 5) return canvasback;
|
||||
return colortables['j'][(d+5)/2];
|
||||
if(euc::in()) d = euc::get_ispacemap()[c->master][0];
|
||||
if(d % 2 == 0 || d < -5 || d > 5) return hrand(100) < jblock ? 0xFFFFFFFF : canvasback;
|
||||
return hrand(100) < jhole ? canvasback : colortables['j'][(d+5)/2];
|
||||
}
|
||||
case 'J': {
|
||||
if(c == currentmap->gamestart()) return canvasback;
|
||||
int d = c->master->distance;
|
||||
if(geometry == gNil) d = c->master->zebraval;
|
||||
if(d % 2 == 0 || d < -5 || d > 5) return hrand(100) < 10 ? 0xFFFFFFFF : canvasback;
|
||||
return hrand(100) < 50 ? 0 : colortables['j'][(d+5)/2];
|
||||
if((d&3) != 2) return hrand(100) < jblock ? 0xFFFFFFFF : canvasback;
|
||||
return hrand(100) < jhole ? canvasback : colortables['j'][(d+10)/4];
|
||||
}
|
||||
case 'G': {
|
||||
color_t r = hrand(0xFFFFFF + 1);
|
||||
if(hrand(100) < rwalls && pseudohept(c) && c != cwt.at) r |= 0x1000000;
|
||||
return r;
|
||||
}
|
||||
case 'f': {
|
||||
color_t res;
|
||||
@ -2876,7 +2892,7 @@ EX namespace linepatterns {
|
||||
|
||||
dialog::addSelItem("line width", fts(width), 'W');
|
||||
dialog::add_action([] () {
|
||||
dialog::editNumber(width, 0, 10, 1, 1, XLAT("line width"), "");
|
||||
dialog::editNumber(width, 0, 10, 0.1, 1, XLAT("line width"), "");
|
||||
});
|
||||
|
||||
dialog::addBoolItem_action("edit widths individually", indiv, 'I');
|
||||
@ -2938,6 +2954,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();
|
||||
@ -2985,6 +3005,13 @@ int read_pattern_args() {
|
||||
else patterns::canvasback = arghex();
|
||||
stop_game_and_switch_mode(rg::nothing);
|
||||
}
|
||||
else if(argis("-canvas-random")) {
|
||||
PHASEFROM(2);
|
||||
stop_game();
|
||||
firstland = specialland = laCanvas;
|
||||
patterns::whichCanvas = 'r';
|
||||
shift(); patterns::rwalls = argi();
|
||||
}
|
||||
else if(argis("-cformula")) {
|
||||
PHASEFROM(2);
|
||||
stop_game();
|
||||
@ -3013,7 +3040,7 @@ int read_pattern_args() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto ah_pattern = addHook(hooks_args, 0, read_pattern_args) + addHook(clearmemory, 100, [] { patterns::computed_nearer_map.clear(); patterns::computed_furthest_map.clear(); });
|
||||
auto ah_pattern = addHook(hooks_args, 0, read_pattern_args) + addHook(hooks_clearmemory, 100, [] { patterns::computed_nearer_map.clear(); patterns::computed_furthest_map.clear(); });
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -1300,8 +1300,8 @@ EX void produceGhost(cell *c, eMonster victim, eMonster who) {
|
||||
EX bool swordAttack(cell *mt, eMonster who, cell *c, int bb) {
|
||||
eMonster m = c->monst;
|
||||
if(c->wall == waCavewall) markOrb(bb ? itOrbSword2: itOrbSword);
|
||||
if(c->wall == waSmallTree || c->wall == waBigTree || c->wall == waRose || c->wall == waCTree || c->wall == waVinePlant ||
|
||||
thruVine(mt, c) || c->wall == waBigBush || c->wall == waSmallBush || c->wall == waSolidBranch || c->wall == waWeakBranch) {
|
||||
if(among(c->wall, waSmallTree, waBigTree, waRose, waCTree, waVinePlant, waBigBush, waSmallBush, waSolidBranch, waWeakBranch, waShrub)
|
||||
|| thruVine(mt, c)) {
|
||||
changes.ccell(c);
|
||||
playSound(NULL, "hit-axe"+pick123());
|
||||
markOrb(bb ? itOrbSword2: itOrbSword);
|
||||
|
75
polygons.cpp
75
polygons.cpp
@ -713,7 +713,7 @@ void geometry_information::procedural_shapes() {
|
||||
bshape(shSwitchDisk, PPR::FLOOR); for(int i=0; i<=S84; i+=S3) hpcpush(ddi(i, .06) * C0);
|
||||
}
|
||||
|
||||
vector<ld> equal_weights(20, 1);
|
||||
vector<ld> equal_weights(1000, 1);
|
||||
|
||||
#if !(CAP_BT && MAXMDIM >= 4)
|
||||
void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector<ld> weights) { }
|
||||
@ -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);
|
||||
@ -811,7 +811,7 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
|
||||
h = zshift(normalize_flat(h), center_altitude * (1-x-y) + altitudes[a] * x + altitudes[b] * y);
|
||||
hpcpush(h); return;
|
||||
}
|
||||
if(sn::in() || !bt::in()) { hpcpush(normalize(h)); return; }
|
||||
if(sn::in() || !bt::in()) { hpcpush(ultra_normalize(h)); return; }
|
||||
hyperpoint res = bt::parabolic3(h[0], h[1]) * xpush0(yy*h[2]);
|
||||
hpcpush(res);
|
||||
});
|
||||
@ -829,7 +829,7 @@ void geometry_information::make_wall(int id, vector<hyperpoint> vertices, vector
|
||||
}
|
||||
if(nil)
|
||||
h = nilv::on_geodesic(vertices[a], vertices[(a+1)%n], y * 1. / STEP);
|
||||
if(sn::in() || !bt::in()) { hpcpush(normalize(h)); continue; }
|
||||
if(sn::in() || !bt::in()) { hpcpush(ultra_normalize(h)); continue; }
|
||||
hyperpoint res = bt::parabolic3(h[0], h[1]) * xpush0(yy*h[2]);
|
||||
hpcpush(res);
|
||||
}
|
||||
@ -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];
|
||||
}
|
||||
@ -967,66 +972,14 @@ void geometry_information::create_wall3d() {
|
||||
walloffsets.clear();
|
||||
}
|
||||
|
||||
if(GDIM == 3 && euclid && S7 == 6) {
|
||||
for(int w=0; w<6; w++) {
|
||||
vector<hyperpoint> vertices;
|
||||
for(int a=0; a<4; a++) {
|
||||
int t[3];
|
||||
t[0] = (w>=3) ? -1 : 1;
|
||||
t[1] = among(a, 0, 3) ? -1 : 1;
|
||||
t[2] = among(a, 2, 3) ? -1 : 1;
|
||||
int x = w%3;
|
||||
int y = (x+2)%3;
|
||||
int z = (y+2)%3;
|
||||
vertices.push_back(hpxy3(t[x]/2., t[y]/2., t[z]/2.));
|
||||
}
|
||||
make_wall(w, vertices);
|
||||
}
|
||||
}
|
||||
|
||||
if(GDIM == 3 && euclid && S7 == 12) {
|
||||
auto v = euc::get_shifttable();
|
||||
for(int w=0; w<12; w++) {
|
||||
auto co = v[w];
|
||||
vector<int> valid;
|
||||
for(int c=0; c<3; c++) if(co[c]) valid.push_back(c);
|
||||
int third = 3 - valid[1] - valid[0];
|
||||
hyperpoint v0 = cpush0(valid[0], co[valid[0]] > 0 ? 1 : -1);
|
||||
hyperpoint v1 = cpush0(valid[1], co[valid[1]] > 0 ? 1 : -1);
|
||||
make_wall(w, {v0, v0/2 + v1/2 + cpush0(third, .5) - C0, v1, v0/2 + v1/2 + cpush0(third, -.5) - C0});
|
||||
}
|
||||
}
|
||||
|
||||
if(GDIM == 3 && euclid && S7 == 14) {
|
||||
auto v = euc::get_shifttable();
|
||||
for(int w=0; w<14; w++) {
|
||||
bshape(shWall3D[w], PPR::WALL);
|
||||
if(w%7 < 3) {
|
||||
int z = w>=7?-1:1;
|
||||
make_wall(w, {
|
||||
cpush0(w%7, z) + cpush0((w%7+1)%3, 1/2.) - C0,
|
||||
cpush0(w%7, z) + cpush0((w%7+2)%3, 1/2.) - C0,
|
||||
cpush0(w%7, z) + cpush0((w%7+1)%3,-1/2.) - C0,
|
||||
cpush0(w%7, z) + cpush0((w%7+2)%3,-1/2.) - C0
|
||||
});
|
||||
}
|
||||
else {
|
||||
auto t = v[w];
|
||||
ld x = t[0], y = t[1], z = t[2];
|
||||
make_wall(w, {
|
||||
hpxy3(x, y/2, 0), hpxy3(x/2, y, 0), hpxy3(0, y, z/2),
|
||||
hpxy3(0, y/2, z), hpxy3(x/2, 0, z), hpxy3(x, 0, z/2)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(reg3::in()) {
|
||||
if(euc::in() || reg3::in()) {
|
||||
int facesize = isize(cgi.cellshape) / S7;
|
||||
int next = 0;
|
||||
for(int w=0; w<S7; w++) {
|
||||
vector<hyperpoint> vertices;
|
||||
if(S7 == 14) facesize = (w%7 < 3 ? 4 : 6);
|
||||
for(int a=0; a<facesize; a++)
|
||||
vertices.push_back(cgi.cellshape[w*facesize+a]);
|
||||
vertices.push_back(cgi.cellshape[next++]);
|
||||
make_wall(w, vertices);
|
||||
}
|
||||
}
|
||||
@ -1189,6 +1142,8 @@ void geometry_information::prepare_shapes() {
|
||||
if(GDIM == 3 && !floor_textures) make_floor_textures();
|
||||
#endif
|
||||
|
||||
if(fake::in()) { FPIU( cgi.require_shapes() ); }
|
||||
|
||||
symmetriesAt.clear();
|
||||
allshapes.clear();
|
||||
#if CAP_GP
|
||||
|
20
quit.cpp
20
quit.cpp
@ -122,7 +122,7 @@ EX hint hints[] = {
|
||||
[]() { return true; },
|
||||
[]() {
|
||||
dialog::addInfo(XLAT(
|
||||
#if ISMOBILE==1
|
||||
#if ISMOBILE
|
||||
"The 'world overview' shows all the lands in HyperRogue."
|
||||
#else
|
||||
"Press 'o' to see all the lands in HyperRogue."
|
||||
@ -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');
|
||||
@ -457,12 +457,12 @@ EX void showMission() {
|
||||
dialog::addItem(XLAT("inventory"), 'i');
|
||||
if(racing::on)
|
||||
dialog::addItem(XLAT("racing menu"), 'o');
|
||||
#if ISMOBILE==0
|
||||
#if !ISMOBILE
|
||||
dialog::addItem(XLAT(quitsaves() ? "save" : "quit"), SDLK_F10);
|
||||
#endif
|
||||
#if CAP_ANDROIDSHARE
|
||||
#endif
|
||||
#if CAP_ANDROIDSHARE
|
||||
dialog::addItem(XLAT("SHARE"), 's'-96);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
dialog::addItem(XLAT("message log"), 'l');
|
||||
|
||||
|
57
racing.cpp
57
racing.cpp
@ -835,7 +835,7 @@ heptspin sview;
|
||||
#if CAP_COMMANDLINE
|
||||
auto hook =
|
||||
addHook(hooks_args, 100, readArgs)
|
||||
+ addHook(clearmemory, 0, []() {
|
||||
+ addHook(hooks_clearmemory, 0, []() {
|
||||
track_ready = false;
|
||||
track.clear();
|
||||
rti.clear();
|
||||
@ -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};
|
||||
|
338
raycaster.cpp
338
raycaster.cpp
@ -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;
|
||||
|
||||
@ -41,16 +41,17 @@ EX int max_cells = 2048;
|
||||
EX bool rays_generate = true;
|
||||
|
||||
EX ld& exp_decay_current() {
|
||||
return (sn::in() || hyperbolic) ? exp_decay_exp : exp_decay_poly;
|
||||
if(fake::in()) return *FPIU(&exp_decay_current());
|
||||
return (sn::in() || hyperbolic || sl2) ? exp_decay_exp : exp_decay_poly;
|
||||
}
|
||||
|
||||
EX int& max_iter_current() {
|
||||
if(nonisotropic) return max_iter_sol;
|
||||
if(nonisotropic || stretch::in()) return max_iter_sol;
|
||||
else return max_iter_iso;
|
||||
}
|
||||
|
||||
ld& maxstep_current() {
|
||||
if(sn::in()) return maxstep_sol;
|
||||
if(sn::in() || stretch::in()) return maxstep_sol;
|
||||
else return maxstep_nil;
|
||||
}
|
||||
|
||||
@ -65,13 +66,17 @@ EX bool available() {
|
||||
if(WDIM == 2) return false;
|
||||
if(hyperbolic && pmodel == mdPerspective && !kite::in())
|
||||
return true;
|
||||
if(sphere && pmodel == mdPerspective && !rotspace)
|
||||
return true;
|
||||
if(nil && S7 == 8)
|
||||
return false;
|
||||
if((sn::in() || nil) && pmodel == mdGeodesic)
|
||||
if((sn::in() || nil || sl2) && pmodel == mdGeodesic)
|
||||
return true;
|
||||
if(euclid && pmodel == mdPerspective && !bt::in())
|
||||
return true;
|
||||
if(prod && PURE)
|
||||
if(prod && (PURE || BITRUNCATED))
|
||||
return true;
|
||||
if(pmodel == mdPerspective && stretch::in())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -79,13 +84,14 @@ EX bool available() {
|
||||
/** do we want to use the raycaster? */
|
||||
EX bool requested() {
|
||||
if(cgflags & qRAYONLY) return true;
|
||||
if(stretch::in()) return true;
|
||||
if(!want_use) return false;
|
||||
#if CAP_TEXTURE
|
||||
if(texture::config.tstate == texture::tsActive) return false;
|
||||
#endif
|
||||
if(!available()) return false;
|
||||
if(want_use == 2) return true;
|
||||
return racing::on || quotient;
|
||||
return racing::on || quotient || fake::in();
|
||||
}
|
||||
|
||||
#if HDR
|
||||
@ -97,6 +103,7 @@ struct raycaster : glhr::GLprogram {
|
||||
GLint uLinearSightRange, uExpStart, uExpDecay;
|
||||
GLint uBLevel;
|
||||
GLint uPosX, uPosY;
|
||||
GLint uWallOffset, uSides;
|
||||
|
||||
raycaster(string vsh, string fsh);
|
||||
};
|
||||
@ -134,6 +141,9 @@ raycaster::raycaster(string vsh, string fsh) : GLprogram(vsh, fsh) {
|
||||
tWallcolor = glGetUniformLocation(_program, "tWallcolor");
|
||||
tTextureMap = glGetUniformLocation(_program, "tTextureMap");
|
||||
|
||||
uWallOffset = glGetUniformLocation(_program, "uWallOffset");
|
||||
uSides = glGetUniformLocation(_program, "uSides");
|
||||
|
||||
uPosX = glGetUniformLocation(_program, "uPosX");
|
||||
uPosY = glGetUniformLocation(_program, "uPosY");
|
||||
}
|
||||
@ -169,16 +179,27 @@ string build_getter(string type, string name, int index) {
|
||||
#define GET(array, index) array "[" index "]"
|
||||
#endif
|
||||
|
||||
EX hookset<void(string&, string&)> *hooks_rayshader;
|
||||
EX hookset<bool(shared_ptr<raycaster>)> *hooks_rayset;
|
||||
EX hookset<void(string&, string&)> hooks_rayshader;
|
||||
EX hookset<bool(shared_ptr<raycaster>)> hooks_rayset;
|
||||
|
||||
void enable_raycaster() {
|
||||
if(geometry != last_geometry) reset_raycaster();
|
||||
using glhr::to_glsl;
|
||||
if(geometry != last_geometry) {
|
||||
reset_raycaster();
|
||||
}
|
||||
|
||||
deg = 0;
|
||||
|
||||
auto samples = hybrid::gen_sample_list();
|
||||
for(int i=0; i<isize(samples)-1; i++)
|
||||
deg = max(deg, samples[i+1].first - samples[i].first);
|
||||
|
||||
last_geometry = geometry;
|
||||
deg = S7; if(prod) deg += 2;
|
||||
if(!our_raycaster) {
|
||||
bool asonov = hr::asonov::in();
|
||||
bool use_reflect = reflect_val && !nil && !levellines;
|
||||
|
||||
bool bi = BITRUNCATED;
|
||||
|
||||
string vsh =
|
||||
"attribute mediump vec4 aPosition;\n"
|
||||
@ -211,7 +232,7 @@ void enable_raycaster() {
|
||||
"uniform mediump vec4 uWallX["+rays+"];\n"
|
||||
"uniform mediump vec4 uWallY["+rays+"];\n"
|
||||
"uniform mediump vec4 uFogColor;\n"
|
||||
"uniform mediump int uWallstart["+its(deg+1)+"];\n"
|
||||
"uniform mediump int uWallstart["+its(isize(cgi.wallstart))+"];\n"
|
||||
"uniform mediump float uLinearSightRange, uExpStart, uExpDecay;\n";
|
||||
|
||||
#ifdef GLES_ONLY
|
||||
@ -225,15 +246,19 @@ void enable_raycaster() {
|
||||
"uniform mediump float uPLevel;\n"
|
||||
"uniform mediump mat4 uLP;\n";
|
||||
|
||||
int flat1 = 0, flat2 = S7;
|
||||
if(bi) fsh +=
|
||||
"uniform int uWallOffset, uSides;\n";
|
||||
|
||||
int flat1 = 0, flat2 = deg;
|
||||
if(prod || rotspace) flat2 -= 2;
|
||||
|
||||
if(hyperbolic && bt::in()) {
|
||||
fsh += "uniform mediump float uBLevel;\n";
|
||||
flat1 = bt::dirs_outer();
|
||||
flat2 -= bt::dirs_inner();
|
||||
}
|
||||
|
||||
if(IN_ODS || hyperbolic) fsh +=
|
||||
|
||||
if(hyperbolic) fsh +=
|
||||
|
||||
"mediump mat4 xpush(float x) { return mat4("
|
||||
"cosh(x), 0., 0., sinh(x),\n"
|
||||
@ -241,7 +266,16 @@ void enable_raycaster() {
|
||||
"0., 0., 1., 0.,\n"
|
||||
"sinh(x), 0., 0., cosh(x)"
|
||||
");}\n";
|
||||
|
||||
|
||||
if(sphere) fsh +=
|
||||
|
||||
"mediump mat4 xpush(float x) { return mat4("
|
||||
"cos(x), 0., 0., sin(x),\n"
|
||||
"0., 1., 0., 0.,\n"
|
||||
"0., 0., 1., 0.,\n"
|
||||
"-sin(x), 0., 0., cos(x)"
|
||||
");}\n";
|
||||
|
||||
if(IN_ODS) fsh +=
|
||||
|
||||
"mediump mat4 xzspin(float x) { return mat4("
|
||||
@ -258,13 +292,22 @@ void enable_raycaster() {
|
||||
"0., 0., 0., 1."
|
||||
");}\n";
|
||||
|
||||
if(bi) {
|
||||
fsh += "int walloffset, sides;\n";
|
||||
}
|
||||
else {
|
||||
fsh += "const int walloffset = 0;\n"
|
||||
"const int sides = " + its(centerover->type) + ";\n";
|
||||
}
|
||||
|
||||
|
||||
fsh +=
|
||||
"mediump vec2 map_texture(mediump vec4 pos, int which) {\n";
|
||||
if(nil) fsh += "if(which == 2 || which == 5) pos.z = 0.;\n";
|
||||
else if(hyperbolic && bt::in()) fsh +=
|
||||
"pos = vec4(-log(pos.w-pos.x), pos.y, pos.z, 1);\n"
|
||||
"pos.yz *= exp(pos.x);\n";
|
||||
else if(hyperbolic) fsh +=
|
||||
else if(hyperbolic || sphere) fsh +=
|
||||
"pos /= pos.w;\n";
|
||||
else if(prod) fsh +=
|
||||
"pos = vec4(pos.x/pos.z, pos.y/pos.z, pos.w, 0);\n";
|
||||
@ -279,6 +322,8 @@ void enable_raycaster() {
|
||||
"}\n"
|
||||
"return vec2(1, 1);\n"
|
||||
"}\n";
|
||||
|
||||
bool stepbased = nonisotropic || stretch::in();
|
||||
|
||||
string fmain = "void main() {\n";
|
||||
|
||||
@ -303,9 +348,13 @@ void enable_raycaster() {
|
||||
" at0.xyz = at0.xyz / length(at0.xyz);\n";
|
||||
|
||||
if(hyperbolic) fsh += " mediump float len(mediump vec4 x) { return x[3]; }\n";
|
||||
else if(sphere && rotspace) fsh += " mediump float len(mediump vec4 x) { return 1.+x.x*x.x+x.y*x.y-x.z*x.z-x.w*x.w; }\n";
|
||||
else if(sl2) fsh += " mediump float len(mediump vec4 x) { return 1.+x.x*x.x+x.y*x.y; }\n";
|
||||
else if(sphere) fsh += " mediump float len(mediump vec4 x) { return 1.-x[3]; }\n";
|
||||
|
||||
else fsh += " mediump float len(mediump vec4 x) { return length(x.xyz); }\n";
|
||||
|
||||
if(nonisotropic) fmain +=
|
||||
if(stepbased) fmain +=
|
||||
" const mediump float maxstep = " + fts(maxstep_current()) + ";\n"
|
||||
" const mediump float minstep = " + fts(minstep) + ";\n"
|
||||
" mediump float next = maxstep;\n";
|
||||
@ -328,6 +377,16 @@ void enable_raycaster() {
|
||||
else fmain +=
|
||||
" mediump vec4 position = vw * vec4(0., 0., 0., 1.);\n"
|
||||
" mediump vec4 tangent = vw * at0;\n";
|
||||
|
||||
if(stretch::in()) {
|
||||
fmain +=
|
||||
"tangent = s_itranslate(position) * tangent;\n"
|
||||
"tangent[2] /= " + to_glsl(stretch::not_squared()) + ";\n"
|
||||
"tangent = s_translate(position) * tangent;\n";
|
||||
;
|
||||
}
|
||||
|
||||
if(bi) fmain += " walloffset = uWallOffset; sides = uSides;\n";
|
||||
|
||||
fmain +=
|
||||
" mediump float go = 0.;\n"
|
||||
@ -345,39 +404,39 @@ void enable_raycaster() {
|
||||
if(IN_ODS) fmain +=
|
||||
" if(go == 0.) {\n"
|
||||
" mediump float best = len(position);\n"
|
||||
" for(int i=0; i<"+its(S7)+"; i++) {\n"
|
||||
" for(int i=0; i<sides; i++) {\n"
|
||||
" mediump float cand = len(uM[i] * position);\n"
|
||||
" if(cand < best - .001) { dist = 0.; best = cand; which = i; }\n"
|
||||
" }\n"
|
||||
" }\n";
|
||||
|
||||
if(!nonisotropic) {
|
||||
if(!stepbased) {
|
||||
|
||||
fmain +=
|
||||
" if(which == -1) {\n";
|
||||
|
||||
fmain += "for(int i="+its(flat1)+"; i<"+its(flat2)+"; i++) {\n";
|
||||
fmain += "for(int i="+its(flat1)+"; i<"+(prod ? "sides-2" : its(flat2))+"; i++) {\n";
|
||||
|
||||
if(in_h2xe()) fmain +=
|
||||
" mediump float v = ((position - uM[i] * position)[2] / (uM[i] * tangent - tangent)[2]);\n"
|
||||
" mediump float v = ((position - uM[walloffset+i] * position)[2] / (uM[walloffset+i] * tangent - tangent)[2]);\n"
|
||||
" if(v > 1. || v < -1.) continue;\n"
|
||||
" mediump float d = atanh(v);\n"
|
||||
" mediump vec4 next_tangent = position * sinh(d) + tangent * cosh(d);\n"
|
||||
" if(next_tangent[2] < (uM[i] * next_tangent)[2]) continue;\n"
|
||||
" if(next_tangent[2] < (uM[walloffset+i] * next_tangent)[2]) continue;\n"
|
||||
" d /= xspeed;\n";
|
||||
else if(in_s2xe()) fmain +=
|
||||
" mediump float v = ((position - uM[i] * position)[2] / (uM[i] * tangent - tangent)[2]);\n"
|
||||
" mediump float v = ((position - uM[walloffset+i] * position)[2] / (uM[walloffset+i] * tangent - tangent)[2]);\n"
|
||||
" mediump float d = atan(v);\n"
|
||||
" mediump vec4 next_tangent = tangent * cos(d) - position * sin(d);\n"
|
||||
" if(next_tangent[2] > (uM[i] * next_tangent)[2]) continue;\n"
|
||||
" if(next_tangent[2] > (uM[walloffset+i] * next_tangent)[2]) continue;\n"
|
||||
" d /= xspeed;\n";
|
||||
else if(in_e2xe()) fmain +=
|
||||
" mediump float deno = dot(position, tangent) - dot(uM[i]*position, uM[i]*tangent);\n"
|
||||
" mediump float deno = dot(position, tangent) - dot(uM[walloffset+i]*position, uM[walloffset+i]*tangent);\n"
|
||||
" if(deno < 1e-6 && deno > -1e-6) continue;\n"
|
||||
" mediump float d = (dot(uM[i]*position, uM[i]*position) - dot(position, position)) / 2. / deno;\n"
|
||||
" mediump float d = (dot(uM[walloffset+i]*position, uM[walloffset+i]*position) - dot(position, position)) / 2. / deno;\n"
|
||||
" if(d < 0.) continue;\n"
|
||||
" mediump vec4 next_position = position + d * tangent;\n"
|
||||
" if(dot(next_position, tangent) < dot(uM[i]*next_position, uM[i]*tangent)) continue;\n"
|
||||
" if(dot(next_position, tangent) < dot(uM[walloffset+i]*next_position, uM[walloffset+i]*tangent)) continue;\n"
|
||||
" d /= xspeed;\n";
|
||||
else if(hyperbolic) fmain +=
|
||||
" mediump float v = ((position - uM[i] * position)[3] / (uM[i] * tangent - tangent)[3]);\n"
|
||||
@ -385,6 +444,11 @@ void enable_raycaster() {
|
||||
" mediump float d = atanh(v);\n"
|
||||
" mediump vec4 next_tangent = position * sinh(d) + tangent * cosh(d);\n"
|
||||
" if(next_tangent[3] < (uM[i] * next_tangent)[3]) continue;\n";
|
||||
else if(sphere) fmain +=
|
||||
" mediump float v = ((position - uM[i] * position)[3] / (uM[i] * tangent - tangent)[3]);\n"
|
||||
" mediump float d = atan(v);\n"
|
||||
" mediump vec4 next_tangent = -position * sin(d) + tangent * cos(d);\n"
|
||||
" if(next_tangent[3] > (uM[i] * next_tangent)[3]) continue;\n";
|
||||
else fmain +=
|
||||
" mediump float deno = dot(position, tangent) - dot(uM[i]*position, uM[i]*tangent);\n"
|
||||
" if(deno < 1e-6 && deno > -1e-6) continue;\n"
|
||||
@ -423,8 +487,8 @@ void enable_raycaster() {
|
||||
}
|
||||
|
||||
if(prod) fmain +=
|
||||
"if(zspeed > 0.) { mediump float d = (uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = "+its(S7)+"+1; }}\n"
|
||||
"if(zspeed < 0.) { mediump float d = (-uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = "+its(S7)+"; }}\n";
|
||||
"if(zspeed > 0.) { mediump float d = (uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = sides-1; }}\n"
|
||||
"if(zspeed < 0.) { mediump float d = (-uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = sides-2; }}\n";
|
||||
|
||||
fmain += "}\n";
|
||||
|
||||
@ -434,7 +498,7 @@ void enable_raycaster() {
|
||||
fmain +=
|
||||
" if(which == -1 && dist == 0.) return;";
|
||||
}
|
||||
|
||||
|
||||
// shift d units
|
||||
if(use_reflect) fmain +=
|
||||
"bool reflect = false;\n";
|
||||
@ -454,12 +518,19 @@ void enable_raycaster() {
|
||||
else if(in_e2xe()) fmain +=
|
||||
" position = position + tangent * dist * xspeed;\n"
|
||||
" zpos += dist * zspeed;\n";
|
||||
else if(hyperbolic) fmain +=
|
||||
else if(hyperbolic && !stepbased) fmain +=
|
||||
" mediump float ch = cosh(dist); mediump float sh = sinh(dist);\n"
|
||||
" mediump vec4 v = position * ch + tangent * sh;\n"
|
||||
" tangent = tangent * ch + position * sh;\n"
|
||||
" position = v;\n";
|
||||
else if(nonisotropic) {
|
||||
else if(sphere && !stepbased) fmain +=
|
||||
" mediump float ch = cos(dist); mediump float sh = sin(dist);\n"
|
||||
" mediump vec4 v = position * ch + tangent * sh;\n"
|
||||
" tangent = tangent * ch - position * sh;\n"
|
||||
" position = v;\n";
|
||||
else if(stepbased) {
|
||||
|
||||
bool use_christoffel = true;
|
||||
|
||||
if(sol && nih) fsh +=
|
||||
"mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n"
|
||||
@ -473,12 +544,49 @@ void enable_raycaster() {
|
||||
"mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n"
|
||||
" return vec4(-vel.z*tra.x - vel.x*tra.z, vel.z*tra.y + vel.y * tra.z, vel.x*tra.x * exp(2.*pos.z) - vel.y * tra.y * exp(-2.*pos.z), 0.);\n"
|
||||
" }\n";
|
||||
else fsh +=
|
||||
else if(nil && false) fsh +=
|
||||
"mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n"
|
||||
" mediump float x = pos.x;\n"
|
||||
" 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";
|
||||
else if(sl2) {
|
||||
fsh += "mediump mat4 s_translate(vec4 h) {\n"
|
||||
"return mat4(h.w,h.z,h.y,h.x,-h.z,h.w,-h.x,h.y,h.y,-h.x,h.w,-h.z,h.x,h.y,h.z,h.w);\n"
|
||||
"}\n";
|
||||
fsh += "mediump mat4 s_itranslate(vec4 h) {\n"
|
||||
"h.xyz = -h.xyz; return s_translate(h);\n"
|
||||
"}\n";
|
||||
fsh += "mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n"
|
||||
"vel = s_itranslate(pos) * vel;\n"
|
||||
"tra = s_itranslate(pos) * tra;\n"
|
||||
"return s_translate(pos) * vec4(\n"
|
||||
" (vel.y*tra.z+vel.z*tra.y) * " + to_glsl(-(-stretch::factor-2)) + ", "
|
||||
" (vel.x*tra.z+vel.z*tra.x) * " + to_glsl(-stretch::factor-2.) + ", "
|
||||
" 0, 0);\n"
|
||||
"}\n";
|
||||
}
|
||||
else if(stretch::in()) {
|
||||
fsh += "mediump mat4 s_translate(vec4 h) {\n"
|
||||
"return mat4(h.w,h.z,-h.y,-h.x,-h.z,h.w,h.x,-h.y,h.y,-h.x,h.w,-h.z,h.x,h.y,h.z,h.w);\n"
|
||||
"}\n";
|
||||
fsh += "mediump mat4 s_itranslate(vec4 h) {\n"
|
||||
"h.xyz = -h.xyz; return s_translate(h);\n"
|
||||
"}\n";
|
||||
fsh += "mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) {\n"
|
||||
"vel = s_itranslate(pos) * vel;\n"
|
||||
"tra = s_itranslate(pos) * tra;\n"
|
||||
"return s_translate(pos) * vec4(\n"
|
||||
" (vel.y*tra.z+vel.z*tra.y) * " + to_glsl(-stretch::factor) + ", "
|
||||
" (vel.x*tra.z+vel.z*tra.x) * " + to_glsl(stretch::factor) + ", "
|
||||
" 0, 0);\n"
|
||||
"}\n";
|
||||
}
|
||||
else use_christoffel = false;
|
||||
|
||||
if(use_christoffel) 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";
|
||||
|
||||
@ -501,13 +609,20 @@ 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";
|
||||
if(use_christoffel) fmain +=
|
||||
"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(sl2) fmain +=
|
||||
"nposition = nposition / sqrt(dot(position.zw, position.zw) - dot(nposition.xy, nposition.xy));\n";
|
||||
|
||||
else if(stretch::in()) fmain +=
|
||||
"nposition = nposition / sqrt(dot(nposition, nposition));\n";
|
||||
|
||||
if(nil) {
|
||||
fmain +=
|
||||
"mediump vec4 xp, xt;\n"
|
||||
@ -550,11 +665,49 @@ void enable_raycaster() {
|
||||
fsh += "uniform mediump mat4 uStraighten;\n";
|
||||
fmain += "mediump vec4 sp = uStraighten * nposition;\n";
|
||||
}
|
||||
|
||||
if(hyperbolic) {
|
||||
fmain +=
|
||||
" mediump float ch = cosh(dist); mediump float sh = sinh(dist);\n"
|
||||
" mediump vec4 v = position * ch + tangent * sh;\n"
|
||||
" mediump vec4 ntangent = tangent * ch + position * sh;\n"
|
||||
" mediump vec4 nposition = v;\n";
|
||||
}
|
||||
|
||||
if(sphere && !use_christoffel) {
|
||||
fmain +=
|
||||
" mediump float ch = cos(dist); mediump float sh = sin(dist);\n"
|
||||
" mediump vec4 v = position * ch + tangent * sh;\n"
|
||||
" mediump vec4 ntangent = tangent * ch - position * sh;\n"
|
||||
" mediump vec4 nposition = v;\n";
|
||||
}
|
||||
|
||||
bool reg = hyperbolic || sphere || euclid || sl2;
|
||||
|
||||
if(reg) {
|
||||
fsh += "mediump float len_h(vec4 h) { return 1. - h[3]; }\n";
|
||||
string s = rotspace ? "-2" : "";
|
||||
fmain +=
|
||||
" mediump float best = len(nposition);\n"
|
||||
" for(int i=0; i<sides"+s+"; i++) {\n"
|
||||
" mediump float cand = len(uM[walloffset+i] * nposition);\n"
|
||||
" if(cand < best) { best = cand; which = i; }\n"
|
||||
" }\n";
|
||||
if(rotspace) fmain +=
|
||||
" if(which == -1) {\n"
|
||||
" best = len_h(nposition);\n"
|
||||
" mediump float cand1 = len_h(uM[walloffset+sides-2]*nposition);\n"
|
||||
" if(cand1 < best) { best = cand1; which = sides-2; }\n"
|
||||
" mediump float cand2 = len_h(uM[walloffset+sides-1]*nposition);\n"
|
||||
" if(cand2 < best) { best = cand2; which = sides-1; }\n"
|
||||
" }\n";
|
||||
}
|
||||
|
||||
fmain +=
|
||||
"if(next >= minstep) {\n";
|
||||
|
||||
if(asonov) fmain +=
|
||||
if(reg) fmain += "if(which != -1) {\n";
|
||||
else if(asonov) fmain +=
|
||||
"if(abs(sp.x) > 1. || abs(sp.y) > 1. || abs(sp.z) > 1.) {\n";
|
||||
else if(nih) fmain +=
|
||||
"if(abs(nposition.x) > uBinaryWidth || abs(nposition.y) > uBinaryWidth || abs(nposition.z) > .5) {\n";
|
||||
@ -610,7 +763,7 @@ void enable_raycaster() {
|
||||
"if(nposition.z > log(2.)/2.) which = nposition.x > 0. ? 3 : 2;\n"
|
||||
"if(nposition.z <-log(2.)/2.) which = nposition.y > 0. ? 7 : 6;\n";
|
||||
}
|
||||
else fmain +=
|
||||
else if(nil) fmain +=
|
||||
"if(nposition.x > .5) which = 3;\n"
|
||||
"if(nposition.x <-.5) which = 0;\n"
|
||||
"if(nposition.y > .5) which = 4;\n"
|
||||
@ -622,14 +775,24 @@ void enable_raycaster() {
|
||||
"next = maxstep;\n"
|
||||
"}\n";
|
||||
|
||||
if(nil) fmain +=
|
||||
"tangent = translatev(position, xt);\n";
|
||||
|
||||
fmain +=
|
||||
"position = nposition;\n";
|
||||
|
||||
if(!nil) fmain +=
|
||||
"tangent = tangent + acc * dist;\n";
|
||||
if(use_christoffel) fmain +=
|
||||
"tangent = tangent + (acc1+2.*acc2+2.*acc3+acc4)/(6.*dist);\n";
|
||||
else if(nil) fmain +=
|
||||
"tangent = translatev(position, xt);\n";
|
||||
else fmain +=
|
||||
"tangent = ntangent;\n";
|
||||
|
||||
if(stretch::in() || sl2) {
|
||||
fmain +=
|
||||
"tangent = s_itranslate(position) * tangent;\n"
|
||||
"tangent[3] = 0.;\n"
|
||||
"float nvelsquared = dot(tangent.xy, tangent.xy) + " + to_glsl(stretch::squared()) + " * tangent.z * tangent.z;\n"
|
||||
"tangent /= sqrt(nvelsquared);\n"
|
||||
"tangent = s_translate(position) * tangent;\n";
|
||||
}
|
||||
}
|
||||
else fmain +=
|
||||
"position = position + tangent * dist;\n";
|
||||
@ -673,10 +836,10 @@ void enable_raycaster() {
|
||||
" if(col[3] > 0.0) {\n";
|
||||
|
||||
if(hard_limit < NO_LIMIT)
|
||||
fmain += " if(go > float(" + fts(hard_limit) + ")) { gl_FragDepth = 1.; return; }\n";
|
||||
fmain += " if(go > " + to_glsl(hard_limit) + ") { gl_FragDepth = 1.; return; }\n";
|
||||
|
||||
if(!(levellines && disable_texture)) fmain +=
|
||||
" mediump vec2 inface = map_texture(position, which);\n"
|
||||
" mediump vec2 inface = map_texture(position, which+walloffset);\n"
|
||||
" mediump vec3 tmap = texture2D(tTextureMap, u).rgb;\n"
|
||||
" if(tmap.z == 0.) col.xyz *= min(1., (1.-inface.x)/ tmap.x);\n"
|
||||
" else {\n"
|
||||
@ -693,7 +856,7 @@ void enable_raycaster() {
|
||||
|
||||
if(use_reflect) fmain +=
|
||||
" if(col.w == 1.) {\n"
|
||||
" col.w = float("+fts(1-reflect_val)+");\n"
|
||||
" col.w = " + to_glsl(1-reflect_val)+";\n"
|
||||
" reflect = true;\n"
|
||||
" }\n";
|
||||
|
||||
@ -725,7 +888,7 @@ void enable_raycaster() {
|
||||
|
||||
#ifndef GLES_ONLY
|
||||
fmain +=
|
||||
" gl_FragDepth = (-float("+fts(vnear+vfar)+")+w*float("+fts(2*vnear*vfar)+")/z)/float("+fts(vnear-vfar)+");\n"
|
||||
" gl_FragDepth = (" + to_glsl(-vnear+vfar)+"+w*" + to_glsl(2*vnear*vfar)+"/z)/" + to_glsl(vnear-vfar)+";\n"
|
||||
" gl_FragDepth = (gl_FragDepth + 1.) / 2.;\n";
|
||||
#endif
|
||||
|
||||
@ -740,7 +903,7 @@ void enable_raycaster() {
|
||||
" }\n";
|
||||
|
||||
if(use_reflect) {
|
||||
if(prod) fmain += "if(reflect && which >= "+its(S7)+") { zspeed = -zspeed; continue; }\n";
|
||||
if(prod) fmain += "if(reflect && which >= "+its(deg-2)+") { zspeed = -zspeed; continue; }\n";
|
||||
if(hyperbolic && bt::in()) fmain +=
|
||||
"if(reflect && (which < "+its(flat1)+" || which >= "+its(flat2)+")) {\n"
|
||||
" mediump float x = -log(position.w - position.x);\n"
|
||||
@ -795,15 +958,23 @@ void enable_raycaster() {
|
||||
" cid = connection.xy;\n";
|
||||
|
||||
if(prod) fmain +=
|
||||
" if(which == "+its(S7)+") { zpos += uPLevel+uPLevel; }\n"
|
||||
" if(which == "+its(S7)+"+1) { zpos -= uPLevel+uPLevel; }\n";
|
||||
" if(which == sides-2) { zpos += uPLevel+uPLevel; }\n"
|
||||
" if(which == sides-1) { zpos -= uPLevel+uPLevel; }\n";
|
||||
|
||||
fmain +=
|
||||
" int mid = int(connection.z * 1024.);\n"
|
||||
" mediump mat4 m = " GET("uM", "mid") " * " GET("uM", "which") ";\n"
|
||||
" mediump mat4 m = " GET("uM", "mid") " * " GET("uM", "walloffset+which") ";\n"
|
||||
" position = m * position;\n"
|
||||
" tangent = m * tangent;\n";
|
||||
|
||||
if(bi) {
|
||||
fmain +=
|
||||
"walloffset = int(connection.w * 256.);\n"
|
||||
"sides = int(connection.w * 4096.) - 16 * walloffset;\n";
|
||||
|
||||
// fmain += "if(sides != 8) { gl_FragColor = vec4(.5,float(sides)/8.,.5,1); return; }";
|
||||
}
|
||||
|
||||
fmain +=
|
||||
" }\n"
|
||||
" gl_FragColor.xyz += left * uFogColor.xyz;\n";
|
||||
@ -891,8 +1062,6 @@ EX void cast() {
|
||||
glUniform1f(o->uPosY, -((cd->ycenter-cd->ytop)*2./cd->ysize - 1));
|
||||
|
||||
if(!callhandlers(false, hooks_rayset, o)) {
|
||||
deg = S7;
|
||||
if(prod) deg += 2;
|
||||
|
||||
length = 4096;
|
||||
per_row = length / deg;
|
||||
@ -944,14 +1113,29 @@ EX void cast() {
|
||||
GLERR("uniform mediump startid");
|
||||
glUniform1f(o->uIPD, vid.ipd);
|
||||
GLERR("uniform mediump IPD");
|
||||
|
||||
if(o->uWallOffset != -1) {
|
||||
glUniform1i(o->uWallOffset, wall_offset(centerover));
|
||||
glUniform1i(o->uSides, centerover->type);
|
||||
}
|
||||
|
||||
vector<transmatrix> ms;
|
||||
for(int j=0; j<S7; j++) ms.push_back(currentmap->iadj(cwt.at, j));
|
||||
if(prod) ms.push_back(mscale(Id, +cgi.plevel));
|
||||
if(prod) ms.push_back(mscale(Id, -cgi.plevel));
|
||||
auto sa = hybrid::gen_sample_list();
|
||||
|
||||
vector<transmatrix> ms(sa.back().first, Id);
|
||||
|
||||
for(auto& p: sa) {
|
||||
int id = p.first;
|
||||
cell *c = p.second;
|
||||
if(!c) continue;
|
||||
for(int j=0; j<c->type; j++)
|
||||
ms[id+j] = hybrid::ray_iadj(c, j);
|
||||
}
|
||||
|
||||
// println(hlog, ms);
|
||||
|
||||
if(!sol && !nil && reflect_val) {
|
||||
for(int j=0; j<S7; j++) {
|
||||
if(BITRUNCATED) exit(1);
|
||||
for(int j=0; j<centerover->type; j++) {
|
||||
transmatrix T = inverse(ms[j]);
|
||||
hyperpoint h = tC0(T);
|
||||
ld d = hdist0(h);
|
||||
@ -1006,18 +1190,26 @@ EX void cast() {
|
||||
}
|
||||
}
|
||||
|
||||
transmatrix T = currentmap->iadj(c, i) * inverse(ms[i]);
|
||||
transmatrix T = currentmap->iadj(c, i) * inverse(ms[wall_offset(c) + i]);
|
||||
for(int k=0; k<=isize(ms); k++) {
|
||||
if(k < isize(ms) && !eqmatrix(ms[k], T)) continue;
|
||||
if(k == isize(ms)) ms.push_back(T);
|
||||
connections[u][2] = (k+.5) / 1024.;
|
||||
break;
|
||||
}
|
||||
connections[u][3] = (wall_offset(c1) / 256.) + (c1->type + .5) / 4096.;
|
||||
}
|
||||
}
|
||||
|
||||
if(prod) ms[S7] = ms[S7+1] = Id;
|
||||
|
||||
if(prod) {
|
||||
for(auto p: sa) {
|
||||
int id =p.first;
|
||||
if(id == 0) continue;
|
||||
ms[id-2] = Id;
|
||||
ms[id-1] = Id;
|
||||
}
|
||||
}
|
||||
|
||||
vector<GLint> wallstart;
|
||||
for(auto i: cgi.wallstart) wallstart.push_back(i);
|
||||
glUniform1iv(o->uWallstart, isize(wallstart), &wallstart[0]);
|
||||
@ -1135,10 +1327,10 @@ EX void configure() {
|
||||
});
|
||||
}
|
||||
|
||||
if(nonisotropic) {
|
||||
if(nonisotropic || stretch::in()) {
|
||||
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;
|
||||
@ -1196,6 +1388,12 @@ int readArgs() {
|
||||
PHASEFROM(2);
|
||||
want_use = 1;
|
||||
}
|
||||
else if(argis("-ray-range")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(exp_start);
|
||||
shift_arg_formula(exp_decay_current());
|
||||
want_use = 1;
|
||||
}
|
||||
else if(argis("-ray-out")) {
|
||||
PHASEFROM(2); shift(); color_out_of_range = arghex();
|
||||
}
|
||||
@ -1203,6 +1401,12 @@ int readArgs() {
|
||||
PHASEFROM(2);
|
||||
comparison_mode = true;
|
||||
}
|
||||
else if(argis("-ray-sol")) {
|
||||
PHASEFROM(2);
|
||||
shift(); max_iter_sol = argi();
|
||||
shift_arg_formula(maxstep_sol, reset_raycaster);
|
||||
reset_raycaster();
|
||||
}
|
||||
else if(argis("-ray-cells")) {
|
||||
PHASEFROM(2); shift();
|
||||
rays_generate = true;
|
||||
|
46
reg3.cpp
46
reg3.cpp
@ -28,10 +28,16 @@ EX namespace reg3 {
|
||||
#endif
|
||||
|
||||
EX bool in() {
|
||||
if(fake::in()) return FPIU(in());
|
||||
return GDIM == 3 && !euclid && !bt::in() && !nonisotropic && !hybri && !kite::in();
|
||||
}
|
||||
|
||||
EX void generate() {
|
||||
|
||||
if(fake::in()) {
|
||||
fake::generate();
|
||||
return;
|
||||
}
|
||||
|
||||
int& loop = cgi.loop;
|
||||
int& face = cgi.face;
|
||||
@ -122,8 +128,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 +137,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;
|
||||
@ -186,6 +192,13 @@ EX namespace reg3 {
|
||||
|
||||
if(loop == 4) cgi.strafedist = adjcheck;
|
||||
else cgi.strafedist = hdist(cgi.adjmoves[0] * C0, cgi.adjmoves[1] * C0);
|
||||
|
||||
if(stretch::applicable()) {
|
||||
transmatrix T = cspin(0, 2, 90 * degree);
|
||||
transmatrix iT = inverse(T);
|
||||
for(auto& v: cgi.adjmoves) v = T * v * iT;
|
||||
for(auto& v: cellshape) v = T * v;
|
||||
}
|
||||
|
||||
vertices_only.clear();
|
||||
for(hyperpoint h: cellshape) {
|
||||
@ -282,6 +295,7 @@ EX namespace reg3 {
|
||||
return Id;
|
||||
}
|
||||
|
||||
#if CAP_CRYSTAL
|
||||
int encode_coord(const crystal::coord& co) {
|
||||
int c = 0;
|
||||
for(int i=0; i<4; i++) c |= ((co[i]>>1) & 3) << (2*i);
|
||||
@ -314,6 +328,7 @@ EX namespace reg3 {
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct hrmap_field3 : reg3::hrmap_quotient3 {
|
||||
|
||||
@ -691,10 +706,15 @@ EX namespace reg3 {
|
||||
dynamicval<hrmap*> cm(currentmap, binary_map);
|
||||
binary_map->virtualRebase(alt, T);
|
||||
}
|
||||
|
||||
|
||||
fixmatrix(T);
|
||||
auto hT = tC0(T);
|
||||
|
||||
bool hopf = stretch::applicable();
|
||||
|
||||
if(hopf)
|
||||
T = stretch::translate(hT);
|
||||
|
||||
if(DEB) println(hlog, "searching at ", alt, ":", hT);
|
||||
|
||||
if(DEB) for(auto& p2: altmap[alt]) println(hlog, "for ", tC0(p2.second), " intval is ", intval(tC0(p2.second), hT));
|
||||
@ -706,7 +726,8 @@ EX namespace reg3 {
|
||||
// println(hlog, "YES found in ", isize(altmap[alt]));
|
||||
if(DEB) println(hlog, "-> found ", p2.first);
|
||||
int fb = 0;
|
||||
hyperpoint old = T * (inverse(T1) * tC0(p1.second));
|
||||
hyperpoint old = tC0(p1.second);;
|
||||
if(!hopf) T * (inverse(T1) * old);
|
||||
#if CAP_FIELD
|
||||
if(quotient_map) {
|
||||
p2.first->c.connect(counterpart(parent)->c.spin(d), parent, d, false);
|
||||
@ -745,6 +766,19 @@ EX namespace reg3 {
|
||||
fv = cp->c.move(d)->fieldval;
|
||||
}
|
||||
#endif
|
||||
if(hopf) {
|
||||
hyperpoint old = tC0(p1.second);
|
||||
for(d2=0; d2<S7; d2++) {
|
||||
hyperpoint back = T * tC0(cgi.adjmoves[d2]);
|
||||
if((err = intval(back, old)) < 1e-3)
|
||||
break;
|
||||
}
|
||||
if(d2 == S7) {
|
||||
d2 = 0;
|
||||
println(hlog, "Hopf connection failed");
|
||||
}
|
||||
println(hlog, "found d2 = ", d2);
|
||||
}
|
||||
heptagon *created = tailored_alloc<heptagon> (S7);
|
||||
created->c7 = newCell(S7, created);
|
||||
if(sphere) spherecells.push_back(created->c7);
|
||||
@ -1304,6 +1338,7 @@ EX int celldistance(cell *c1, cell *c2) {
|
||||
EX bool pseudohept(cell *c) {
|
||||
auto m = regmap();
|
||||
if(cgflags & qSINGLE) return true;
|
||||
if(fake::in()) return FPIU(reg3::pseudohept(c));
|
||||
if(sphere) {
|
||||
hyperpoint h = tC0(m->relative_matrix(c->master, regmap()->origin, C0));
|
||||
if(S7 == 12) {
|
||||
@ -1472,6 +1507,7 @@ int dist_alt(cell *c) {
|
||||
#if MAXMDIM >= 4
|
||||
EX cellwalker strafe(cellwalker cw, int j) {
|
||||
hyperpoint hfront = tC0(cgi.adjmoves[cw.spin]);
|
||||
cw.at->cmove(j);
|
||||
transmatrix T = currentmap->adj(cw.at, j);
|
||||
for(int i=0; i<S7; i++) if(i != cw.at->c.spin(j))
|
||||
if(hdist(hfront, T * tC0(cgi.adjmoves[i])) < cgi.strafedist + .01)
|
||||
|
@ -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;
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include "../hyper.h"
|
||||
#include "rogueviz.h"
|
||||
|
||||
namespace rogueviz {
|
||||
@ -145,7 +144,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
|
||||
|
@ -281,6 +281,7 @@ auto hchook = addHook(hooks_drawcell, 100, draw_ptriangle)
|
||||
[] (presmode mode) {
|
||||
setCanvas(mode, '0');
|
||||
|
||||
slidecommand = "animation";
|
||||
if(mode == pmKey) {
|
||||
tour::slide_backup(cylanim, !cylanim);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
/* explore the Janko group J1: https://en.wikipedia.org/wiki/Janko_group_J1 */
|
||||
|
||||
#include "../hyper.h"
|
||||
#include "rogueviz.h"
|
||||
|
||||
#if !ISWEB
|
||||
|
||||
namespace hr {
|
||||
|
||||
@ -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
|
||||
|
@ -1,16 +1,11 @@
|
||||
#include "../hyper.h"
|
||||
#include "rogueviz.h"
|
||||
|
||||
namespace hr {
|
||||
namespace rogueviz {
|
||||
|
||||
#if CAP_CRYSTAL
|
||||
|
||||
void curvepoint(const hyperpoint& H1);
|
||||
dqi_poly& queuecurve(color_t linecol, color_t fillcol, PPR prio);
|
||||
|
||||
namespace magic {
|
||||
|
||||
bool on = false;
|
||||
|
||||
int back = 0x202020;
|
||||
|
||||
int magiccolors[14] = { 0xFFFFFF, 0xFFFF00, 0x0000FF, 0x00FF00, 0xFF0000, 0xFF8000, 0x800080, 0x808080, 0x00FFFF, 0x80FFFF, 0x4040C0, 0x40C040, 0xC04040, 0xC0A040 };
|
||||
@ -31,8 +26,10 @@ void build(crystal::coord co, int at) {
|
||||
setdist(c, 7, NULL);
|
||||
if(twos == 0)
|
||||
c->landparam = back;
|
||||
else if(twos == 1)
|
||||
else if(twos == 1) {
|
||||
c->landparam = magiccolors[index];
|
||||
if(WDIM == 3) c->wall = waWaxWall;
|
||||
}
|
||||
|
||||
println(hlog, co, " twos = ", twos, " index = ", index, " set = ", format("%06X", c->landparam));
|
||||
|
||||
@ -52,7 +49,7 @@ void magic(int sides) {
|
||||
start_game();
|
||||
|
||||
build(crystal::c0, 0);
|
||||
on = true;
|
||||
vizid = (void*) &magic;
|
||||
}
|
||||
|
||||
void curveline(hyperpoint a, hyperpoint b, int lev) {
|
||||
@ -65,9 +62,13 @@ void curveline(hyperpoint a, hyperpoint b, int lev) {
|
||||
}
|
||||
|
||||
bool magic_markers(cell *c, const transmatrix& V) {
|
||||
if(!on) return false;
|
||||
if(vizid != &magic) return false;
|
||||
timerghost = false;
|
||||
if(c->landparam == back) {
|
||||
if(GDIM == 2) {
|
||||
auto co = crystal::get_coord(c->master);
|
||||
for(int a=0; a<S7/2; a++) if(co[a] >= 6 || co[a] <= -6) c->landparam = 0;
|
||||
}
|
||||
if(GDIM == 2)
|
||||
for(int i=0; i<S7; i++) {
|
||||
cell *c2 = c->move(i);
|
||||
@ -132,7 +133,7 @@ void twos_to_fours(vector<int>& zeros, crystal::coord co, int d) {
|
||||
}
|
||||
|
||||
bool magic_rotate(cell *c) {
|
||||
if(!on) return false;
|
||||
if(vizid != &magic) return false;
|
||||
if(c->landparam != back) return false;
|
||||
vector<int> zeros;
|
||||
auto co = crystal::get_coord(c->master);
|
||||
@ -140,6 +141,7 @@ bool magic_rotate(cell *c) {
|
||||
for(int i=0; i<crystal::get_dim(); i++) {
|
||||
if(co[i] == 0) zeros.push_back(i);
|
||||
else if(co[i] == 2 || co[i] == -2) ;
|
||||
else if(co[i] == 4 || co[i] == -4) ;
|
||||
else return false;
|
||||
}
|
||||
println(hlog, "zeros = ", zeros);
|
||||
@ -149,20 +151,21 @@ bool magic_rotate(cell *c) {
|
||||
}
|
||||
|
||||
bool magic_rugkey(int sym, int uni) {
|
||||
if((cmode & sm::NORMAL) && uni == 'p' && on) {
|
||||
if(vizid != &magic) return false;
|
||||
if((cmode & sm::NORMAL) && uni == 'p') {
|
||||
rug::texturesize = 4096;
|
||||
if(rug::rugged) rug::close();
|
||||
else rug::init();
|
||||
return true;
|
||||
}
|
||||
if((cmode & sm::NORMAL) && uni == 'r' && on) {
|
||||
if((cmode & sm::NORMAL) && uni == 'r') {
|
||||
mine::performMarkCommand(mouseover);
|
||||
return true;
|
||||
}
|
||||
if((cmode & sm::NORMAL) && uni == 'R' && on) {
|
||||
if((cmode & sm::NORMAL) && uni == 'R') {
|
||||
build(crystal::c0, 0);
|
||||
}
|
||||
if((cmode & sm::NORMAL) && uni == 'k' && on) {
|
||||
}
|
||||
if((cmode & sm::NORMAL) && uni == 'k') {
|
||||
crystal::view_coordinates = !crystal::view_coordinates;
|
||||
return true;
|
||||
}
|
||||
|
@ -2,16 +2,14 @@
|
||||
// example commandline: -noplayer -rugtsize 4096 -smart 1 -canvas B -ncee
|
||||
// set CAP_NCONF (and change the path) if you have access to newconformist
|
||||
|
||||
#include "../hyper.h"
|
||||
|
||||
#ifndef CAP_NCONF
|
||||
#define CAP_NCONF 0
|
||||
#endif
|
||||
#include "rogueviz.h"
|
||||
|
||||
#if CAP_NCONF
|
||||
|
||||
#ifndef CAP_DRAW
|
||||
#define CAP_DRAW 0
|
||||
#endif
|
||||
|
||||
#define main nconf_main
|
||||
#undef unordered_map
|
||||
#undef self
|
||||
@ -638,11 +636,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 +712,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 +798,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;
|
||||
@ -346,7 +346,7 @@ bool handleKey(int sym, int uni) {
|
||||
auto xhook = addHook(hooks_args, 100, readArgs)
|
||||
+ addHook(hooks_handleKey, 0, handleKey)
|
||||
+ addHook(hooks_prestats, 0, frame)
|
||||
+ addHook(clearmemory, 40, [] () { snubon = false; } )
|
||||
+ addHook(hooks_clearmemory, 40, [] () { snubon = false; } )
|
||||
+ addHook(rvtour::hooks_build_rvtour, 142, [] (vector<tour::slide>& v) {
|
||||
using namespace tour;
|
||||
v.push_back(
|
||||
|
@ -21,6 +21,8 @@ namespace hybrid { extern hrmap *pmap; }
|
||||
|
||||
namespace qtm {
|
||||
|
||||
int mode;
|
||||
|
||||
color_t rcolor() {
|
||||
color_t res;
|
||||
part(res, 0) = hrand(0x80);
|
||||
@ -30,6 +32,30 @@ color_t rcolor() {
|
||||
swap(part(res, 2), part(res, rand() % 3));
|
||||
return res;
|
||||
}
|
||||
|
||||
color_t rainbow_color(hyperpoint h) {
|
||||
ld sat = 1 - 1 / h[2];
|
||||
ld hue = atan2(h[0], h[1]) / (2 * M_PI);
|
||||
|
||||
hue = frac(hue);
|
||||
|
||||
if(hue < 0) hue++;
|
||||
|
||||
hue *= 6;
|
||||
|
||||
color_t res;
|
||||
|
||||
if(hue<1) res = gradient(0xFF0000, 0xFFFF00, 0, hue, 1);
|
||||
else if(hue<2) res = gradient(0x00FF00, 0xFFFF00, 2, hue, 1);
|
||||
else if(hue<3) res = gradient(0x00FF00, 0x00FFFF, 2, hue, 3);
|
||||
else if(hue<4) res = gradient(0x0000FF, 0x00FFFF, 4, hue, 3);
|
||||
else if(hue<5) res = gradient(0x0000FF, 0xFF00FF, 4, hue, 5);
|
||||
else if(hue<6) res = gradient(0xFF0000, 0xFF00FF, 6, hue, 5);
|
||||
|
||||
println(hlog, "sat = ", sat, " hue = ", hue);
|
||||
|
||||
return gradient(0xFFFFFF, res, 0, sat, 1);
|
||||
}
|
||||
|
||||
void set_cell(cell *c) {
|
||||
if(hybri) {
|
||||
@ -40,12 +66,22 @@ void set_cell(cell *c) {
|
||||
c->landparam = c1->landparam;
|
||||
c->item = itNone;
|
||||
c->monst = moNone;
|
||||
if(mode == 1) {
|
||||
if(hybrid::get_where(c).second == 0)
|
||||
c->landparam = 0xFFFFFF;
|
||||
}
|
||||
if(mode == 2) {
|
||||
if(hybrid::get_where(c).second != 0)
|
||||
c->wall = waNone;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(c->land == laHive) return;
|
||||
color_t col;
|
||||
if(hyperbolic)
|
||||
col = rcolor();
|
||||
if(hyperbolic) {
|
||||
hyperpoint h = calc_relative_matrix(c, currentmap->gamestart(), C0) * C0;
|
||||
col = rainbow_color(h);
|
||||
}
|
||||
else if(nil) {
|
||||
part(col, 0) = 128 + c->master->zebraval * 50;
|
||||
part(col, 1) = 128 + c->master->emeraldval * 50;
|
||||
@ -76,11 +112,58 @@ int args() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-qtm-stripe")) {
|
||||
mode = 1;
|
||||
}
|
||||
else if(argis("-qtm-no-stripe")) {
|
||||
mode = 0;
|
||||
}
|
||||
else if(argis("-qtm-stripe-only")) {
|
||||
mode = 2;
|
||||
}
|
||||
else if(argis("-qtm")) {
|
||||
PHASEFROM(2);
|
||||
qtm_on = true;
|
||||
}
|
||||
|
||||
else if(argis("-spheredemo")) {
|
||||
start_game();
|
||||
auto c = currentmap->allcells();
|
||||
for(cell* cx: c) cx->wall = waNone, cx->item = itNone, cx->land = laCanvas, cx->landparam = 0;
|
||||
c[1]->wall = waPalace;
|
||||
c[1]->land = laPalace;
|
||||
int N = isize(c);
|
||||
|
||||
int i = 1+N/4;
|
||||
int j = 1+2*N/4 + 4;
|
||||
int k = 1+3*N/4;
|
||||
j %= N;
|
||||
|
||||
c[i]->wall = waIcewall;
|
||||
c[i]->land = laIce;
|
||||
|
||||
c[j]->wall = waBigTree;
|
||||
c[j]->land = laDryForest;
|
||||
|
||||
c[k]->wall = waWaxWall;
|
||||
c[k]->landparam = 0xFF0000;
|
||||
}
|
||||
|
||||
else if(argis("-two-way")) {
|
||||
start_game();
|
||||
cwt.at->move(0)->wall = waWaxWall;
|
||||
cwt.at->move(0)->landparam = 0xFF0000;
|
||||
|
||||
cwt.at->move(6)->wall = waWaxWall;
|
||||
cwt.at->move(6)->landparam = 0xFFFF40;
|
||||
}
|
||||
|
||||
else if(argis("-one-center")) {
|
||||
start_game();
|
||||
cwt.at->wall = waWaxWall;
|
||||
cwt.at->landparam = 0xFFD500;
|
||||
}
|
||||
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -585,7 +585,7 @@ bool drawVertex(const transmatrix &V, cell *c, shmup::monster *m) {
|
||||
|
||||
int lid = shmup::lmousetarget ? shmup::lmousetarget->pid : -2;
|
||||
|
||||
if(!leftclick) for(int j=0; j<isize(vd.edges); j++) {
|
||||
if(!lshiftclick) for(int j=0; j<isize(vd.edges); j++) {
|
||||
edgeinfo *ei = vd.edges[j].second;
|
||||
vertexdata& vd1 = vdata[ei->i];
|
||||
vertexdata& vd2 = vdata[ei->j];
|
||||
@ -913,10 +913,6 @@ void close() {
|
||||
relmatrices.clear();
|
||||
}
|
||||
|
||||
#ifndef CAP_RVSLIDES
|
||||
#define CAP_RVSLIDES (CAP_TOUR && !ISWEB)
|
||||
#endif
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
@ -1232,7 +1228,7 @@ auto hooks =
|
||||
#if CAP_COMMANDLINE
|
||||
addHook(hooks_args, 100, readArgs) +
|
||||
#endif
|
||||
addHook(clearmemory, 0, close) +
|
||||
addHook(hooks_clearmemory, 0, close) +
|
||||
addHook(hooks_prestats, 100, rogueviz_hud) +
|
||||
addHook(shmup::hooks_draw, 100, drawVertex) +
|
||||
addHook(shmup::hooks_describe, 100, describe_monster) +
|
||||
@ -1240,7 +1236,7 @@ auto hooks =
|
||||
addHook(hooks_o_key, 100, o_key) +
|
||||
|
||||
#if CAP_RVSLIDES
|
||||
addHook(tour::ss::extra_slideshows, 100, [] (bool view) {
|
||||
addHook(tour::ss::hooks_extra_slideshows, 100, [] (bool view) {
|
||||
if(!view) return 1;
|
||||
dialog::addBoolItem(XLAT("RogueViz Tour"), tour::ss::wts == &rvtour::rvslides[0], 'r');
|
||||
dialog::add_action([] { tour::ss::wts = rvtour::gen_rvtour(); popScreen(); });
|
||||
|
@ -6,6 +6,14 @@
|
||||
|
||||
#define RVPATH HYPERPATH "rogueviz/"
|
||||
|
||||
#ifndef CAP_NCONF
|
||||
#define CAP_NCONF 0
|
||||
#endif
|
||||
|
||||
#ifndef CAP_RVSLIDES
|
||||
#define CAP_RVSLIDES (CAP_TOUR && !ISWEB)
|
||||
#endif
|
||||
|
||||
namespace rogueviz {
|
||||
using namespace hr;
|
||||
|
||||
@ -107,11 +115,11 @@ namespace rogueviz {
|
||||
|
||||
extern colorpair dftcolor;
|
||||
|
||||
inline hookset<void(vertexdata&, cell*, shmup::monster*, int)> *hooks_drawvertex;
|
||||
inline hookset<bool(edgeinfo*, bool store)> *hooks_alt_edges;
|
||||
inline hookset<void(vertexdata&, cell*, shmup::monster*, int)> hooks_drawvertex;
|
||||
inline hookset<bool(edgeinfo*, bool store)> hooks_alt_edges;
|
||||
inline purehookset hooks_rvmenu;
|
||||
inline hookset<bool()> *hooks_rvmenu_replace;
|
||||
inline hookset<bool(int&, string&, FILE*)> *hooks_readcolor;
|
||||
inline hookset<bool()> hooks_rvmenu_replace;
|
||||
inline hookset<bool(int&, string&, FILE*)> hooks_readcolor;
|
||||
inline purehookset hooks_close;
|
||||
|
||||
void readcolor(const string& cfname);
|
||||
@ -121,7 +129,7 @@ namespace rogueviz {
|
||||
|
||||
namespace rvtour {
|
||||
using namespace hr::tour;
|
||||
inline hookset<void(vector<slide>&)> *hooks_build_rvtour;
|
||||
inline hookset<void(vector<slide>&)> hooks_build_rvtour;
|
||||
slide *gen_rvtour();
|
||||
|
||||
template<class T> function<void(presmode)> roguevizslide(char c, const T& t) {
|
||||
|
@ -150,6 +150,7 @@ void snow_slide(vector<tour::slide>& v, string title, string desc, reaction_t t)
|
||||
[t] (presmode mode) {
|
||||
setCanvas(mode, '0');
|
||||
|
||||
slidecommand = "auto-movement";
|
||||
if(mode == pmKey) {
|
||||
using namespace anims;
|
||||
tour::slide_backup(ma, ma == maTranslation ? maNone : maTranslation);
|
||||
@ -199,7 +200,7 @@ named_functionality o_key() {
|
||||
|
||||
auto hchook = addHook(hooks_drawcell, 100, draw_snow)
|
||||
|
||||
+ addHook(clearmemory, 40, [] () {
|
||||
+ addHook(hooks_clearmemory, 40, [] () {
|
||||
matrices_at.clear();
|
||||
})
|
||||
|
||||
@ -238,7 +239,7 @@ auto hchook = addHook(hooks_drawcell, 100, draw_snow)
|
||||
|
||||
+ addHook(rvtour::hooks_build_rvtour, 140, [] (vector<tour::slide>& v) {
|
||||
v.push_back(tour::slide{
|
||||
cap+"intro", 10, tour::LEGAL::NONE | tour::QUICKSKIP,
|
||||
cap+"snowball visualization", 10, tour::LEGAL::NONE | tour::QUICKSKIP,
|
||||
"Non-Euclidean visualizations usually show some regular constructions. Could we visualize the geometries themselves? Let's distribute the snowballs randomly."
|
||||
"\n\n"
|
||||
"You can use mouse to look in different directions. Press 5 to turn the automatic movement on or off. Press 'o' to change density and shape."
|
||||
@ -291,16 +292,17 @@ auto hchook = addHook(hooks_drawcell, 100, draw_snow)
|
||||
tour::slide_backup(snow_shape, 2);
|
||||
snow_lambda = 5;
|
||||
});
|
||||
snow_slide(v, "SL(2,R)", "Here is SL(2,R), like Nil but based on hyperbolic plane instead. Geometric lensing effects are strong in both Nil and SL(2,R). (Starting with spherical plane yields spherical geometry.)", [] {
|
||||
snow_slide(v, "SL(2,R)", "Here is SL(2,R), like Nil but based on hyperbolic plane instead. Geometric lensing effects are strong in both Nil and SL(2,R). (Starting with S^2 yields spherical geometry.)", [] {
|
||||
set_geometry(gNormal);
|
||||
set_variation(eVariation::pure);
|
||||
set_geometry(gRotSpace);
|
||||
snow_lambda = 5;
|
||||
});
|
||||
#if CAP_SOLV
|
||||
snow_slide(v, "Solv", "Solv geometry. Like the non-isotropic hyperbolic space (#4) but where the horizontal and vertical curvatures work in the other way.", [] {
|
||||
snow_slide(v, "Solv", "Solv geometry. Like the non-isotropic hyperbolic geometry but where the horizontal and vertical curvatures work in the other way.", [] {
|
||||
set_geometry(gSol);
|
||||
snow_lambda = 20;
|
||||
// tour::slide_backup(snow_shape, 2);
|
||||
snow_lambda = 3;
|
||||
});
|
||||
#endif
|
||||
});
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,14 @@ int how1 = how - 1;
|
||||
// precision: number of substeps to simulate (best if divisible by how and how1)
|
||||
int isteps = 4 * 1024;
|
||||
|
||||
/* the generators correspond to: */
|
||||
|
||||
nilv::mvec a(1,0,0);
|
||||
nilv::mvec b(0,1,0);
|
||||
nilv::mvec c = (a * b).inverse();
|
||||
|
||||
vector<nilv::mvec> gens = { a, b, c, a.inverse(), b.inverse(), c.inverse() };
|
||||
|
||||
struct triangledata {
|
||||
hyperpoint at;
|
||||
bool computed;
|
||||
@ -74,15 +82,15 @@ struct trianglemaker {
|
||||
|
||||
hyperpoint start = point31(0, 0, 0);
|
||||
|
||||
double lastz;
|
||||
|
||||
double lasta;
|
||||
|
||||
double ca;
|
||||
|
||||
// compute how to scale this in Nil so that everything fits
|
||||
|
||||
for(ld a = 1e-5;; a+=1e-5) {
|
||||
ld amin = 0, amax = 1;
|
||||
|
||||
for(int it=0; it<100; it++) {
|
||||
ld a = (amin + amax) / 2;
|
||||
ca = a;
|
||||
hyperpoint at = start;
|
||||
for(int d=0; d<3; d++) {
|
||||
for(int i=0; i<isteps; i++) {
|
||||
@ -92,11 +100,11 @@ struct trianglemaker {
|
||||
|
||||
println(hlog, "at = ", at, " for a = ", a, " sq = ", at[2] / a / a);
|
||||
if(at[2] > 0) {
|
||||
ld z = at[2];
|
||||
ca = lerp(lasta, a, ilerp(lastz, z, 0));
|
||||
break;
|
||||
amax = a;
|
||||
}
|
||||
else {
|
||||
amin = a;
|
||||
}
|
||||
lastz = at[2]; lasta =a;
|
||||
}
|
||||
|
||||
// compute the shift between the cubes
|
||||
@ -111,9 +119,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
|
||||
|
||||
@ -414,7 +422,9 @@ void find_coefficients() {
|
||||
}
|
||||
|
||||
void growthrate() {
|
||||
/*
|
||||
|
||||
cnts.resize(20);
|
||||
|
||||
for(int a=0; a<CTO; a++) {
|
||||
int cnt = 0;
|
||||
map<cell*, int> howmany;
|
||||
@ -427,22 +437,28 @@ void growthrate() {
|
||||
cnts[a] = cnt;
|
||||
if(a >= 4) println(hlog, "D4 = ", cnts[a-4] - 4 * cnts[a-3] + 6 * cnts[a-2] - 4 * cnts[a-1] + cnts[a]);
|
||||
println(hlog, "cnts = ", cnts);
|
||||
}*/
|
||||
}
|
||||
|
||||
cnts = {1,7,31,113,299,681,1363,2501,4181,6570,9874,14256,20027,27601,37171,48815,62993,79912,100181,123868,151680,184339,222347,265733,314523,369424,431221,500952,578350,665794,763300,871250,988488,1116635,1256293,1409165,1575969,1758327,1958977,2174877};
|
||||
find_coefficients();
|
||||
auto cnt2 = cnts;
|
||||
for(int i=isize(cnt2)-1; i>=1; i--) cnt2[i] -= cnt2[i-1];
|
||||
println(hlog, "cnts dif = ", cnt2);
|
||||
|
||||
// this was computed on integers, not using the program above
|
||||
|
||||
cnts =
|
||||
{1,6,24,80,186,368,644,1046,1574,2260,3128,4198,5482,7006,8788,10860,13228,15918,18948,22350,26130,30314,34926,39986,45506,51518,58034,65086,72680,80842,89596,98968,108964,119610,130930,142950,155676,169140,183354,198350,214140,230744,248186,266492,285668,305746,326744,348688,371584,395464,420346,446256,473206,501216,530310,560520,591846,624320,657960,692792,728828,766094,804608,844396,885470,927856,971572,1016650,1063090,1110924,1160176,1210866,1263006,1316622,1371732,1428368,1486536,1546262,1607564,1670474,1734998,1801162,1868990,1938502,2009710,2082646,2157322,2233770,2311996,2392026,2473884,2557596,2643168,2730626,2819994,2911298,3004544,3099764,3196970,3296194,3397448,3500752,3606130,3713608,3823192};
|
||||
|
||||
println(hlog, "coefficients_known = ", coefficients_known);
|
||||
if(coefficients_known == 2) {
|
||||
string fmt = "a(d+" + its(isize(coef)) + ") = ";
|
||||
bool first = true;
|
||||
for(int i=0; i<isize(coef); i++) if(coef[i]) {
|
||||
if(first && coef[i] == 1) ;
|
||||
else if(first) fmt += its(coef[i]);
|
||||
else if(coef[i] == 1) fmt += " + ";
|
||||
else if(coef[i] == -1) fmt += " - ";
|
||||
else if(coef[i] > 1) fmt += " + " + its(coef[i]);
|
||||
else if(coef[i] < -1) fmt += " - " + its(-coef[i]);
|
||||
for(int i=0; i<isize(coef); i++) if(kz(coef[i])) {
|
||||
if(first && !kz(coef[i]-1)) ;
|
||||
else if(first) fmt += fts(coef[i]);
|
||||
else if(!kz(coef[i]-1)) fmt += " + ";
|
||||
else if(!kz(coef[i]+1)) fmt += " - ";
|
||||
else if(coef[i] > 0) fmt += " + " + fts(coef[i]);
|
||||
else if(coef[i] < 0) fmt += " - " + fts(-coef[i]);
|
||||
fmt += "a(d";
|
||||
if(i != isize(coef) - 1)
|
||||
fmt += "+" + its(isize(coef) - 1 - i);
|
||||
@ -464,7 +480,7 @@ bool draw_ptriangle(cell *c, const transmatrix& V) {
|
||||
if(mkr && mkr->icgi != &cgi) reset();
|
||||
|
||||
if(!mkr) { mkr = new trianglemaker; mkr->init();
|
||||
growthrate();
|
||||
// growthrate();
|
||||
}
|
||||
|
||||
for(auto& td: mkr->tds[c]) {
|
||||
@ -523,7 +539,7 @@ auto hchook = addHook(hooks_drawcell, 100, draw_ptriangle)
|
||||
else if(argis("-tri-net")) {
|
||||
on = true; net = true;
|
||||
}
|
||||
else if(argis("-tri-net")) {
|
||||
else if(argis("-tri-one")) {
|
||||
on = true; net = false;
|
||||
}
|
||||
else return 1;
|
||||
|
302
rogueviz/ts2.cpp
302
rogueviz/ts2.cpp
@ -1,302 +0,0 @@
|
||||
#include "../hyper.h"
|
||||
|
||||
// Twisted S2xE.
|
||||
|
||||
// We use a model with coordinates (r,phi,z), where (r,phi) are the polar coordinates in S2.
|
||||
|
||||
// Metric: ds^2 = (dr)^2 + (sin r * dphi)^2 + (dz + K * (1-cos(r)) dphi)^2
|
||||
|
||||
// See https://youtu.be/lZCkEuud6aU and https://youtu.be/rfu6m_xGxWY
|
||||
|
||||
|
||||
namespace hr {
|
||||
|
||||
EX namespace ts2 {
|
||||
|
||||
eGeometry ts2 = eGeometry(-1);
|
||||
|
||||
EX bool in() { return geometry == gTS; }
|
||||
|
||||
EX ld K = -.9;
|
||||
|
||||
EX hyperpoint at = point3(.5, 0, 0);
|
||||
EX transmatrix camera;
|
||||
|
||||
void init() {
|
||||
ld r = .5;
|
||||
at = point3(r, 0, 0);
|
||||
camera = build_matrix(
|
||||
point3(1, 0, 0),
|
||||
point3(0, 1/sin(r), K/sin(r)*(cos(r)-1)),
|
||||
point3(0, 0, 1),
|
||||
point31(0,0,0)
|
||||
);
|
||||
camera = camera * cspin(1, 2, 90*degree);
|
||||
}
|
||||
|
||||
// a dummy map that does nothing
|
||||
struct hrmap_ts2 : hrmap {
|
||||
heptagon *origin;
|
||||
heptagon *getOrigin() override { return origin; }
|
||||
|
||||
struct transmatrix relative_matrix(heptagon *h2, heptagon *h1, const hyperpoint& hint) override {
|
||||
return Id;
|
||||
}
|
||||
|
||||
hrmap_ts2() {
|
||||
init();
|
||||
heptagon*& h =origin;
|
||||
h = tailored_alloc<heptagon> (S7);
|
||||
h->c7 = newCell(S7, h);
|
||||
h->distance = 0;
|
||||
h->dm4 = 0;
|
||||
h->fieldval = 0;
|
||||
h->cdata = NULL;
|
||||
h->alt = NULL;
|
||||
}
|
||||
|
||||
heptagon *create_step(heptagon *parent, int d) override {
|
||||
parent->c.connect(d, parent, d, false);
|
||||
return parent;
|
||||
}
|
||||
|
||||
void draw() override {
|
||||
println(hlog, "at = ", at);
|
||||
for(int i=0; i<3; i++)
|
||||
println(hlog, i, ": ", camera * point3(i==0, i==1, i==2));
|
||||
}
|
||||
};
|
||||
|
||||
EX hrmap* new_map() { return new hrmap_ts2; };
|
||||
|
||||
EX hyperpoint christoffel(const hyperpoint at, const hyperpoint velocity, const hyperpoint transported) {
|
||||
const ld r = at[0];
|
||||
|
||||
hyperpoint c = point3(0,0,0);
|
||||
// const ld r2 = r * r;
|
||||
const ld K2 = K * K;
|
||||
const ld sr = sin(r);
|
||||
// const ld sr2 = sr * sr;
|
||||
|
||||
const ld cr = cos(r) - 1;
|
||||
const ld cr2 = cr * cr;
|
||||
|
||||
c[ 0 ] = 0
|
||||
+ velocity[ 1 ] * transported[ 1 ] * (-K2*(cr) + cos(r))*sr
|
||||
+ velocity[ 1 ] * transported[ 2 ] * K*sr/2
|
||||
+ velocity[ 2 ] * transported[ 1 ] * K*sr/2;
|
||||
c[ 1 ] = 0
|
||||
+ velocity[ 0 ] * transported[ 1 ] * (K2*cos(r) - K2 - 2*cos(r))/(2*sr)
|
||||
+ velocity[ 0 ] * transported[ 2 ] * -K/(2*sr)
|
||||
+ velocity[ 1 ] * transported[ 0 ] * (K2*cos(r) - K2 - 2*cos(r))/(2*sr)
|
||||
+ velocity[ 2 ] * transported[ 0 ] * -K/(2*sr);
|
||||
c[ 2 ] = 0
|
||||
+ velocity[ 0 ] * transported[ 1 ] * K*(K2 - 1)*cr2/(2*sr)
|
||||
+ velocity[ 0 ] * transported[ 2 ] * K2*(1 - cos(r))/(2*sr)
|
||||
+ velocity[ 1 ] * transported[ 0 ] * K*(K2 - 1)*cr2/(2*sr)
|
||||
+ velocity[ 2 ] * transported[ 0 ] * K2*(1 - cos(r))/(2*sr);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void geodesic_step(hyperpoint& at, hyperpoint& velocity) {
|
||||
auto acc = ts2::christoffel(at, velocity, velocity);
|
||||
|
||||
auto at2 = at + velocity / 2;
|
||||
auto velocity2 = velocity + acc / 2;
|
||||
|
||||
auto acc2 = ts2::christoffel(at2, velocity2, velocity2);
|
||||
|
||||
at = at + velocity + acc2 / 2;
|
||||
|
||||
velocity = velocity + acc;
|
||||
}
|
||||
|
||||
EX bool shift_view(hyperpoint dist) {
|
||||
|
||||
if(!in()) return false;
|
||||
|
||||
auto tPos = transpose(camera);
|
||||
hyperpoint h = camera * dist;
|
||||
|
||||
int steps = 100;
|
||||
h /= steps;
|
||||
|
||||
for(int i=0; i<steps; i++) {
|
||||
for(int j=0; j<3; j++)
|
||||
tPos[j] += christoffel(at, h, tPos[j]);
|
||||
geodesic_step(at, h);
|
||||
}
|
||||
|
||||
camera = transpose(tPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
EX bool rotate_view(transmatrix T) {
|
||||
if(!in()) return false;
|
||||
camera = camera * inverse(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
EX void radar() {
|
||||
hyperpoint a = at;
|
||||
hyperpoint v = camera * point3(0,0,1) / 100.;
|
||||
|
||||
int it;
|
||||
for(it=0; it<1000; it++) {
|
||||
geodesic_step(a, v);
|
||||
// if(a[0] < .1) break;
|
||||
|
||||
if(a[0] > .5 && a[0] < .6 && cos(a[1]) > .9 && cos(a[2]) > .9) break;
|
||||
}
|
||||
|
||||
println(hlog, "radar = ", it);
|
||||
}
|
||||
|
||||
void twist() {
|
||||
|
||||
for(K = -2; K<=2; K += .1)
|
||||
for(ld start: {0.5f, 1.f}) {
|
||||
hyperpoint at = point3(start, 0, 0);
|
||||
hyperpoint vel = point3(0, 1e-5, 0);
|
||||
|
||||
// println(hlog, "simulating");
|
||||
|
||||
hyperpoint at1 = at, at2 = at;
|
||||
|
||||
int it = 0;
|
||||
for(; ; it++) {
|
||||
at2 = at1; at1 = at;
|
||||
// if(it % 1000 == 0) println(hlog, format("%6d. ", it), at, " vel = ", vel);
|
||||
geodesic_step(at, vel);
|
||||
|
||||
if(at2[0] > at1[0] && at1[0] < at[0]) break;
|
||||
}
|
||||
|
||||
println(hlog, format("%8d. ", it), lalign(40, kz(at)), " vel = ", lalign(40, kz(vel)), " K = ", K);
|
||||
}
|
||||
}
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-ts2")) {
|
||||
if(ts2 == (eGeometry)(-1)) {
|
||||
ts2 = (eGeometry) isize(ginf);
|
||||
ginf.push_back(geometryinfo{
|
||||
"TS", "none", "TS", "ts", 1, 1, qEXPERIMENTAL | qRAYONLY, giSphere3, 0x31400, {{7, 2}}, eVariation::pure
|
||||
});
|
||||
}
|
||||
set_geometry(ts2);
|
||||
}
|
||||
else if(argis("-twist")) {
|
||||
twist();
|
||||
exit(1);
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto fundamentalhook = addHook(hooks_args, 100, readArgs);
|
||||
|
||||
EX string fragmentshader() {
|
||||
return
|
||||
"varying mediump vec4 at;\n"
|
||||
"uniform mediump vec4 uStart;\n"
|
||||
"uniform mediump mat4 uLP;\n"
|
||||
|
||||
"const float K = float(" + fts(ts2::K) + ");\n"
|
||||
"const float maxdist = 20.;\n"
|
||||
|
||||
"vec4 christoffel(vec4 at, vec4 vel) {\n"
|
||||
"float r = at.x;\n"
|
||||
|
||||
"float K2 = K * K;\n"
|
||||
"float sr = sin(r);\n"
|
||||
"float cr = cos(r) - 1.;\n"
|
||||
"float cr2 = cr * cr;\n"
|
||||
|
||||
"vec4 c;\n"
|
||||
|
||||
"c[ 0 ] = 0.\n"
|
||||
"+ vel.y * vel.y * (-K2*(cr) + cos(r))*sr\n"
|
||||
"+ vel.y * vel.z * K*sr/2.\n"
|
||||
"+ vel.z * vel.y * K*sr/2.;\n"
|
||||
"c[ 1 ] = 0."
|
||||
"+ vel.x * vel.y * (K2*cos(r) - K2 - 2.*cos(r))/(2.*sr)\n"
|
||||
"+ vel.x * vel.z * -K/(2.*sr)\n"
|
||||
"+ vel.y * vel.x * (K2*cos(r) - K2 - 2.*cos(r))/(2.*sr)\n"
|
||||
"+ vel.z * vel.x * -K/(2.*sr);\n"
|
||||
"c[ 2 ] = 0."
|
||||
"+ vel.x * vel.y * K*(K2 - 1.)*cr2/(2.*sr)\n"
|
||||
"+ vel.x * vel.z * K2*(1. - cos(r))/(2.*sr)\n"
|
||||
"+ vel.y * vel.x * K*(K2 - 1.)*cr2/(2.*sr)\n"
|
||||
"+ vel.z * vel.x * K2*(1. - cos(r))/(2.*sr);\n"
|
||||
|
||||
"return c;}\n"
|
||||
|
||||
"void main() {\n"
|
||||
|
||||
" mediump vec4 at0 = at;\n"
|
||||
" at0.y = -at.y;\n"
|
||||
" at0.xyz = at0.xyz / length(at0.xyz);\n"
|
||||
|
||||
" mediump vec4 position = uStart;\n"
|
||||
" mediump vec4 tangent = uLP * at0;\n"
|
||||
|
||||
" tangent = tangent;\n"
|
||||
" float dist = 0.;\n"
|
||||
" int iter = 0;"
|
||||
|
||||
" while(dist < maxdist && iter < 10000) {"
|
||||
|
||||
// we make smaller steps if we are close to the singularities at the poles
|
||||
|
||||
" float step = sin(position.x) * .05;"
|
||||
" dist = dist + step;\n"
|
||||
" iter++;\n"
|
||||
" tangent = tangent * step;\n"
|
||||
|
||||
" vec4 acc = christoffel(position, tangent);"
|
||||
" vec4 at2 = position + tangent / 2.;"
|
||||
" vec4 tangent2 = tangent + acc / 2.;"
|
||||
" vec4 acc2 = christoffel(at2, tangent2);"
|
||||
" position = position + tangent + acc2 / 2.;"
|
||||
" tangent = tangent + acc;\n"
|
||||
" tangent = tangent / step;\n"
|
||||
" if(position.x > .5 && position.x < .6 && cos(position.y) > .9 && cos(position.z/2./K) > .9) {\n"
|
||||
" float bri = float(1. - dist / maxdist);\n"
|
||||
" int e = 0;\n"
|
||||
" if(position.x < .51 || position.x > .59) e++;\n"
|
||||
" if(cos(position.y) < .91) e++;\n"
|
||||
" if(cos(position.z/2./K) < .91) e++;\n"
|
||||
" if(e >= 2) bri /= 2.;\n"
|
||||
" gl_FragColor = vec4(bri, bri, bri, 1.);\n"
|
||||
" return;"
|
||||
" }"
|
||||
" }\n"
|
||||
|
||||
" gl_FragColor = vec4(0.,0.,0.,1.);\n"
|
||||
|
||||
" }";
|
||||
}
|
||||
|
||||
int ah2 = addHook(ray::hooks_rayshader, 100, [] (string &vsh, string &fsh) { fsh = ts2::fragmentshader(); })
|
||||
+ addHook(ray::hooks_rayset, 100, [] (shared_ptr<ray::raycaster> o) {
|
||||
if(!in()) return false;
|
||||
glUniformMatrix4fv(o->uLP, 1, 0, glhr::tmtogl_transpose3(ts2::camera).as_array());
|
||||
auto pg = glhr::pointtogl(ts2::at);
|
||||
glUniform4f(o->uStart, pg[0], pg[1], pg[2], pg[3]);
|
||||
return true;
|
||||
})
|
||||
+ addHook(hooks_newmap, 100, [] () { if(in()) return ts2::new_map(); return (hrmap*) nullptr; })
|
||||
+ addHook(hooks_rotate_view, 100, rotate_view)
|
||||
+ addHook(hooks_shift_view, 100, shift_view)
|
||||
;
|
||||
|
||||
|
||||
EX }
|
||||
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ EX void show_memory_menu() {
|
||||
}
|
||||
|
||||
EX bool protect_memory() {
|
||||
if(!CAP_MEMORY_RESERVE) return false;
|
||||
#if CAP_MEMORY_RESERVE
|
||||
apply_memory_reserve();
|
||||
if(reserve_limit && reserve_count < reserve_limit && !ignored_memory_warning) {
|
||||
pushScreen(show_memory_menu);
|
||||
@ -295,6 +295,7 @@ EX bool protect_memory() {
|
||||
pushScreen(show_memory_menu);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
731
screenshot.cpp
731
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,375 @@ 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
|
||||
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
|
||||
#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 +616,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;
|
||||
@ -281,20 +654,26 @@ EX void default_screenshot_content() {
|
||||
#endif
|
||||
drawfullmap();
|
||||
|
||||
rots::draw_underlying(false);
|
||||
|
||||
if(caption != "")
|
||||
displayfr(vid.xres/2, vid.fsize+vid.fsize/4, 3, vid.fsize*2, caption, forecolor, 8);
|
||||
callhooks(hooks_hqshot);
|
||||
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 +706,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 +765,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 +792,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 +810,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 +831,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,17 +950,29 @@ 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::addItem(XLAT("centering"), 'C');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(vid.fixed_facing_dir, 0, 360, 15, 90, XLAT("centering"),
|
||||
XLAT("You can pick the angle. Note: the direction the PC is facing matters."));
|
||||
dialog::reaction = fullcenter;
|
||||
dialog::extra_options = [] () {
|
||||
dialog::addBoolItem(XLAT("rotate PC"), centering == eCentering::face, 'R');
|
||||
dialog::add_action([] {
|
||||
flipplayer = false;
|
||||
cwt++;
|
||||
mirror::act(1, mirror::SPINSINGLE);
|
||||
cwt.at->mondir++;
|
||||
cwt.at->mondir %= cwt.at->type;
|
||||
fullcenter();
|
||||
});
|
||||
dialog::addBoolItem(XLAT("face"), centering == eCentering::face, 'F');
|
||||
dialog::add_action([] { centering = eCentering::face; fullcenter(); });
|
||||
dialog::addBoolItem(XLAT("edge"), centering == eCentering::edge, 'E');
|
||||
@ -483,18 +990,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 +997,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 +1227,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();
|
||||
@ -770,15 +1268,23 @@ EX string animfile = "animation-%04d.png";
|
||||
|
||||
int min_frame = 0, max_frame = 999999;
|
||||
|
||||
int numturns = 0;
|
||||
|
||||
bool record_animation() {
|
||||
lastticks = 0;
|
||||
ticks = 0;
|
||||
int oldturn = -1;
|
||||
for(int i=0; i<noframes; i++) {
|
||||
if(i < min_frame || i > max_frame) continue;
|
||||
printf("%d/%d\n", i, noframes);
|
||||
int newticks = i * period / noframes;
|
||||
cmode = (env_shmup ? sm::NORMAL : 0);
|
||||
while(ticks < newticks) shmup::turn(1), ticks++;
|
||||
if(cheater && numturns) {
|
||||
int nturn = numturns * i / noframes;
|
||||
if(nturn != oldturn) monstersTurn();
|
||||
oldturn = nturn;
|
||||
}
|
||||
if(playermoved) centerpc(INF), optimizeview();
|
||||
dynamicval<bool> v2(inHighQual, true);
|
||||
apply();
|
||||
@ -987,6 +1493,12 @@ EX void show() {
|
||||
animator(XLATN("Ocean"), env_ocean, 'o');
|
||||
animator(XLATN("Volcanic Wasteland"), env_volcano, 'v');
|
||||
if(shmup::on) dialog::addBoolItem_action(XLAT("shmup action"), env_shmup, 'T');
|
||||
if(cheater) {
|
||||
dialog::addSelItem(XLAT("monster turns"), its(numturns), 'n');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(numturns, 0, 100, 1, 0, XLAT("monster turns"), XLAT("Number of turns to pass. Useful when simulating butterflies or cellular automata."));
|
||||
});
|
||||
}
|
||||
|
||||
#if CAP_RUG
|
||||
if(rug::rugged) {
|
||||
@ -1010,7 +1522,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 +1554,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 +1701,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 +1712,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,28 +1725,32 @@ 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);
|
||||
}};
|
||||
|
||||
startanim rug { "Hypersian Rug", [] {
|
||||
if(!CAP_RUG) { pick(); return; }
|
||||
rug::init(), rug::rugged = false; }, [] {
|
||||
#if CAP_RUG
|
||||
rug::init();
|
||||
rug::rugged = false;
|
||||
#else
|
||||
pick();
|
||||
#endif
|
||||
}, [] {
|
||||
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);
|
||||
|
41
shaders.cpp
41
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;
|
||||
@ -31,6 +32,8 @@ constexpr flagtype SF_ZFOG = 65536;
|
||||
constexpr flagtype SF_ODSBOX = (1<<17);
|
||||
#endif
|
||||
|
||||
EX bool solv_all;
|
||||
|
||||
#if HDR
|
||||
/* standard attribute bindings */
|
||||
/* taken from: https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/attributes.php */
|
||||
@ -62,7 +65,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";
|
||||
@ -180,6 +191,9 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
|
||||
case gcSolNIH:
|
||||
switch(sn::geom()) {
|
||||
case gSol:
|
||||
if(solv_all) {
|
||||
vsh += "\n#define SOLV_ALL\n";
|
||||
}
|
||||
vsh += sn::shader_symsol;
|
||||
break;
|
||||
case gNIH:
|
||||
@ -311,6 +325,7 @@ void display_data::set_projection(int ed) {
|
||||
id <<= 6; id |= spherephase;
|
||||
id <<= 1; if(vid.consider_shader_projection) id |= 1;
|
||||
id <<= 2; id |= (spherespecial & 3);
|
||||
if(sol && solv_all) id |= 1;
|
||||
if(in_h2xe()) id |= 1;
|
||||
if(in_s2xe()) id |= 2;
|
||||
shared_ptr<glhr::GLprogram> selected;
|
||||
@ -359,7 +374,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 +382,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 +422,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 +433,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 +453,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 +471,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);
|
||||
|
24
shmup.cpp
24
shmup.cpp
@ -236,7 +236,7 @@ bool isBullet(monster *m) {
|
||||
bool isPlayer(monster *m) { return m->type == moPlayer; }
|
||||
bool isMonster(monster *m) { return m->type != moPlayer && m->type != moBullet; }
|
||||
|
||||
EX hookset<bool(shmup::monster*)> *hooks_kill;
|
||||
EX hookset<bool(shmup::monster*)> hooks_kill;
|
||||
|
||||
void killMonster(monster* m, eMonster who_kills, flagtype flags = 0) {
|
||||
int tk = tkills();
|
||||
@ -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)
|
||||
@ -2456,7 +2456,7 @@ EX void fixStorage() {
|
||||
for(monster *m: restore) m->store();
|
||||
}
|
||||
|
||||
EX hookset<bool(int)> *hooks_turn;
|
||||
EX hookset<bool(int)> hooks_turn;
|
||||
|
||||
EX void turn(int delta) {
|
||||
|
||||
@ -2771,7 +2771,7 @@ EX bool boatAt(cell *c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EX hookset<bool(const transmatrix&, cell*, shmup::monster*)> *hooks_draw;
|
||||
EX hookset<bool(const transmatrix&, cell*, shmup::monster*)> hooks_draw;
|
||||
|
||||
EX void clearMonsters() {
|
||||
for(mit it = monstersAt.begin(); it != monstersAt.end(); it++)
|
||||
@ -2833,7 +2833,7 @@ EX void virtualRebase(shmup::monster *m) {
|
||||
virtualRebase(m->base, m->at);
|
||||
}
|
||||
|
||||
EX hookset<bool(shmup::monster*, string&)> *hooks_describe;
|
||||
EX hookset<bool(shmup::monster*, string&)> hooks_describe;
|
||||
|
||||
EX void addShmupHelp(string& out) {
|
||||
if(shmup::mousetarget && sqdist(mouseh, tC0(shmup::mousetarget->pat)) < .1) {
|
||||
@ -2844,7 +2844,7 @@ EX void addShmupHelp(string& out) {
|
||||
}
|
||||
}
|
||||
|
||||
auto hooks = addHook(clearmemory, 0, shmup::clearMemory) +
|
||||
auto hooks = addHook(hooks_clearmemory, 0, shmup::clearMemory) +
|
||||
addHook(hooks_gamedata, 0, shmup::gamedata) +
|
||||
addHook(hooks_removecells, 0, [] () {
|
||||
for(mit it = monstersAt.begin(); it != monstersAt.end();) {
|
||||
|
Binary file not shown.
Binary file not shown.
@ -83,7 +83,7 @@ int musfadeval = 2000;
|
||||
|
||||
eLand cid = laNone;
|
||||
|
||||
hookset<bool(eLand&)> *hooks_music;
|
||||
hookset<bool(eLand&)> hooks_music;
|
||||
|
||||
bool music_out_of_focus = false;
|
||||
|
||||
@ -129,7 +129,7 @@ EX void handlemusic() {
|
||||
}
|
||||
}
|
||||
|
||||
hookset<bool(eLand&)> *hooks_resetmusic;
|
||||
hookset<bool(eLand&)> hooks_resetmusic;
|
||||
|
||||
EX void resetmusic() {
|
||||
if(audio && musicvolume) {
|
||||
@ -218,7 +218,7 @@ string wheresounds = SOUNDDESTDIR;
|
||||
string wheresounds = HYPERPATH "sounds/";
|
||||
#endif
|
||||
|
||||
hookset<bool(const string& s, int vol)> *hooks_sound;
|
||||
hookset<bool(const string& s, int vol)> hooks_sound;
|
||||
|
||||
EX void playSound(cell *c, const string& fname, int vol) {
|
||||
LATE( hr::playSound(c, fname, vol); )
|
||||
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user