mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2026-09-09 22:19:11 +00:00
renamed the RogueViz files
This commit is contained in:
@@ -0,0 +1,525 @@
|
||||
// Banach-Tarski animation in RogueViz.
|
||||
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// good parameters: -fixx 10 -W Cros -bantar_anim
|
||||
// use -bantar_map to see how it works
|
||||
|
||||
namespace rogueviz { namespace banachtarski {
|
||||
|
||||
bool on;
|
||||
|
||||
typedef vector<int> cwpath;
|
||||
|
||||
cwpath invertpath(cwpath p) {
|
||||
cwpath res;
|
||||
for(int i=0; i<isize(p); i++)
|
||||
res.push_back(-p[isize(p)-1-i]);
|
||||
return res;
|
||||
}
|
||||
|
||||
array<cwpath, 4> gens;
|
||||
|
||||
cellwalker bttargets[4];
|
||||
|
||||
cellwalker trace(cellwalker cw, cwpath& p) {
|
||||
for(int i: p) if(i == 0) cw += wstep; else cw += i;
|
||||
return cw;
|
||||
}
|
||||
|
||||
set<cell*> testlist;
|
||||
|
||||
map<cell*, cell*> parent;
|
||||
|
||||
bool test_uniq(cellwalker cw, int z, int lev, cell *par) {
|
||||
if(testlist.count(cw.at)) return false;
|
||||
testlist.insert(cw.at);
|
||||
if(par) parent[cw.at] = par;
|
||||
if(celldist(cw.at) > 9) return true;
|
||||
|
||||
/* if(cw.at->wall == waSea) {
|
||||
printf("test_uniq failed\n");
|
||||
cw.at->wall = waEternalFire;
|
||||
}
|
||||
cw.at->wall = waSea; */
|
||||
if(lev) for(int y=0; y<4; y++) if(y != z)
|
||||
if(!test_uniq(trace(cw, gens[y]), y^2, lev-1, cw.at))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T> void recursively(cell *c, cell *c1, const T& t) {
|
||||
t(c);
|
||||
for(int i=0; i<c->type; i++)
|
||||
if(c->move(i) && c->c.spin(i) == 0 && c->move(i) != c1)
|
||||
recursively(c->move(i), c, t);
|
||||
}
|
||||
|
||||
vector<cell*> allcells;
|
||||
|
||||
set<cell*> seen;
|
||||
|
||||
struct cellinfo {
|
||||
cell *c;
|
||||
int gid;
|
||||
int spdist;
|
||||
eWall w;
|
||||
eItem it;
|
||||
eLand land;
|
||||
eMonster mo;
|
||||
vector<int> way;
|
||||
cwpath pinv;
|
||||
};
|
||||
|
||||
map<cell*, cellinfo> infos;
|
||||
|
||||
int cidd = 0;
|
||||
|
||||
int more = 5;
|
||||
|
||||
void debugpath(vector<int>& way, cwpath& pinv) {
|
||||
printf("pinv:"); for(int i: pinv) printf(" %d", i); printf("\n");
|
||||
|
||||
cellwalker cw = cwt;
|
||||
|
||||
cellwalker last_cw = cw;
|
||||
int lastd = 0;
|
||||
|
||||
printf("way:"); for(int i: way) {
|
||||
cellwalker cw2 = trace(cw, pinv);
|
||||
printf(" [%d]", lastd = celldist(cw2.at));
|
||||
printf(" %d", i);
|
||||
last_cw = cw;
|
||||
cw = trace(cw, gens[i]);
|
||||
}
|
||||
|
||||
cellwalker cw2 = trace(cw, pinv);
|
||||
int curd;
|
||||
printf(" [%d]", curd = celldist(cw2.at));
|
||||
printf("\n");
|
||||
|
||||
if(lastd == 10 && curd == 2) {
|
||||
int b = way.back();
|
||||
way.pop_back();
|
||||
printf("CW:"); for(int w: way) for(int wp: gens[w]) printf(" %d", wp);
|
||||
printf(" {");
|
||||
for(int wp: gens[b]) printf(" %d", wp);
|
||||
printf(" }");
|
||||
for(int i: pinv) printf(" %d", i);
|
||||
way.push_back(b);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void recursive_paint(cwpath& pinv, vector<int>& way, int noway) {
|
||||
cellwalker cw = cwt;
|
||||
for(int i: way) cw = trace(cw, gens[i]);
|
||||
cw = trace(cw, pinv);
|
||||
cell *c = cw.at;
|
||||
|
||||
/* if(cidd == 1 && way == vector<int>{1,2,3})
|
||||
c->item = itPirate; */
|
||||
|
||||
if(seen.count(c)) {
|
||||
printf("seen error [%d]\n", celldist(c));
|
||||
debugpath(way, pinv);
|
||||
debugpath(infos[c].way, infos[c].pinv);
|
||||
return;
|
||||
}
|
||||
seen.insert(c);
|
||||
|
||||
int hsh = 7;
|
||||
for(int w: way) hsh = 11301 * hsh + w * 37121;
|
||||
|
||||
bool all0 = true;
|
||||
for(int w: way) if(w) all0 = false;
|
||||
|
||||
int gid;
|
||||
|
||||
/* if(d)
|
||||
c->landparam = 0x202020;
|
||||
else */
|
||||
if(all0 || way[0] == 2)
|
||||
gid = 0;
|
||||
else if(way[0] == 0)
|
||||
gid = 1;
|
||||
else if(way[0] == 1)
|
||||
gid = 2;
|
||||
else if(way[0] == 3)
|
||||
gid = 3;
|
||||
else
|
||||
gid = 3;
|
||||
|
||||
infos[c] = cellinfo{c, gid, 0};
|
||||
infos[c].way = way;
|
||||
infos[c].pinv = pinv;
|
||||
|
||||
// c->landparam ^= ((isize(way)&1) * 0x3F3F3F);
|
||||
// c->landparam = hsh; // d * 5 + 256 * (hsh&0xFFFF) + 0x400000;
|
||||
if(cidd>112899) c->landparam = 0x101010;
|
||||
// c->landparam = cidd * 0x1241C3;
|
||||
|
||||
if(celldist(c) <= 11+more) for(int i=0; i<4; i++) if(i != noway) {
|
||||
vector<int> newway = {i};
|
||||
for(int ii: way) newway.push_back(ii);
|
||||
recursive_paint(pinv, newway, i^2);
|
||||
}
|
||||
}
|
||||
|
||||
bool once = true;
|
||||
|
||||
cwpath path_to(cell *c, int dir = 0) {
|
||||
cwpath p;
|
||||
cellwalker cw(c, dir);
|
||||
while(cw != cwt) {
|
||||
if(celldist((cw+wstep).at) < celldist(cw.at))
|
||||
p.push_back(0), cw += wstep;
|
||||
else {
|
||||
if(p.size() && p.back()) p.back()++;
|
||||
else p.push_back(1);
|
||||
cw += 1;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void bantar_note(cell *c) {
|
||||
if(seen.count(c)) return;
|
||||
|
||||
cwpath pinv = invertpath(path_to(c));
|
||||
|
||||
vector<int> way;
|
||||
recursive_paint(pinv, way, 4);
|
||||
cidd++;
|
||||
}
|
||||
|
||||
using bantar_config = pair<cell*, cell*>;
|
||||
|
||||
tuple<ld,bool,ld> quality(bantar_config cp) {
|
||||
hyperpoint h1 = tC0(ggmatrix(cp.first));
|
||||
hyperpoint h2 = tC0(ggmatrix(cp.second));
|
||||
return make_tuple(hdist0(h1) * hdist0(h2), h2[1] > 0, abs(h2[0] / h2[1]));
|
||||
}
|
||||
|
||||
int notry = 0;
|
||||
|
||||
void bantar() {
|
||||
if(!on) return;
|
||||
cwt = cellwalker(currentmap->gamestart(), 0);
|
||||
viewctr = heptspin(cwt.at->master, 0);
|
||||
infos.clear();
|
||||
|
||||
vector<bantar_config> genchoices;
|
||||
|
||||
int lnotry = notry;
|
||||
|
||||
{
|
||||
celllister clgen(cwt.at, 4, 1000000, NULL);
|
||||
for(cell *c1: clgen.lst) if(c1->type == S7)
|
||||
for(cell *c2: clgen.lst) if(c2->type == S7)
|
||||
genchoices.emplace_back(c1, c2);
|
||||
stable_sort(genchoices.begin(), genchoices.end(), [] (const bantar_config b1, const bantar_config b2) { return quality(b1) < quality(b2); });
|
||||
|
||||
for(bantar_config bc: genchoices) {
|
||||
if(get<0>(quality(bc)) >= 4) exit(1);
|
||||
for(int i=0; i<S7; i++)
|
||||
for(int j=0; j<S7; j++) {
|
||||
gens[0] = path_to(bc.first, i);
|
||||
gens[1] = path_to(bc.second, j);
|
||||
gens[2] = invertpath(gens[0]);
|
||||
gens[3] = invertpath(gens[1]);
|
||||
testlist.clear();
|
||||
parent.clear();
|
||||
bool tres = test_uniq(cwt, -1, 15, NULL);
|
||||
auto q = quality(bc);
|
||||
if(tres) {
|
||||
DEBB(DF_LOG, ("gens = ", gens));
|
||||
DEBB(DF_LOG, ("testing quality ", q, " ", make_pair(celldist(bc.first), celldist(bc.second)), ", result = ", tres));
|
||||
lnotry--; if(lnotry <= 0) goto picked;
|
||||
}
|
||||
// if(tres) goto picked;
|
||||
}
|
||||
}
|
||||
}
|
||||
picked:
|
||||
|
||||
/*
|
||||
if(S7 == 8) {
|
||||
gens[1] = {0,4,0,4};
|
||||
gens[0] = {2,0,2};
|
||||
}
|
||||
else {
|
||||
gens[0] = {0,4,0,4};
|
||||
gens[1] = {2,0,4,0,2};
|
||||
}
|
||||
gens[2] = invertpath(gens[0]);
|
||||
gens[3] = invertpath(gens[1]);
|
||||
*/
|
||||
|
||||
for(int i=0; i<4; i++) bttargets[i] = trace(cwt, gens[i]);
|
||||
|
||||
celllister cl(cwt.at, 8+more, 1000000, NULL);
|
||||
// recursively(cwt.at, NULL, [] (cell *c) { allcells.push_back(c); } );
|
||||
for(cell* c: cl.lst) bantar_note(c);
|
||||
|
||||
for(cell *c: cl.lst) if(infos.count(c) && infos[c].gid == 0)
|
||||
forCellEx(c2, c) if(infos.count(c2) && infos[c2].gid != 0)
|
||||
c->bardir = NOBARRIERS;
|
||||
|
||||
for(int it=0; it<ittypes; it++) if(itemclass(eItem(it)) == IC_TREASURE)
|
||||
items[it] = 200;
|
||||
}
|
||||
|
||||
vector<int> spdist;
|
||||
|
||||
int curpart;
|
||||
|
||||
/* bool hidebad(cell *c, const transmatrix& V) {
|
||||
if(c->wparam != curpart && curpart < 4) return true;
|
||||
return false;
|
||||
} */
|
||||
|
||||
heptspin cth(cellwalker cw) {
|
||||
return heptspin(cw.at->master, cw.spin, cw.mirrored);
|
||||
}
|
||||
|
||||
ld alphaof(hyperpoint h) {
|
||||
return atan2(h[1], h[0]);
|
||||
}
|
||||
|
||||
#define ForInfos for(auto& cci: infos)
|
||||
|
||||
void bantar_frame() {
|
||||
setGLProjection();
|
||||
|
||||
ForInfos
|
||||
cci.second.w = cci.second.c->wall,
|
||||
cci.second.it = cci.second.c->item,
|
||||
cci.second.mo = cci.second.c->monst,
|
||||
cci.second.land = cci.second.c->land,
|
||||
cci.second.c->wparam = cci.second.gid;
|
||||
|
||||
calcparam();
|
||||
|
||||
vector<unique_ptr<drawqueueitem>> subscr[4];
|
||||
|
||||
compute_graphical_distance();
|
||||
|
||||
const int tmax = 2000;
|
||||
int t = ticks % (5*tmax);
|
||||
int tphase = t / tmax, tsub = t % tmax;
|
||||
ld xdst, ydst;
|
||||
|
||||
for(int i=0; i<4; i++) {
|
||||
|
||||
ptds.clear();
|
||||
|
||||
cellwalker xcw;
|
||||
ld part = 1;
|
||||
if(i == 1) xcw = bttargets[0];
|
||||
else if(i == 2) xcw = bttargets[1], part = .5;
|
||||
else if(i == 3) xcw = bttargets[3], part = .5;
|
||||
else xcw = cwt;
|
||||
|
||||
View = Id;
|
||||
|
||||
transmatrix tView = actualV(cth(xcw), Id) * calc_relative_matrix(cwt.at, xcw.at, NOHINT) * inverse(actualV(cth(cwt), Id));
|
||||
|
||||
if(tphase < 2) part = 0;
|
||||
else if(tphase == 2)
|
||||
part = part * tsub / tmax;
|
||||
|
||||
transmatrix itView = inverse(tView);
|
||||
transmatrix z = rspintox(itView*C0) * xpush(hdist0(itView*C0) * part) * spintox(itView*C0);
|
||||
transmatrix ful = rspintox(itView*C0) * xpush(hdist0(itView*C0) * tmax / tmax) * spintox(itView*C0); // rgpushxto0(itView*C0);
|
||||
hyperpoint C1 = xpush0(1);
|
||||
ld bof = alphaof(tView * ful * C1);
|
||||
z = z * spin(bof * part);
|
||||
View = inverse(z);
|
||||
|
||||
if(tphase == 0 && tsub > tmax/2) {
|
||||
ld alpha = rand() % 10;
|
||||
ld d = (rand() % 1000) / 20000. * (tsub-tmax/2) / (tmax/2);
|
||||
View = spin(alpha) * xpush(d) * spin(-alpha);
|
||||
}
|
||||
|
||||
/* int phasemask = 3;
|
||||
if(tphase == 0) phasemask = 0;
|
||||
if(tphase == 4) phasemask = 2; */
|
||||
|
||||
ForInfos if(cci.second.gid == i)
|
||||
cci.second.c->wall = cci.second.w,
|
||||
cci.second.c->item = cci.second.it,
|
||||
cci.second.c->monst = cci.second.mo,
|
||||
cci.second.c->land = cci.second.land;
|
||||
else
|
||||
cci.second.c->wall = waInvisibleFloor,
|
||||
cci.second.c->item = itNone,
|
||||
cci.second.c->monst = moNone,
|
||||
cci.second.c->land = laNone;
|
||||
|
||||
mapeditor::drawplayer = cwt.at->wparam == i;
|
||||
|
||||
switch(tphase) {
|
||||
case 0:
|
||||
xdst = ydst = 0;
|
||||
curpart = 4;
|
||||
break;
|
||||
case 1:
|
||||
xdst = ydst = .5 * tsub / tmax;
|
||||
break;
|
||||
case 2:
|
||||
xdst = ydst = .5;
|
||||
break;
|
||||
case 3:
|
||||
xdst = .5, ydst = .5 * (tmax-tsub) / tmax;
|
||||
break;
|
||||
case 4:
|
||||
xdst = .5, ydst = 0;
|
||||
break;
|
||||
default:
|
||||
xdst = ydst = 0;
|
||||
}
|
||||
|
||||
/* ld xpos = (!(i&2)) ? xdst : -xdst;
|
||||
ld ypos = (!(i&1)) ? ydst : -ydst; */
|
||||
|
||||
gmatrix.clear();
|
||||
|
||||
currentmap->draw();
|
||||
if(0) for(auto p: parent) if(gmatrix.count(p.first) && gmatrix.count(p.second) && infos[p.first].gid == i && infos[p.second].gid == i)
|
||||
queueline(tC0(gmatrix[p.first]), tC0(gmatrix[p.second]), 0xFFFFFFFF, 2);
|
||||
subscr[i] = move(ptds);
|
||||
}
|
||||
|
||||
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;
|
||||
calcparam();
|
||||
drawqueue();
|
||||
}
|
||||
|
||||
ForInfos
|
||||
cci.second.c->wall = cci.second.w,
|
||||
cci.second.c->item = cci.second.it,
|
||||
cci.second.c->monst = cci.second.mo,
|
||||
cci.second.c->land = cci.second.land;
|
||||
}
|
||||
|
||||
void bantar_anim() {
|
||||
|
||||
vid.aurastr = 0;
|
||||
bool breakanim = false;
|
||||
int t = SDL_GetTicks();
|
||||
drawthemap();
|
||||
while(!breakanim) {
|
||||
ticks = SDL_GetTicks() - t;
|
||||
|
||||
bantar_frame();
|
||||
|
||||
SDL_GL_SwapBuffers();
|
||||
SDL_Event ev;
|
||||
while(SDL_PollEvent(&ev))
|
||||
if(ev.type == SDL_KEYDOWN || ev.type == SDL_MOUSEBUTTONDOWN)
|
||||
breakanim = true;
|
||||
}
|
||||
mapeditor::drawplayer = true;
|
||||
vid.xposition = vid.yposition = 0;
|
||||
vid.scale = 1;
|
||||
}
|
||||
|
||||
bool bmap;
|
||||
|
||||
void bantar_stats() {
|
||||
if(bmap) {
|
||||
vid.linewidth *= (inHighQual ? 10 : 2);
|
||||
for(auto p: parent) if(gmatrix.count(p.first) && gmatrix.count(p.second))
|
||||
queueline(tC0(gmatrix[p.first]), tC0(gmatrix[p.second]), 0x00FF00FF, 4);
|
||||
|
||||
double x = cgi.hexvdist;
|
||||
for(auto gm: gmatrix) for(cell *c: {gm.first})
|
||||
if(euclid || !pseudohept(c)) for(int t=0; t<c->type; t++) if(infos.count(c) && infos.count(c->move(t)) && c->move(t) && infos[c].gid != infos[c->move(t)].gid)
|
||||
if(euclid ? c->move(t)<c : (((t^1)&1) || c->move(t) < c))
|
||||
queueline(gm.second * ddspin(c,t,-M_PI/S6) * xpush(x) * C0,
|
||||
gm.second * ddspin(c,t,+M_PI/S6) * xpush(x) * C0,
|
||||
0xFF0000FF, 1);
|
||||
vid.linewidth /= (inHighQual ? 10 : 2);
|
||||
drawqueue();
|
||||
}
|
||||
}
|
||||
|
||||
void init_bantar() {
|
||||
if(!on) {
|
||||
stop_game();
|
||||
on = true;
|
||||
start_game();
|
||||
}
|
||||
}
|
||||
|
||||
void init_bantar_map() {
|
||||
bmap = true;
|
||||
ForInfos {
|
||||
int hsh = 0x202047;
|
||||
for(int w: cci.second.way) hsh = (11301 * hsh + w * 37121) & 0x7F7F7F;
|
||||
cci.second.c->landparam = hsh;
|
||||
cci.second.c->land = laCanvas;
|
||||
cci.second.c->wall = waNone;
|
||||
cci.second.c->item = itNone;
|
||||
cci.second.c->monst = moNone;
|
||||
}
|
||||
}
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-bantar_anim")) {
|
||||
PHASE(3);
|
||||
init_bantar();
|
||||
peace::on = true;
|
||||
airmap.clear();
|
||||
ForInfos if(cci.second.c->monst == moAirElemental)
|
||||
cci.second.c->monst = moFireElemental;
|
||||
bantar_anim();
|
||||
}
|
||||
else if(argis("-bantar_test")) {
|
||||
PHASE(3);
|
||||
init_bantar();
|
||||
peace::on = true;
|
||||
airmap.clear();
|
||||
ForInfos if(cci.second.c->monst == moAirElemental)
|
||||
cci.second.c->monst = moFireElemental;
|
||||
ForInfos if(cci.second.gid != 2)
|
||||
cci.second.c->wall = waInvisibleFloor,
|
||||
cci.second.c->item = itNone,
|
||||
cci.second.c->monst = moNone,
|
||||
cci.second.c->land = laNone;
|
||||
airmap.clear();
|
||||
havewhat = 0;
|
||||
}
|
||||
else if(argis("-bantar_map")) {
|
||||
init_bantar();
|
||||
init_bantar_map();
|
||||
}
|
||||
else if(argis("-btry")) {
|
||||
shift(); notry = argi();
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto hook = addHook(hooks_args, 100, readArgs)
|
||||
+ addHook(hooks_initgame, 100, bantar)
|
||||
+ addHook(hooks_frame, 100, bantar_stats);
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright (C) 2018 Zeno and Tehora Rogue, see 'hyper.cpp' for details
|
||||
// this is a plugin which generates branched tilings for newconformist
|
||||
// https://github.com/zenorogue/newconformist (see the option '-cvl')
|
||||
|
||||
namespace hr {
|
||||
#if CAP_SHOT
|
||||
struct location {
|
||||
transmatrix lView;
|
||||
heptspin lviewctr;
|
||||
};
|
||||
|
||||
struct lineinfo {
|
||||
vector<location> locs;
|
||||
int plus_matrices;
|
||||
int minus_matrices;
|
||||
};
|
||||
|
||||
map<int, lineinfo> lines;
|
||||
|
||||
location loc_multiply(location orig, transmatrix T) {
|
||||
dynamicval<transmatrix> dv(View, orig.lView);
|
||||
dynamicval<heptspin> dc(viewctr, orig.lviewctr);
|
||||
View = inverse(T) * View;
|
||||
for(int a=0; a<10; a++) optimizeview();
|
||||
return location{View, viewctr};
|
||||
}
|
||||
|
||||
bool show_map = false;
|
||||
|
||||
void cvl_marker() {
|
||||
if(show_map) for(auto& l: lines) {
|
||||
int id = 0;
|
||||
for(auto& loc: l.second.locs) {
|
||||
if(gmatrix.count(loc.lviewctr.at->c7)) {
|
||||
transmatrix T = gmatrix[loc.lviewctr.at->c7] * inverse(spin(loc.lviewctr.spin*2*M_PI/S7 + master_to_c7_angle())) * inverse(loc.lView);
|
||||
queuepoly(T, cgi.shAsymmetric, 0xFF00FFFF);
|
||||
queuestr(T, 1.0, its(l.first)+"/"+its(id), 0xFFFFFF);
|
||||
}
|
||||
id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-cvlbuild")) {
|
||||
PHASEFROM(3);
|
||||
start_game();
|
||||
shift();
|
||||
fhstream f(argcs(), "rt");
|
||||
if(!f.f) { shift(); printf("failed to open file\n"); return 0; }
|
||||
int id;
|
||||
lineinfo l0;
|
||||
scan(f, id, l0.plus_matrices, l0.minus_matrices);
|
||||
l0.locs.push_back(location{View, viewctr});
|
||||
for(int i=1; i<l0.plus_matrices; i++)
|
||||
l0.locs.push_back(loc_multiply(l0.locs.back(), xpush(1)));
|
||||
lines[id] = std::move(l0);
|
||||
|
||||
while(true) {
|
||||
scan(f, id);
|
||||
println(hlog, "id=", id, ".");
|
||||
if(id < 0) break;
|
||||
auto& l1 = lines[id];
|
||||
int step;
|
||||
scan(f, id, step);
|
||||
transmatrix T;
|
||||
for(int a=0; a<9; a++) scan(f, T[0][a]);
|
||||
scan(f, l1.plus_matrices, l1.minus_matrices);
|
||||
auto old = lines[id].locs[step];
|
||||
println(hlog, "FROM ", old.lView, old.lviewctr, " id=", id, " step=", step);
|
||||
l1.locs.push_back(loc_multiply(old, T));
|
||||
println(hlog, "TO ", l1.locs.back().lView, l1.locs.back().lviewctr, "; creating ", l1.plus_matrices);
|
||||
for(int i=1; i<l1.plus_matrices; i++)
|
||||
l1.locs.push_back(loc_multiply(l1.locs.back(), xpush(1)));
|
||||
println(hlog, "LAST ", l1.locs.back().lView, l1.locs.back().lviewctr);
|
||||
}
|
||||
}
|
||||
else if(argis("-cvllist")) {
|
||||
for(auto& l: lines)
|
||||
for(auto& loc: l.second.locs) {
|
||||
println(hlog, l.first, ". ", loc.lviewctr, " (dist=", celldist(loc.lviewctr.at->c7), "), View = ", loc.lView);
|
||||
}
|
||||
}
|
||||
else if(argis("-cvlmap")) {
|
||||
show_map = !show_map;
|
||||
}
|
||||
else if(argis("-cvldraw")) {
|
||||
shift(); string s = args();
|
||||
for(auto& p: lines) {
|
||||
int i = 0;
|
||||
for(auto& loc: p.second.locs) {
|
||||
dynamicval<transmatrix> dv(View, loc.lView);
|
||||
dynamicval<heptspin> dc(viewctr, loc.lviewctr);
|
||||
shot::take(format(s.c_str(), p.first, i++));
|
||||
}
|
||||
}
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto magichook = addHook(hooks_args, 100, readArgs) + addHook(hooks_frame, 100, cvl_marker);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
// flocking simulations
|
||||
// Copyright (C) 2018 Zeno and Tehora Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// based on Flocking by Daniel Shiffman (which in turn implements Boids by Craig Reynold)
|
||||
// https://processing.org/examples/flocking.html
|
||||
|
||||
// Our implementation simplifies some equations a bit.
|
||||
|
||||
// example parameters:
|
||||
|
||||
// flocking on a torus:
|
||||
// -tpar 21,4 -geo 6 -flocking 10 -rvshape 3
|
||||
|
||||
// flocking on the Zebra quotient:
|
||||
// -geo 4 -flocking 10 -rvshape 3 -zoom .9
|
||||
|
||||
// press 'o' when flocking active to change the parameters.
|
||||
|
||||
#ifndef NO_THREADS
|
||||
#include <thread>
|
||||
int threads = 1;
|
||||
#endif
|
||||
|
||||
template<class T> auto parallelize(long long N, T action) -> decltype(action(0,0)) {
|
||||
#ifdef NO_THREADS
|
||||
return action(0,N);
|
||||
#else
|
||||
if(threads == 1) return action(0,N);
|
||||
std::vector<std::thread> v;
|
||||
typedef decltype(action(0,0)) Res;
|
||||
std::vector<Res> results(threads);
|
||||
for(int k=0; k<threads; k++)
|
||||
v.emplace_back([&,k] () {
|
||||
results[k] = action(N*k/threads, N*(k+1)/threads);
|
||||
});
|
||||
for(std::thread& t:v) t.join();
|
||||
Res res = 0;
|
||||
for(Res r: results) res += r;
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace rogueviz {
|
||||
|
||||
namespace flocking {
|
||||
|
||||
int N;
|
||||
|
||||
bool draw_lines = false;
|
||||
|
||||
int follow = 0;
|
||||
string follow_names[3] = {"nothing", "specific boid", "center of mass"};
|
||||
|
||||
map<cell*, map<cell*, transmatrix>> relmatrices;
|
||||
|
||||
ld ini_speed = .5;
|
||||
ld max_speed = 1;
|
||||
|
||||
ld sep_factor = 1.5;
|
||||
ld sep_range = .25;
|
||||
|
||||
ld align_factor = 1;
|
||||
ld align_range = .5;
|
||||
|
||||
ld coh_factor = 1;
|
||||
ld coh_range = 2.5;
|
||||
|
||||
ld check_range = 2.5;
|
||||
|
||||
char shape = 'b';
|
||||
|
||||
vector<tuple<hyperpoint, hyperpoint, color_t> > lines;
|
||||
|
||||
// parameters of each boid
|
||||
// m->base: the cell it is currently on
|
||||
// m->vel: velocity
|
||||
// m->at: determines the position and speed:
|
||||
// m->at * (0, 0, 1) is the current position (in Minkowski hyperboloid coordinates relative to m->base)
|
||||
// m->at * (m->vel, 0, 0) is the current velocity vector (tangent to the Minkowski hyperboloid)
|
||||
// m->pat: like m->at but relative to the screen
|
||||
|
||||
void init() {
|
||||
if(!bounded) {
|
||||
addMessage("Flocking simulation needs a bounded space.");
|
||||
return;
|
||||
}
|
||||
stop_game();
|
||||
rogueviz::init(); kind = kFlocking;
|
||||
vdata.resize(N);
|
||||
|
||||
const auto v = currentmap->allcells();
|
||||
|
||||
printf("computing relmatrices...\n");
|
||||
// relmatrices[c1][c2] is the matrix we have to multiply by to
|
||||
// change from c1-relative coordinates to c2-relative coordinates
|
||||
for(cell* c1: v) {
|
||||
manual_celllister cl;
|
||||
cl.add(c1);
|
||||
for(int i=0; i<isize(cl.lst); i++) {
|
||||
cell *c2 = cl.lst[i];
|
||||
transmatrix T = calc_relative_matrix(c2, c1, C0);
|
||||
if(hdist0(tC0(T)) <= check_range) {
|
||||
relmatrices[c1][c2] = T;
|
||||
forCellEx(c3, c2) cl.add(c3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("setting up...\n");
|
||||
for(int i=0; i<N; i++) {
|
||||
vertexdata& vd = vdata[i];
|
||||
// set initial base and at to random cell and random position there
|
||||
createViz(i, v[hrand(isize(v))], spin(hrand(100)) * xpush(hrand(100) / 200.));
|
||||
vd.name = its(i+1);
|
||||
vd.cp = dftcolor;
|
||||
vd.cp.color2 = ((hrand(0x1000000) << 8) + 0xFF) | 0x808080FF;
|
||||
vd.cp.shade = shape;
|
||||
vd.m->vel = ini_speed;
|
||||
}
|
||||
|
||||
storeall();
|
||||
printf("done\n");
|
||||
}
|
||||
|
||||
int precision = 10;
|
||||
|
||||
void simulate(int delta) {
|
||||
int iter = 0;
|
||||
while(delta > precision && iter < 100) {
|
||||
simulate(precision); delta -= precision;
|
||||
iter++;
|
||||
}
|
||||
ld d = delta / 1000.;
|
||||
int N = isize(vdata);
|
||||
vector<transmatrix> pats(N);
|
||||
vector<ld> vels(N);
|
||||
using shmup::monster;
|
||||
|
||||
map<cell*, vector<monster*>> monsat;
|
||||
|
||||
for(int i=0; i<N; i++) {
|
||||
vertexdata& vd = vdata[i];
|
||||
auto m = vd.m;
|
||||
monsat[m->base].push_back(m);
|
||||
}
|
||||
|
||||
lines.clear();
|
||||
|
||||
parallelize(N, [&monsat, &d, &vels, &pats] (int a, int b) { for(int i=a; i<b; i++) {
|
||||
vertexdata& vd = vdata[i];
|
||||
auto m = vd.m;
|
||||
|
||||
transmatrix I = inverse(m->at);
|
||||
|
||||
// we do all the computations here in the frame of reference
|
||||
// where m is at (0,0,1) and its velocity is (m->vel,0,0)
|
||||
|
||||
hyperpoint velvec = hpxyz(m->vel, 0, 0);
|
||||
|
||||
hyperpoint sep = hpxyz(0, 0, 0);
|
||||
int sep_count = 0;
|
||||
|
||||
hyperpoint align = hpxyz(0, 0, 0);
|
||||
int align_count = 0;
|
||||
|
||||
hyperpoint coh = hpxyz(0, 0, 0);
|
||||
int coh_count = 0;
|
||||
|
||||
for(auto& p: relmatrices[m->base]) {
|
||||
auto f = monsat.find(p.first);
|
||||
if(f != monsat.end()) for(auto m2: f->second) if(m != m2) {
|
||||
ld vel2 = m2->vel;
|
||||
transmatrix at2 = I * p.second * m2->at;
|
||||
|
||||
// at2 is like m2->at but relative to m->at
|
||||
|
||||
// m2's position relative to m (tC0 means *(0,0,1))
|
||||
hyperpoint ac = tC0(at2);
|
||||
|
||||
// distance and azimuth to m2
|
||||
ld di = hdist0(ac);
|
||||
transmatrix alphaspin = rspintox(ac); // spin(-atan2(ac));
|
||||
|
||||
color_t col = 0;
|
||||
|
||||
if(di < align_range) {
|
||||
// we need to transfer m2's velocity vector to m's position
|
||||
// this is done by applying an isometry which sends m2 to m1
|
||||
// and maps the straight line on which m1 and m2 are to itself
|
||||
align += gpushxto0(ac) * at2 * hpxyz(vel2, 0, 0);
|
||||
align_count++;
|
||||
col |= 0xFF0040;
|
||||
}
|
||||
|
||||
if(di < coh_range) {
|
||||
// azimuthal equidistant projection of ac
|
||||
// (thus the cohesion force pushes us towards the
|
||||
// average of azimuthal equidistant projections)
|
||||
coh += alphaspin * hpxyz(di, 0, 0);
|
||||
coh_count++;
|
||||
col |= 0xFF40;
|
||||
}
|
||||
|
||||
if(di < sep_range && di > 0) {
|
||||
sep -= alphaspin * hpxyz(1 / di, 0, 0);
|
||||
sep_count++;
|
||||
col |= 0xFF000040;
|
||||
}
|
||||
|
||||
if(col && draw_lines)
|
||||
lines.emplace_back(m->pat * C0, m->pat * at2 * C0, col);
|
||||
}
|
||||
}
|
||||
|
||||
// a bit simpler rules than original
|
||||
|
||||
if(sep_count) velvec += sep * (d * sep_factor / sep_count);
|
||||
if(align_count) velvec += align * (d * align_factor / align_count);
|
||||
if(coh_count) velvec += coh * (d * coh_factor / coh_count);
|
||||
|
||||
// hypot2 is the length of a vector in R^2
|
||||
vels[i] = hypot_d(2, velvec);
|
||||
|
||||
transmatrix alphaspin = rspintox(velvec); // spin(-atan2(velvec));
|
||||
|
||||
if(vels[i] > max_speed) {
|
||||
velvec = velvec * (max_speed / vels[i]);
|
||||
vels[i] = max_speed;
|
||||
}
|
||||
|
||||
pats[i] = m->at * alphaspin * xpush(vels[i] * d);
|
||||
fixmatrix(pats[i]);
|
||||
} return 0; });
|
||||
|
||||
for(int i=0; i<N; i++) {
|
||||
vertexdata& vd = vdata[i];
|
||||
auto m = vd.m;
|
||||
// these two functions compute new base and at, based on pats[i]
|
||||
m->at = pats[i];
|
||||
virtualRebase(m, true);
|
||||
m->vel = vels[i];
|
||||
}
|
||||
shmup::fixStorage();
|
||||
|
||||
}
|
||||
|
||||
bool turn(int delta) {
|
||||
if(!on) return false;
|
||||
if(kind == kFlocking) simulate(delta), timetowait = 0;
|
||||
|
||||
if(follow) {
|
||||
|
||||
if(follow == 1) {
|
||||
gmatrix.clear();
|
||||
vdata[0].m->pat = View * calc_relative_matrix(vdata[0].m->base, viewctr.at->c7, C0) * vdata[0].m->at;
|
||||
View = spin(90 * degree) * inverse(vdata[0].m->pat) * View;
|
||||
if(GDIM == 3) {
|
||||
View = hr::cspin(1, 2, 90 * degree) * View;
|
||||
}
|
||||
}
|
||||
|
||||
if(follow == 2) {
|
||||
// we take the average in R^3 of all the boid positions of the Minkowski hyperboloid
|
||||
// (in quotient spaces, the representants closest to the current view
|
||||
// are taken), and normalize the result to project it back to the hyperboloid
|
||||
// (the same method is commonly used on the sphere AFAIK)
|
||||
hyperpoint h = Hypc;
|
||||
for(int i=0; i<N; i++) if(gmatrix.count(vdata[i].m->base)) {
|
||||
vdata[i].m->pat = gmatrix[vdata[i].m->base] * vdata[i].m->at;
|
||||
h += tC0(vdata[i].m->pat);
|
||||
}
|
||||
h = normalize(h);
|
||||
View = gpushxto0(h) * View;
|
||||
}
|
||||
|
||||
optimizeview();
|
||||
centerover.at = viewctr.at->c7;
|
||||
compute_graphical_distance();
|
||||
gmatrix.clear();
|
||||
playermoved = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
// shmup::pc[0]->rebase();
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
// options before reading
|
||||
if(0) ;
|
||||
else if(argis("-flocking")) {
|
||||
PHASEFROM(2);
|
||||
shift(); N = argi();
|
||||
init();
|
||||
}
|
||||
else if(argis("-cohf")) {
|
||||
shift(); coh_factor = argf();
|
||||
}
|
||||
else if(argis("-alignf")) {
|
||||
shift(); align_factor = argf();
|
||||
}
|
||||
else if(argis("-sepf")) {
|
||||
shift(); sep_factor = argf();
|
||||
}
|
||||
else if(argis("-checkr")) {
|
||||
shift(); check_range = argf();
|
||||
}
|
||||
else if(argis("-cohr")) {
|
||||
shift(); coh_range = argf();
|
||||
}
|
||||
else if(argis("-alignr")) {
|
||||
shift(); align_range = argf();
|
||||
}
|
||||
else if(argis("-sepr")) {
|
||||
shift(); sep_range = argf();
|
||||
}
|
||||
else if(argis("-flockfollow")) {
|
||||
shift(); follow = argi();
|
||||
}
|
||||
else if(argis("-flockprec")) {
|
||||
shift(); precision = argi();
|
||||
}
|
||||
else if(argis("-flockshape")) {
|
||||
shift(); shape = argcs()[0];
|
||||
for(int i=0; i<N; i++)
|
||||
vdata[i].cp.shade = shape;
|
||||
}
|
||||
#ifndef NO_THREADS
|
||||
else if(argis("-threads")) {
|
||||
shift(); threads = argi();
|
||||
}
|
||||
#endif
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flock_marker() {
|
||||
if(draw_lines)
|
||||
for(auto p: lines) queueline(get<0>(p), get<1>(p), get<2>(p), 0);
|
||||
}
|
||||
|
||||
void show() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("flocking"), iinf[itPalace].color, 150, 0);
|
||||
|
||||
dialog::addSelItem("initial speed", fts(ini_speed), 'i');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(ini_speed, 0, 2, .1, .5, "", "");
|
||||
});
|
||||
|
||||
dialog::addSelItem("max speed", fts(max_speed), 'm');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(max_speed, 0, 2, .1, .5, "", "");
|
||||
});
|
||||
|
||||
dialog::addSelItem("separation factor", fts(sep_factor), 's');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(sep_factor, 0, 2, .1, 1.5, "", "");
|
||||
});
|
||||
|
||||
string rangehelp = "Increasing this parameter may also require increasing the 'check range' parameter.";
|
||||
|
||||
dialog::addSelItem("separation range", fts(sep_range), 'S');
|
||||
dialog::add_action([rangehelp]() {
|
||||
dialog::editNumber(sep_range, 0, 2, .1, .5, "", rangehelp);
|
||||
});
|
||||
|
||||
dialog::addSelItem("alignment factor", fts(align_factor), 'a');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(align_factor, 0, 2, .1, 1.5, "", "");
|
||||
});
|
||||
|
||||
dialog::addSelItem("alignment range", fts(align_range), 'A');
|
||||
dialog::add_action([rangehelp]() {
|
||||
dialog::editNumber(align_range, 0, 2, .1, .5, "", rangehelp);
|
||||
});
|
||||
|
||||
dialog::addSelItem("cohesion factor", fts(coh_factor), 'c');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(coh_factor, 0, 2, .1, 1.5, "", "");
|
||||
});
|
||||
|
||||
dialog::addSelItem("cohesion range", fts(coh_range), 'C');
|
||||
dialog::add_action([rangehelp]() {
|
||||
dialog::editNumber(coh_range, 0, 2, .1, .5, "", rangehelp);
|
||||
});
|
||||
|
||||
dialog::addSelItem("check range", fts(check_range), 't');
|
||||
dialog::add_action([]() {
|
||||
ld radius = 0;
|
||||
for(cell *c: currentmap->allcells())
|
||||
for(int i=0; i<c->degree(); i++) {
|
||||
hyperpoint h = nearcorner(c, i);
|
||||
radius = max(radius, hdist0(h));
|
||||
}
|
||||
dialog::editNumber(check_range, 0, 2, .1, .5, "",
|
||||
"Value used in the algorithm: "
|
||||
"only other boids in cells whose centers are at most 'check range' from the center of the current cell are considered. "
|
||||
"Should be more than the other ranges by at least double the cell radius (in the current geometry, double the radius is " + fts(radius*2) + "); "
|
||||
"but too large values slow the simulation down.\n\n"
|
||||
"Restart the simulation to apply the changes to this parameter. In quotient spaces, the simulation may not work correctly when the same cell is in range check_range "
|
||||
"in multiple directions."
|
||||
);
|
||||
});
|
||||
|
||||
dialog::addSelItem("number of boids", its(N), 'n');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(N, 0, 1000, 1, 20, "", "");
|
||||
});
|
||||
|
||||
dialog::addSelItem("precision", its(precision), 'p');
|
||||
dialog::add_action([]() {
|
||||
dialog::editNumber(precision, 0, 1000, 1, 10, "", "smaller number = more precise simulation");
|
||||
});
|
||||
|
||||
dialog::addSelItem("change geometry", XLAT(ginf[geometry].shortname), 'g');
|
||||
hr::showquotients = true;
|
||||
dialog::add_action(runGeometryExperiments);
|
||||
|
||||
dialog::addBoolItem_action("draw forces", draw_lines, 'l');
|
||||
|
||||
dialog::addSelItem("follow", follow_names[follow], 'f');
|
||||
dialog::add_action([] () { follow++; follow %= 3; });
|
||||
|
||||
dialog::addBreak(100);
|
||||
|
||||
dialog::addItem("restart", 'r');
|
||||
dialog::add_action(init);
|
||||
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
named_functionality o_key() {
|
||||
if(kind == kFlocking) return named_dialog("flocking", show);
|
||||
return named_functionality();
|
||||
}
|
||||
|
||||
auto hooks =
|
||||
addHook(hooks_args, 100, readArgs) +
|
||||
addHook(shmup::hooks_turn, 100, turn) +
|
||||
addHook(hooks_frame, 100, flock_marker) +
|
||||
addHook(hooks_o_key, 80, o_key) +
|
||||
0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
namespace rogueviz {
|
||||
|
||||
namespace graph {
|
||||
vector<string> formula;
|
||||
bool graph_on;
|
||||
|
||||
color_t graphcolor;
|
||||
|
||||
hyperpoint err = hpxyz(500,0,0);
|
||||
|
||||
bool iserror(hyperpoint h) { return sqhypot_d(2, h) > 10000 || std::isnan(h[0]) || std::isnan(h[1]) || std::isnan(h[2]) || std::isinf(h[0]) || std::isinf(h[1]) || std::isinf(h[2]); }
|
||||
|
||||
hyperpoint xy_to_point(ld x, ld y) {
|
||||
if(sphere && hypot(x, y) > 1)
|
||||
return err;
|
||||
return hpxy(x, y);
|
||||
}
|
||||
|
||||
hyperpoint find_point(ld t) {
|
||||
exp_parser ep;
|
||||
auto &dict = ep.extra_params;
|
||||
dict["t"] = t;
|
||||
dict["phi"] = t * 2 * M_PI;
|
||||
dict["x"] = tan(t * M_PI - M_PI/2);
|
||||
for(auto& ff: formula) {
|
||||
ep.s = ff;
|
||||
string varname = "";
|
||||
ep.at = 0;
|
||||
while(!among(ep.next(), '=', -1)) varname += ep.next(), ep.at++;
|
||||
ep.at++;
|
||||
cld x = ep.parse();
|
||||
if(!ep.ok()) return err;
|
||||
dict[varname] = x;
|
||||
}
|
||||
if(!dict.count("y") && dict.count("r"))
|
||||
return xspinpush0(real(dict["phi"]), real(dict["r"]));
|
||||
if(dict.count("z") && dict.count("x"))
|
||||
return hpxyz(real(dict["x"]), real(dict["y"]), real(dict["z"]));
|
||||
if(dict.count("z")) {
|
||||
return xy_to_point(real(dict["z"]), imag(dict["z"]));
|
||||
}
|
||||
return xy_to_point(real(dict["x"]), real(dict["y"]));
|
||||
}
|
||||
|
||||
hyperpoint gcurvestart = err;
|
||||
|
||||
void xcurvepoint(hyperpoint h) {
|
||||
curvepoint(cwtV * h);
|
||||
if(iserror(gcurvestart))
|
||||
gcurvestart = h;
|
||||
else if(sphere && intval(gcurvestart, h) > .1) {
|
||||
queuecurve(graphcolor, 0, PPR::LINE);
|
||||
curvepoint(cwtV * h);
|
||||
gcurvestart = h;
|
||||
}
|
||||
}
|
||||
|
||||
void finish() {
|
||||
if(!iserror(gcurvestart)) {
|
||||
queuecurve(graphcolor, 0, PPR::LINE);
|
||||
gcurvestart = err;
|
||||
}
|
||||
}
|
||||
|
||||
int small_limit = 6, big_limit = 20;
|
||||
|
||||
void draw_to(ld t0, hyperpoint h0, ld t1, hyperpoint h1, int small = 0, int big = 0) {
|
||||
if(iserror(h0) || iserror(h1) || intval(h0, h1) < .01) small++;
|
||||
else small = 0;
|
||||
if(small >= small_limit || big >= big_limit) {
|
||||
xcurvepoint(h1);
|
||||
return;
|
||||
}
|
||||
if(t1-t0 < 1e-6) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
ld t2 = (t0 + t1) / 2;
|
||||
hyperpoint h2 = find_point(t2);
|
||||
draw_to(t0, h0, t2, h2, small, big+1);
|
||||
draw_to(t2, h2, t1, h1, small, big+1);
|
||||
}
|
||||
|
||||
int editwhich = -1;
|
||||
|
||||
void show_graph() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("graph"));
|
||||
for(int i=0; i<isize(formula); i++) {
|
||||
if(editwhich == i) {
|
||||
dialog::addItem(dialog::view_edited_string(), '1'+i);
|
||||
}
|
||||
else {
|
||||
dialog::addItem(formula[i], editwhich == -1 ? '1'+i : 0);
|
||||
dialog::add_action([i] () { editwhich = i; dialog::start_editing(formula[i]); });
|
||||
}
|
||||
}
|
||||
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
|
||||
keyhandler = [] (int sym, int uni) {
|
||||
if(editwhich >= 0) {
|
||||
if(dialog::handle_edit_string(sym, uni)) ;
|
||||
else if(doexiton(sym, uni))
|
||||
editwhich = -1;
|
||||
}
|
||||
else {
|
||||
handlePanning(sym, uni);
|
||||
dialog::handleNavigation(sym, uni);
|
||||
// if(doexiton(sym, uni)) popScreen();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void frame() {
|
||||
if(graphcolor) {
|
||||
hyperpoint h0 = find_point(0);
|
||||
hyperpoint h1 = find_point(1);
|
||||
if(!iserror(h0)) xcurvepoint(h0);
|
||||
draw_to(0, h0, 1, h1);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-dgraph")) {
|
||||
PHASE(3);
|
||||
showstartmenu = false;
|
||||
pushScreen(show_graph);
|
||||
shift();
|
||||
while(args().find("=") != string::npos) {
|
||||
formula.emplace_back(args());
|
||||
shift();
|
||||
}
|
||||
graphcolor = arghex();
|
||||
}
|
||||
else if(argis("-dgs")) {
|
||||
small_limit = argi();
|
||||
}
|
||||
else if(argis("-dgl")) {
|
||||
big_limit = argi();
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
auto xhook = addHook(hooks_args, 100, readArgs)
|
||||
+ addHook(hooks_frame, 0, frame);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
// show the fundamental domain for quotient spaces
|
||||
// Copyright (C) 2018 Zeno and Tehora Rogue, see 'hyper.cpp' for details
|
||||
|
||||
namespace hr {
|
||||
|
||||
namespace fundamental {
|
||||
|
||||
color_t color1, color2;
|
||||
|
||||
map<cell*, int> same;
|
||||
map<cell*, transmatrix> gm;
|
||||
|
||||
bool is_connected(cellwalker cw) {
|
||||
return same[cw.at] & (1<<cw.spin);
|
||||
}
|
||||
|
||||
void be_connected(cellwalker cw) {
|
||||
// transmatrix T = gm[cw.at];
|
||||
same[cw.at] |= (1<<cw.spin);
|
||||
cw += wstep;
|
||||
same[cw.at] |= (1<<cw.spin);
|
||||
/* printf("%s", display(T * C0));
|
||||
printf(" %s\n", display(gm[cw.at] * C0)); */
|
||||
// queueline(T * C0, gm[cw.at] * C0, 0xFF0000FF, 3);
|
||||
}
|
||||
|
||||
int funmode = 0;
|
||||
|
||||
hyperpoint corner(cellwalker cw) {
|
||||
transmatrix T = gm[cw.at];
|
||||
if(funmode == 2) {
|
||||
while(cw.at->type != S7) {
|
||||
cw++;
|
||||
T = T * calc_relative_matrix(cw.peek(), cw.at, cw.spin);
|
||||
cw += wstep;
|
||||
}
|
||||
return T * C0;
|
||||
}
|
||||
return gm[cw.at] * get_corner_position(cw.at, cw.spin+(cw.mirrored?0:1), 3);
|
||||
}
|
||||
|
||||
transmatrix rel(cellwalker cw) {
|
||||
return calc_relative_matrix(cw.cpeek(), cw.at, cw.spin);
|
||||
}
|
||||
|
||||
ld label_dist = .3;
|
||||
|
||||
transmatrix labelpos(hyperpoint h1, hyperpoint h2) {
|
||||
hyperpoint h = mid(h1, h2);
|
||||
transmatrix T = rgpushxto0(h);
|
||||
hyperpoint hx = inverse(T) * h2;
|
||||
ld alpha = atan2(-hx[1], hx[0]);
|
||||
return T * xspinpush(alpha + M_PI/2, label_dist);
|
||||
}
|
||||
|
||||
ld widthfactor = 5;
|
||||
ld label_scale = 1;
|
||||
|
||||
void fundamental_marker() {
|
||||
if(!funmode || !(quotient || euwrap || elliptic)) return;
|
||||
same.clear();
|
||||
gm.clear();
|
||||
|
||||
same[cwt.at] = 0;
|
||||
gm[cwt.at] = ggmatrix(cwt.at);
|
||||
|
||||
vector<cell*> cells;
|
||||
cells.push_back(cwt.at);
|
||||
|
||||
int tree_edges = 0;
|
||||
int face_edges = 0;
|
||||
|
||||
for(int k=0; k<isize(cells); k++) {
|
||||
cell *c = cells[k];
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cellwalker cw(c, i);
|
||||
cell *c2 = cw.cpeek();
|
||||
if(gm.count(c2)) continue;
|
||||
gm[c2] = gm[c] * rel(cw);
|
||||
// queueline(gm[c2] * C0, gm[c2] * xspinpush0(ticks, 0.2), 0xFFFFFFFF, 3);
|
||||
be_connected(cw);
|
||||
tree_edges++;
|
||||
cells.push_back(c2);
|
||||
}
|
||||
}
|
||||
|
||||
while(true) {
|
||||
int f = face_edges;
|
||||
for(int k=0; k<isize(cells); k++) {
|
||||
cell *c = cells[k];
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cellwalker cw(c, i);
|
||||
if(is_connected(cw) && is_connected(cw+1) && !is_connected(cw+wstep-1)) {
|
||||
face_edges++;
|
||||
be_connected(cw+wstep-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(f == face_edges) break;
|
||||
}
|
||||
|
||||
cellwalker cw;
|
||||
|
||||
int corners = 0;
|
||||
|
||||
for(int k=0; k<isize(cells); k++) {
|
||||
cell *c = cells[k];
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cellwalker cw0(c, i);
|
||||
if(!is_connected(cw0) && !is_connected(cw0+1) && !is_connected(cw0+wstep-1))
|
||||
corners++, cw = cw0;
|
||||
}
|
||||
}
|
||||
|
||||
// printf("tree edges = %d, face edges = %d, corners = %d\n", tree_edges, face_edges, corners);
|
||||
|
||||
map<cellwalker, cellwalker> next_corner;
|
||||
map<cellwalker, cellwalker> prev_corner;
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
cellwalker cw0 = cw;
|
||||
|
||||
while(true) {
|
||||
cw++;
|
||||
if(is_connected(cw)) {
|
||||
cw += wstep;
|
||||
cw++;
|
||||
}
|
||||
if(!is_connected(cw+1) && !is_connected(cw+wstep-1))
|
||||
break;
|
||||
}
|
||||
|
||||
next_corner[cw0] = cw;
|
||||
prev_corner[cw] = cw0;
|
||||
}
|
||||
|
||||
vector<transmatrix> nearm;
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
for(int u=0; u<1; u++) {
|
||||
cellwalker cw1 = cw+u+wstep+(u-1);
|
||||
/* printf("%p/%d %p/%d ", cw.at, cw.spin, cw1.at, cw1.spin);
|
||||
printf("[%d %d %d] ", is_connected(cw), is_connected(cw+1), is_connected(cw+wstep-1));
|
||||
printf("[%d %d %d] ", is_connected(cw1), is_connected(cw1+1), is_connected(cw1+wstep-1));
|
||||
printf("%d %d;\n", !!next_corner.count(cw1), !!next_corner.count(cw1+wmirror-1)); */
|
||||
transmatrix T_here = gm[cw.at] * rel(cw+u);
|
||||
transmatrix T_there = gm[cw1.at];
|
||||
nearm.push_back(T_here * inverse(T_there));
|
||||
}
|
||||
cw = next_corner[cw];
|
||||
}
|
||||
|
||||
vid.linewidth *= widthfactor;
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
|
||||
hyperpoint h = corner(cw);
|
||||
cw = next_corner[cw];
|
||||
hyperpoint h2 = corner(cw);
|
||||
|
||||
for(auto& T: nearm) queueline(T * h, T * h2, color1, 3);
|
||||
}
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
|
||||
hyperpoint h = corner(cw);
|
||||
cw = next_corner[cw];
|
||||
hyperpoint h2 = corner(cw);
|
||||
|
||||
queueline(h, h2, color2, 3);
|
||||
}
|
||||
|
||||
if(0) for(int k=0; k<isize(cells); k++) {
|
||||
cell *c = cells[k];
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cellwalker cw0(c, i);
|
||||
if(!is_connected(cw0)) continue;
|
||||
int v = 0;
|
||||
for(auto& n: nearm) {
|
||||
queueline(n * gm[cw0.at] * xspinpush0(v, .05), n * gm[cw0.cpeek()] * xspinpush0(v, .05), 0xFF8000FF, 0);
|
||||
v++;
|
||||
}
|
||||
queueline(gm[cw0.at] * C0, gm[cw0.cpeek()] * C0, 0xFF0000FF, 0);
|
||||
}
|
||||
}
|
||||
|
||||
set<cellwalker> visited;
|
||||
|
||||
int id = 0;
|
||||
|
||||
for(int ci=0; ci<corners; ci++) {
|
||||
|
||||
cellwalker cw1 = (cw+1+wstep);
|
||||
bool mirrored = false;
|
||||
if(!next_corner.count(cw1)) cw1 = cw1 + wmirror - 1, mirrored = true;
|
||||
|
||||
// visited.insert(next_corner[cw]);
|
||||
// cellwalker cw2 = next_corner[cw];
|
||||
if(next_corner[cw] < (mirrored ? next_corner[cw1] : cw1)) {
|
||||
|
||||
int mc = (mirrored ? color1 : color2) >> 8;
|
||||
if(hdist(corner(cw), corner(next_corner[cw])) > 1e-3) {
|
||||
queuestr(labelpos(corner(cw), corner(next_corner[cw])), label_scale/cgi.scalefactor, its(id), mc);
|
||||
if(mirrored)
|
||||
queuestr(labelpos(corner(cw1), corner(next_corner[cw1])), label_scale/cgi.scalefactor, its(id), mc);
|
||||
else
|
||||
queuestr(labelpos(corner(prev_corner[cw1]), corner(cw1)), label_scale/cgi.scalefactor, its(id), mc);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
cw = next_corner[cw];
|
||||
}
|
||||
|
||||
vid.linewidth /= widthfactor;
|
||||
}
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-fundamental")) {
|
||||
shift(); funmode = argi();
|
||||
shift(); color1 = arghex();
|
||||
shift(); color2 = arghex();
|
||||
shift_arg_formula(widthfactor);
|
||||
shift_arg_formula(label_scale);
|
||||
shift_arg_formula(label_dist);
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto fundamentalhook = addHook(hooks_args, 100, readArgs) + addHook(hooks_frame, 100, fundamental_marker);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,176 @@
|
||||
namespace hr {
|
||||
|
||||
#if CAP_CRYSTAL
|
||||
void performMarkCommand(cell *c);
|
||||
|
||||
namespace crystal {
|
||||
typedef array<int, MAXDIM> coord;
|
||||
heptagon *get_heptagon_at(coord c);
|
||||
coord get_coord(heptagon *h);
|
||||
void set_crystal(int sides);
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
int dim() { return ginf[gCrystal].sides / 2; }
|
||||
|
||||
void build(crystal::coord co, int at) {
|
||||
if(at < dim()) {
|
||||
for(int z: {0,2,-2,4,-4}) co[at] = z, build(co, at+1);
|
||||
return;
|
||||
}
|
||||
for(int i=0; i<S7; i++) crystal::get_heptagon_at(co)->cmove(i);
|
||||
|
||||
int twos = 0, index = 0;
|
||||
for(int a=0; a<dim(); a++)
|
||||
if(co[a] == 4) twos++, index = 2*a;
|
||||
else if(co[a] == -4) twos++, index = 2*a+1;
|
||||
|
||||
auto c = crystal::get_heptagon_at(co)->c7;
|
||||
setdist(c, 7, NULL);
|
||||
if(twos == 0)
|
||||
c->landparam = back;
|
||||
else if(twos == 1)
|
||||
c->landparam = magiccolors[index];
|
||||
|
||||
println(hlog, co, " twos = ", twos, " index = ", index, " set = ", format("%06X", c->landparam));
|
||||
|
||||
}
|
||||
|
||||
void magic(int sides) {
|
||||
stop_game();
|
||||
crystal::set_crystal(sides);
|
||||
set_variation(eVariation::pure);
|
||||
firstland = specialland = laCanvas;
|
||||
patterns::whichCanvas = 'g';
|
||||
patterns::canvasback = 0;
|
||||
check_cgi();
|
||||
start_game();
|
||||
|
||||
build(crystal::c0, 0);
|
||||
on = true;
|
||||
}
|
||||
|
||||
void curveline(hyperpoint a, hyperpoint b, int lev) {
|
||||
if(lev>0) {
|
||||
hyperpoint c = mid(a, b);
|
||||
curveline(a, c, lev-1);
|
||||
curveline(c, b, lev-1);
|
||||
}
|
||||
curvepoint(b);
|
||||
}
|
||||
|
||||
bool magic_markers(cell *c, const transmatrix& V) {
|
||||
if(!on) return false;
|
||||
timerghost = false;
|
||||
if(c->landparam == back) {
|
||||
for(int i=0; i<S7; i++) {
|
||||
cell *c2 = c->move(i);
|
||||
if(c2->landparam != back) {
|
||||
hyperpoint h1 = V * get_corner_position(c, i, 3/.9);
|
||||
hyperpoint h2 = V * get_corner_position(c, i+1, 3/.9);
|
||||
curvepoint(h1);
|
||||
curveline(h1, h2, 3);
|
||||
hyperpoint h3 = V * get_corner_position(c, i, 3/.7);
|
||||
hyperpoint h4 = V * get_corner_position(c, i+1, 3/.7);
|
||||
curvepoint(h4);
|
||||
curveline(h4, h3, 3);
|
||||
queuecurve(0xFF, (c2->landparam << 8) | 0xFF, PPR::LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else c->wall = waInvisibleFloor;
|
||||
return false;
|
||||
}
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-magic")) {
|
||||
PHASEFROM(2);
|
||||
shift(); magic(argi());
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void twos_to_fours(vector<int>& zeros, crystal::coord co, int d) {
|
||||
if(d == dim()) {
|
||||
int facetable[5][5];
|
||||
for(int x=0; x<5; x++)
|
||||
for(int y=0; y<5; y++) {
|
||||
co[zeros[0]] = 2*x-4;
|
||||
co[zeros[1]] = 2*y-4;
|
||||
facetable[y][x] = crystal::get_heptagon_at(co)->c7->landparam;
|
||||
}
|
||||
for(int x=0; x<5; x++)
|
||||
for(int y=0; y<5; y++) {
|
||||
co[zeros[0]] = 2*y-4;
|
||||
co[zeros[1]] = 4-2*x;
|
||||
crystal::get_heptagon_at(co)->c7->landparam = facetable[y][x];
|
||||
}
|
||||
}
|
||||
else {
|
||||
twos_to_fours(zeros, co, d+1);
|
||||
if(co[d] == 2 || co[d] == -2) {
|
||||
co[d] *= 2;
|
||||
twos_to_fours(zeros, co, d+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool magic_rotate(cell *c) {
|
||||
if(!on) return false;
|
||||
if(c->landparam != back) return false;
|
||||
vector<int> zeros;
|
||||
auto co = crystal::get_coord(c->master);
|
||||
println(hlog, "co = ", co);
|
||||
for(int i=0; i<dim(); i++) {
|
||||
if(co[i] == 0) zeros.push_back(i);
|
||||
else if(co[i] == 2 || co[i] == -2) ;
|
||||
else return false;
|
||||
}
|
||||
println(hlog, "zeros = ", zeros);
|
||||
if(isize(zeros) != 2) return false;
|
||||
twos_to_fours(zeros, co, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool magic_rugkey(int sym, int uni) {
|
||||
if((cmode & sm::NORMAL) && uni == 'p' && on) {
|
||||
rug::texturesize = 4096;
|
||||
if(rug::rugged) rug::close();
|
||||
else rug::init();
|
||||
return true;
|
||||
}
|
||||
if((cmode & sm::NORMAL) && uni == 'r' && on) {
|
||||
performMarkCommand(mouseover);
|
||||
return true;
|
||||
}
|
||||
if((cmode & sm::NORMAL) && uni == 'R' && on) {
|
||||
build(crystal::c0, 0);
|
||||
}
|
||||
if((cmode & sm::NORMAL) && uni == 'k' && on) {
|
||||
crystal::view_coordinates = !crystal::view_coordinates;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto magichook = addHook(hooks_args, 100, readArgs) + addHook(hooks_drawcell, 100, magic_markers)
|
||||
+ addHook(hooks_mark, 150, magic_rotate)
|
||||
+ addHook(hooks_handleKey, 150, magic_rugkey);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,768 @@
|
||||
// newconformist explorable explanation
|
||||
// example commandline: -noplayer -rugtsize 4096 -smart 1 -canvas B -ncee
|
||||
// set CAP_NCONF (and change the path) if you have access to newconformist
|
||||
|
||||
#ifndef CAP_NCONF
|
||||
#define CAP_NCONF 0
|
||||
#endif
|
||||
|
||||
#if CAP_NCONF
|
||||
#ifndef CAP_DRAW
|
||||
#define CAP_DRAW 0
|
||||
#endif
|
||||
#define main nconf_main
|
||||
#undef unordered_map
|
||||
#include "nconf.cpp"
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
namespace hr {
|
||||
|
||||
namespace nconf2 {
|
||||
|
||||
enum class ptype : char { outside, inside, inside_left_up, inside_left_down, top, bottom, left_inf, right_inf, marked };
|
||||
|
||||
void add_border(vector<string>& v, int cy) {
|
||||
int Y = isize(v), X = isize(v[0]);
|
||||
char nx = '6';
|
||||
for(int y=0; y<Y; y++)
|
||||
for(int x=0; x<X; x++)
|
||||
if(v[y][x] != '1')
|
||||
if((y && v[y-1][x] == '1') || (y<Y-1 && v[y+1][x] == '1') || (x && v[y][x-1] == '1') || (x<X-1 && v[y][x+1] == '1'))
|
||||
v[y][x] = y < cy ? '4' : y > cy ? '5' : (nx++);
|
||||
}
|
||||
|
||||
vector<string> gensquare(int X, int Y) {
|
||||
vector<string> res(Y+4, string (X+4, '0'));
|
||||
for(int y=0; y<Y; y++)
|
||||
for(int x=0; x<X; x++)
|
||||
res[y+2][x+2] = '1';
|
||||
add_border(res, 2+Y/2);
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<string> gent(int X, int Y) {
|
||||
vector<string> res(Y+X+4, string (Y+X+X+4, '0'));
|
||||
for(int y=0; y<Y; y++)
|
||||
for(int x=0; x<X+X+Y; x++)
|
||||
res[y+2][x+2] = '1';
|
||||
for(int y=0; y<Y; y++)
|
||||
for(int x=0; x<X; x++)
|
||||
res[x+2+Y][y+2+X] = '1';
|
||||
add_border(res, 2+Y/2);
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<string> fmap = gensquare(13, 13);
|
||||
|
||||
vector<string> snake = {
|
||||
"00000000000000000000000000000000000",
|
||||
"00444444444444444444444444444444400",
|
||||
"04111111111111111111111111111111140",
|
||||
"04111111111111111111111111111111140",
|
||||
"06111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"00555555555555555555555555511111140",
|
||||
"00000000000000000000000000051111140",
|
||||
"00555555555555555555555555511111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111444444444444444444444444400",
|
||||
"05111114000000000000000000000000000",
|
||||
"05111111444444444444444444444444400",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111140",
|
||||
"05111111111111111111111111111111170",
|
||||
"05111111111111111111111111111111150",
|
||||
"05111111111111111111111111111111150",
|
||||
"00555555555555555555555555555555500",
|
||||
"00000000000000000000000000000000000"
|
||||
};
|
||||
|
||||
struct coord {
|
||||
int x, y;
|
||||
coord operator + (int d) {
|
||||
coord res = *this;
|
||||
d &= 3;
|
||||
if(d == 0) res.x++;
|
||||
if(d == 1) res.y++;
|
||||
if(d == 2) res.x--;
|
||||
if(d == 3) res.y--;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
char out = '-';
|
||||
|
||||
char& fmap_at(coord c) { return c.x >= 0 && c.x < isize(fmap[0]) && c.y >= 0 && c.y < isize(fmap) ? fmap[c.y][c.x] : out; };
|
||||
|
||||
ld vx[256][256], vy[256][256];
|
||||
|
||||
void reset_vxy() { for(int y=0; y<256; y++) for(int x=0; x<256; x++) vy[y][x] = vx[y][x] = 0; }
|
||||
|
||||
ld cscale;
|
||||
|
||||
bool pretty = true;
|
||||
|
||||
void iterate() {
|
||||
int Y = isize(fmap);
|
||||
int X = isize(fmap[0]);
|
||||
for(int y=0; y<Y; y++)
|
||||
for(int x=0; x<X; x++) {
|
||||
if(fmap[y][x] == '6')
|
||||
vy[y][x] = 0, vx[y][x] = -1;
|
||||
else if(fmap[y][x] == '7')
|
||||
vy[y][x] = 0, vx[y][x] = +1;
|
||||
else if(fmap[y][x] == '4')
|
||||
vy[y][x] = -1;
|
||||
else if(fmap[y][x] == '5')
|
||||
vy[y][x] = +1;
|
||||
else if(fmap[y][x] == '1')
|
||||
vy[y][x] = (vy[y-1][x] + vy[y+1][x] + vy[y][x-1] + vy[y][x+1]) / 4;
|
||||
if(among(fmap[y][x], '1', '4', '5')) {
|
||||
int qty = 0;
|
||||
ld total = 0;
|
||||
auto in = [&] (char c) { return pretty ? c > '0' : among(c, '1', '6', '7'); };
|
||||
if(y > 0 && in(fmap[y-1][x])) qty++, total += vx[y-1][x];
|
||||
if(y < Y-1 && in(fmap[y+1][x])) qty++, total += vx[y+1][x];
|
||||
if(x > 0 && in(fmap[y][x-1])) qty++, total += vx[y][x-1];
|
||||
if(x < X-1 && in(fmap[y][x+1])) qty++, total += vx[y][x+1];
|
||||
vx[y][x] = total / qty;
|
||||
}
|
||||
}
|
||||
|
||||
vector<ld> xes;
|
||||
|
||||
for(int y=0; y<Y-1; y++) for(int x=0; x<X-1; x++)
|
||||
if(fmap[y][x] == '1' && fmap[y+1][x] == '1' && fmap[y][x+1] == '1') {
|
||||
|
||||
hyperpoint here = point2(vx[y][x], vy[y][x]);
|
||||
hyperpoint v0 = point2(vx[y][x+1], vy[y][x+1]) - here;
|
||||
hyperpoint v1 = point2(vx[y+1][x], vy[y+1][x]) - here;
|
||||
|
||||
ld det = (v0 ^ v1)[2];
|
||||
if(det == 0) continue;
|
||||
|
||||
hyperpoint ba2 = point2(v1[1], -v0[1]) / det;
|
||||
hyperpoint ca2 = point2(-v1[0], v0[0]) / det;
|
||||
|
||||
ld d = (ba2|ba2);
|
||||
if(d == 0) continue;
|
||||
|
||||
ld good = (ca2^ba2)[2] / d;
|
||||
|
||||
xes.push_back(good);
|
||||
}
|
||||
|
||||
sort(xes.begin(), xes.end());
|
||||
if(isize(xes))
|
||||
cscale = -xes[isize(xes) / 2];
|
||||
|
||||
// println(hlog, "cscale = ", cscale);
|
||||
}
|
||||
|
||||
#if CAP_NCONF
|
||||
void nconf_solve() {
|
||||
nconf::SY = isize(fmap);
|
||||
nconf::SX = isize(fmap[0]);
|
||||
nconf::resize_pt();
|
||||
for(int y=0; y<nconf::SY; y++)
|
||||
for(int x=0; x<nconf::SX; x++) {
|
||||
auto& p = nconf::pts[y][x];
|
||||
p.type = (nconf::ptype)(fmap[y][x] - '0');
|
||||
p.side = 0;
|
||||
}
|
||||
nconf::pretty_borders = pretty;
|
||||
nconf::draw_progress = false;
|
||||
nconf::text_progress = false;
|
||||
nconf::computemap(nconf::pts);
|
||||
for(int y=0; y<nconf::SY; y++)
|
||||
for(int x=0; x<nconf::SX; x++) {
|
||||
if(fmap[y][x] == '1')
|
||||
vx[y][x] = nconf::pts[y][x].x[0] * 2 - 1,
|
||||
vy[y][x] = nconf::pts[y][x].x[1] * 2 - 1;
|
||||
if(pretty && (fmap[y][x] == '4' || fmap[y][x] == '5'))
|
||||
vx[y][x] = nconf::pts[y][x].x[0] * 2 - 1;
|
||||
}
|
||||
|
||||
printf("nconf solved\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
basic_textureinfo nctinf, nctinf2;
|
||||
vector<glvertex> vs;
|
||||
|
||||
bool viewmap = true;
|
||||
|
||||
void fix_border() {
|
||||
int Y = isize(fmap);
|
||||
int X = isize(fmap[0]);
|
||||
for(string& s: fmap) for(char& c: s) if(c == '5') c = '4';
|
||||
|
||||
coord cc;
|
||||
for(int y=0; y<Y; y++) for(int x=0; x<X; x++) if(fmap[y][x] == '6') cc = coord{x,y};
|
||||
|
||||
int dir = 0;
|
||||
while(fmap_at(cc+dir) != '1') dir++;
|
||||
|
||||
cc = cc + dir;
|
||||
dir += 2;
|
||||
|
||||
while(true) {
|
||||
if(fmap_at(cc+dir) == '1') cc = cc + dir, dir++;
|
||||
else {
|
||||
if(fmap_at(cc+dir) == '4') fmap_at(cc+dir) = '5';
|
||||
if(fmap_at(cc+dir) == '7') break;
|
||||
dir--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void doublemap() {
|
||||
for(string& s: fmap) {
|
||||
string res = "";
|
||||
for(char c: s) res += c, res += c;
|
||||
s = res;
|
||||
}
|
||||
fmap.resize(isize(fmap) * 2);
|
||||
for(int y=isize(fmap)-1; y>=0; y--) fmap[y] = fmap[y/2];
|
||||
|
||||
int Y = isize(fmap);
|
||||
int X = isize(fmap[0]);
|
||||
|
||||
for(int y=Y-1; y>=0; y--) for(int x=X-1; x>=0; x--)
|
||||
vx[y][x] = vx[y/2][x/2], vy[y][x] = vy[y/2][x/2];
|
||||
|
||||
for(int y=0; y<Y; y++) for(int x=0; x<X; x++) {
|
||||
coord cc{x,y};
|
||||
auto& us = fmap[y][x];
|
||||
if(us >= '4') {
|
||||
bool live = false;
|
||||
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '1') live = true;
|
||||
if(!live) us = '0';
|
||||
}
|
||||
}
|
||||
|
||||
bool found6 = false, found7 = false;
|
||||
for(int y=0; y<Y; y++) for(int x=0; x<X; x++) {
|
||||
if(fmap[y][x] == '6') {
|
||||
if(found6) fmap[y][x] = '4'; else found6 = true;
|
||||
}
|
||||
if(fmap[y][x] == '7') {
|
||||
if(found7) fmap[y][x] = '5'; else found7 = true;
|
||||
}
|
||||
fix_border();
|
||||
}
|
||||
}
|
||||
|
||||
int pointmode;
|
||||
|
||||
bool show_mapping = true;
|
||||
bool show_mgrid = true;
|
||||
|
||||
ld mapping_split = .75;
|
||||
|
||||
char paintmode;
|
||||
|
||||
void changepoint(int x, int y, bool can_add) {
|
||||
int Y = isize(fmap);
|
||||
int X = isize(fmap[0]);
|
||||
if(x < 0 || y < 0 || x >= X || y >= Y) return;
|
||||
if(pointmode) {
|
||||
if(fmap[y][x] < '4') return;
|
||||
for(string& s: fmap) for(char& c: s) if(c == pointmode) c = '4';
|
||||
fmap[y][x] = pointmode;
|
||||
fix_border();
|
||||
return;
|
||||
}
|
||||
if(y == 0) {
|
||||
paintmode = 0;
|
||||
fmap.emplace_back();
|
||||
for(int i=Y-1; i>=0; i--) fmap[i+1] = fmap[i];
|
||||
for(char& c: fmap[0]) c = '0';
|
||||
}
|
||||
if(y == Y-1) {
|
||||
paintmode = 0;
|
||||
fmap.push_back(fmap[0]);
|
||||
for(char& c: fmap.back()) c = '0';
|
||||
}
|
||||
if(x == 0) {
|
||||
paintmode = 0;
|
||||
for(string& s: fmap) s = '0' + s;
|
||||
}
|
||||
if(x == X-1) {
|
||||
paintmode = 0;
|
||||
for(string& s: fmap) s = s + '0';
|
||||
}
|
||||
coord cc{x,y};
|
||||
auto& us = fmap[y][x];
|
||||
if(fmap[y][x] >= '4') {
|
||||
if(fmap[y][x] > '5') {
|
||||
int q = 0;
|
||||
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '0') q++;
|
||||
if(q != 1) return;
|
||||
}
|
||||
else {
|
||||
for(int k=0; k<4; k++) if(fmap_at(cc+k) == (us^ '1')) return;
|
||||
int q = 0;
|
||||
for(int k=0; k<4; k++) if(fmap_at(cc+k) >= '4') q++;
|
||||
if(q > 2) return;
|
||||
}
|
||||
for(int k=0; k<4; k++)
|
||||
if(fmap_at(cc+k) != '1')
|
||||
if(fmap_at(cc+k+(k+1)) == '1')
|
||||
if(fmap_at(cc+(k+1)) != '1')
|
||||
return;
|
||||
|
||||
for(int k=0; k<4; k++)
|
||||
if(fmap_at(cc+k) != '1')
|
||||
if(fmap_at(cc+k+k) == '1')
|
||||
if(fmap_at(cc+k+(k+1)) != '1')
|
||||
if(fmap_at(cc+k+(k-1)) != '1')
|
||||
return;
|
||||
|
||||
if(fmap[y-1][x] == '0') fmap[y-1][x] = us;
|
||||
if(fmap[y][x-1] == '0') fmap[y][x-1] = us;
|
||||
if(fmap[y+1][x] == '0') fmap[y+1][x] = us;
|
||||
if(fmap[y][x+1] == '0') fmap[y][x+1] = us;
|
||||
us = '1';
|
||||
}
|
||||
else if(us == '1') {
|
||||
int q = 0;
|
||||
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '1') q++;
|
||||
if(q == 0) return;
|
||||
if(q == 4) return;
|
||||
if(q == 3) {
|
||||
for(int k=0; k<4; k++) if(fmap_at(cc+k) != '1') {
|
||||
int nei = 0;
|
||||
if(fmap_at(cc+k+(k+1)) == '1') nei++;
|
||||
if(fmap_at(cc+k+(k+3)) == '1') nei++;
|
||||
if(nei == 2) return;
|
||||
us = fmap_at(cc+k);
|
||||
if(nei == 0) fmap_at(cc+k) = '0';
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(q == 2 && fmap_at(cc+0) == '1' && fmap_at(cc+2) == '1') return;
|
||||
if(q == 2 && fmap_at(cc+1) == '1' && fmap_at(cc+3) == '1') return;
|
||||
for(int k=0; k<4; k++) if(fmap_at(cc+k) == '1' && fmap_at(cc+(k+1)) == '1' && fmap_at(cc+k+(k+1)) != '1') return;
|
||||
bool have4 = false, kill6 = false, kill7 = false, live[4];
|
||||
for(int k=0; k<4; k++) {
|
||||
char ch = fmap_at(cc+k);
|
||||
|
||||
live[k] = false;
|
||||
for(int k=0; k<4; k++) {
|
||||
for(int l=0; l<4; l++) if(k!=(l^2) && fmap_at(cc+k+l) == '1') live[k] = true;
|
||||
}
|
||||
|
||||
switch(ch) {
|
||||
case '4': have4 = true; break;
|
||||
case '5': break;
|
||||
case '6': if(!live[k]) kill6 = true; break;
|
||||
case '7': if(!live[k]) kill7 = true; break;
|
||||
};
|
||||
}
|
||||
|
||||
if(kill6 && kill7) return;
|
||||
|
||||
if(kill6) us = '6';
|
||||
else if(kill7) us = '7';
|
||||
else if(have4) us = '4';
|
||||
else us = '5';
|
||||
|
||||
for(int k=0; k<4; k++) if(!live[k]) fmap_at(cc+k) = '0';
|
||||
}
|
||||
};
|
||||
|
||||
bool showmenu = true;
|
||||
|
||||
void conf_shapes() {
|
||||
cmode = 0;
|
||||
dialog::init(XLAT("shapes"));
|
||||
dialog::addItem("square 11x11", 'a');
|
||||
dialog::add_action([] { fmap = gensquare(13, 13); reset_vxy(); popScreen(); });
|
||||
dialog::addItem("rectangle 15x8", 'b');
|
||||
dialog::add_action([] { fmap = gensquare(15, 8); reset_vxy(); popScreen(); });
|
||||
dialog::addItem("T-shape", 'c');
|
||||
dialog::add_action([] { fmap = gent(19, 7); reset_vxy(); popScreen(); });
|
||||
dialog::addItem("snake", 'd');
|
||||
dialog::add_action([] { fmap = snake; reset_vxy(); popScreen(); });
|
||||
dialog::addBreak(100);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
int algo_speed = 10000;
|
||||
|
||||
int algo_ticks = 0;
|
||||
|
||||
bool in_visualization;
|
||||
int nconf_pos;
|
||||
ld steps_to_do;
|
||||
|
||||
#define DELTA [] { static int oldticks = ticks; int res = ticks - oldticks; oldticks = ticks; return res; }
|
||||
|
||||
auto nconf_delta = DELTA;
|
||||
|
||||
#if CAP_NCONF
|
||||
void nconf_prepare(bool fast) {
|
||||
// pretend we are solving
|
||||
nconf_solve();
|
||||
build_equations(nconf::pts, 1, fast);
|
||||
nconf_pos = 0;
|
||||
in_visualization = true;
|
||||
steps_to_do = 0;
|
||||
algo_ticks = 0;
|
||||
nconf_delta();
|
||||
printf("points: %d\n", isize(nconf::allpoints));
|
||||
}
|
||||
|
||||
void nconf_run() {
|
||||
int d = nconf_delta();
|
||||
algo_ticks += d;
|
||||
steps_to_do += d * algo_speed / 1000.;
|
||||
while(steps_to_do > 0) {
|
||||
if(nconf_pos == isize(nconf::allpoints)) { in_visualization = false; break; }
|
||||
auto co = nconf::allpoints[nconf_pos++];
|
||||
auto &p = nconf::pts[co];
|
||||
nconf::eliminate(nconf::pts, co);
|
||||
printf("point #%d has %d equations\n", nconf_pos-1, hr::isize(p.eqs));
|
||||
steps_to_do -= pow(hr::isize(p.eqs), 2);
|
||||
}
|
||||
}
|
||||
|
||||
void pick_algorithm() {
|
||||
cmode = 0;
|
||||
dialog::init(XLAT("solving"));
|
||||
dialog::addItem("iterative/reset", 'r');
|
||||
dialog::add_action([] { reset_vxy(); algo_ticks = 0; popScreen(); });
|
||||
dialog::addItem("solve linear equations", 's');
|
||||
dialog::add_action([] { nconf_solve(); algo_ticks = 0; popScreen(); });
|
||||
dialog::addItem("visualize (slow)", 'a');
|
||||
dialog::add_action([] { nconf_prepare(false); popScreen(); });
|
||||
dialog::addItem("visualize (fast)", 'b');
|
||||
dialog::add_action([] { nconf_prepare(true); popScreen(); });
|
||||
dialog::addSelItem("visualization speed", its(algo_speed), 'v');
|
||||
dialog::add_action([] { dialog::editNumber(algo_speed, 100, 1000000, 0.1, 10000, "", ""), dialog::scaleLog(), dialog::dialogflags = 0, dialog::numberdark = dialog::DONT_SHOW; });
|
||||
dialog::addBreak(50);
|
||||
dialog::addBoolItem_action("pretty corners", pretty, 'p');
|
||||
dialog::addBreak(50);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace ncee_scr {
|
||||
int X, Y, xc, yc, x0, y0, siz;
|
||||
}
|
||||
|
||||
void draw_ncee() {
|
||||
using namespace ncee_scr;
|
||||
auto cd = current_display;
|
||||
|
||||
Y = isize(fmap);
|
||||
X = isize(fmap[0]);
|
||||
siz = min((cd->ysize / (show_mapping ? 2 : 1) - 5) / Y, showmenu ? (cd->xcenter -5 )*2/X : (cd->xsize - 5) / X);
|
||||
|
||||
xc = 0;
|
||||
yc = vid.yres * (show_mapping ? mapping_split : 1) / 2 - cd->ycenter;
|
||||
|
||||
x0 = - int(siz * X / 2);
|
||||
y0 = - int(siz * Y / 2);
|
||||
|
||||
const ld period = 2.898149445355172 / M_PI * 2;
|
||||
|
||||
dynamicval<eModel> pm(pmodel, mdUnchanged);
|
||||
dynamicval<eGeometry> pg(geometry, gEuclid);
|
||||
|
||||
initquickqueue();
|
||||
nctinf2.texture_id = rug::glbuf->renderedTexture;
|
||||
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;
|
||||
|
||||
if(show_mapping) {
|
||||
for(int iter=-10; iter<=10; iter++) {
|
||||
ld maxx = period * vid.scale / 4;
|
||||
ld scax = sca2 * maxx / 0.5;
|
||||
ld xpos = scax * 2 * iter;
|
||||
curvepoint(hpxy(xpos-scax, map_ypos-sca2));
|
||||
nctinf2.tvertices.push_back(glhr::makevertex(0.5-maxx, 0, 0));
|
||||
curvepoint(hpxy(xpos-scax, map_ypos+sca2));
|
||||
nctinf2.tvertices.push_back(glhr::makevertex(0.5-maxx, 1, 0));
|
||||
curvepoint(hpxy(xpos+scax, map_ypos-sca2));
|
||||
nctinf2.tvertices.push_back(glhr::makevertex(0.5+maxx, 0, 0));
|
||||
curvepoint(hpxy(xpos-scax, map_ypos+sca2));
|
||||
nctinf2.tvertices.push_back(glhr::makevertex(0.5-maxx, 1, 0));
|
||||
curvepoint(hpxy(xpos+scax, map_ypos-sca2));
|
||||
nctinf2.tvertices.push_back(glhr::makevertex(0.5+maxx, 0, 0));
|
||||
curvepoint(hpxy(xpos+scax, map_ypos+sca2));
|
||||
nctinf2.tvertices.push_back(glhr::makevertex(0.5+maxx, 1, 0));
|
||||
}
|
||||
auto& q = queuecurve(0, show_mgrid ? 0x404040FF : 0xFFFFFFFF, PPR::LINE);
|
||||
q.tinf = &nctinf2;
|
||||
q.flags |= POLY_TRIANGLES;
|
||||
q.offset_texture = 0;
|
||||
}
|
||||
|
||||
auto h = [&] (int x, int y) { return hpxy(x0 + x * siz + xc, y0 + y * siz + yc); };
|
||||
auto hc = [&] (int x, int y) { return hpxy(x0 + x * siz + siz/2 + xc, y0 + y * siz + siz/2 + yc); };
|
||||
|
||||
color_t typecols[8] = {
|
||||
0x101010FF, 0xD0D0D0FF, 0, 0, 0xF04040FF, 0x4040F0FF, 0xF0F040FF, 0x40F0F0FF
|
||||
};
|
||||
|
||||
for(int x=0; x<X; x++) for(int y=0; y<Y; y++) {
|
||||
curvepoint(h(x,y));
|
||||
curvepoint(h(x+1,y));
|
||||
curvepoint(h(x+1,y+1));
|
||||
curvepoint(h(x,y+1));
|
||||
#if CAP_NCONF
|
||||
bool ineq =
|
||||
in_visualization && fmap[y][x] == '1';
|
||||
#endif
|
||||
queuecurve(0,
|
||||
#if CAP_NCONF
|
||||
(ineq && nconf::pts[y][x].state == 1) ? 0xFF8000FF :
|
||||
(ineq && nconf::pts[y][x].state == 2) ? 0x00FF00FF :
|
||||
#endif
|
||||
(fmap[y][x] == '1' && show_mgrid && show_mapping) ? 0x404040FF : typecols[fmap[y][x] - '0'], PPR::LINE);
|
||||
}
|
||||
|
||||
nctinf.texture_id = rug::glbuf->renderedTexture;
|
||||
nctinf.tvertices.clear();
|
||||
|
||||
static int z = 0;
|
||||
|
||||
auto tri = [&] (const array<coord,3>& c) {
|
||||
|
||||
int id = -1;
|
||||
for(int i=0; i<3; i++) if(fmap_at(c[i])) id = i;
|
||||
if(id == -1) return;
|
||||
ld delta = (int((vx[c[id].y][c[id].x]) / cscale / period + 1000.5) - 1000) * period;
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
if(viewmap && !in_visualization) for(int x=0; x<X-1; x++) for(int y=0; y<Y-1; y++) {
|
||||
if(fmap[y][x+1] > '0' && fmap[y+1][x] > '0') {
|
||||
if(fmap[y][x] > '0') tri(make_array(coord{x,y}, coord{x+1,y}, coord{x,y+1}));
|
||||
if(fmap[y+1][x+1] > '0') tri(make_array(coord{x+1,y+1}, coord{x+1,y}, coord{x,y+1}));
|
||||
}
|
||||
else if(fmap[y][x] > '0' && fmap[y+1][x+1] > '0') {
|
||||
if(fmap[y][x+1] > '0') tri(make_array(coord{x,y}, coord{x+1,y}, coord{x+1,y+1}));
|
||||
if(fmap[y+1][x] > '0') tri(make_array(coord{x,y}, coord{x,y+1}, coord{x+1,y+1}));
|
||||
}
|
||||
}
|
||||
|
||||
auto& q = queuecurve(0, (show_mgrid && show_mapping) ? 0x404040FF : 0xFFFFFFFF, PPR::LINE);
|
||||
q.tinf = &nctinf;
|
||||
q.flags |= POLY_TRIANGLES;
|
||||
q.offset_texture = 0;
|
||||
|
||||
hyperpoint vmap[256][256];
|
||||
|
||||
pair<int, int> mpt = {(mousex - xc - cd->xcenter - x0) / siz, (mousey - yc - cd->ycenter - y0) / siz};
|
||||
|
||||
const color_t gridcol = 0xFFFFFFFF;
|
||||
if(show_mapping && show_mgrid && !in_visualization) {
|
||||
for(int x=0; x<X-1; x++) for(int y=0; y<Y-1; y++)
|
||||
if(fmap[y][x] > '0')
|
||||
vmap[y][x] = hpxy(vx[y][x]/cscale * sca2 / 2, vy[y][x] * sca2 / 2+ map_ypos);
|
||||
for(int x=0; x<X-1; x++) for(int y=0; y<Y-1; y++) {
|
||||
if(y < Y-2 && fmap[y][x] > '0' && fmap[y+1][x] > '0') {
|
||||
color_t col = (make_pair(x,y) == mpt || make_pair(x,y+1) == mpt) ? 0xFFFF00FF : gridcol;
|
||||
dynamicval<ld> lw(vid.linewidth, vid.linewidth * (col == 0xFFFF00FF ? 4 : 1));
|
||||
queueline(hc(x, y), hc(x, y+1), col, 0, PPR::CIRCLE);
|
||||
queueline(vmap[y][x], vmap[y+1][x], col, 0, PPR::CIRCLE);
|
||||
}
|
||||
if(x < X-2 && fmap[y][x] > '0' && fmap[y][x+1] > '0') {
|
||||
color_t col = (make_pair(x,y) == mpt || make_pair(x+1,y) == mpt) ? 0xFFFF00FF : gridcol;
|
||||
dynamicval<ld> lw(vid.linewidth, vid.linewidth * (col == 0xFFFF00FF ? 4 : 1));
|
||||
queueline(hc(x, y), hc(x+1, y), col, 0, PPR::CIRCLE);
|
||||
queueline(vmap[y][x], vmap[y][x+1], col, 0, PPR::CIRCLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int x=0; x<=X; x++) queueline(h(x,0), h(x,Y), 0x80808080);
|
||||
for(int y=0; y<=Y; y++) queueline(h(0,y), h(X,y), 0x80808080);
|
||||
quickqueue();
|
||||
|
||||
}
|
||||
|
||||
int ncee_map_prepared;
|
||||
|
||||
void prepare_ncee_map() {
|
||||
ncee_map_prepared = 5;
|
||||
pmodel = mdBand;
|
||||
dynamicval<int> cgl(vid.cells_generated_limit, 9999999);
|
||||
dynamicval<bool> r(rug::display_warning, false);
|
||||
// vid.consider_shader_projection = false;
|
||||
vid.scale = 0.5;
|
||||
rug::init();
|
||||
rug::prepareTexture();
|
||||
rug::rugged = false;
|
||||
}
|
||||
|
||||
void ncee() {
|
||||
cmode = showmenu ? (sm::SIDE | sm::MAYDARK | sm::DIALOG_STRICT_X) : 0;
|
||||
calcparam();
|
||||
|
||||
if(ncee_map_prepared < 5) { cmode = sm::NORMAL; ncee_map_prepared++; if(ncee_map_prepared == 5) prepare_ncee_map(); gamescreen(2); return; }
|
||||
|
||||
#if CAP_NCONF
|
||||
if(in_visualization)
|
||||
nconf_run();
|
||||
else
|
||||
#endif
|
||||
iterate();
|
||||
|
||||
draw_ncee();
|
||||
using namespace ncee_scr;
|
||||
auto cd = current_display;
|
||||
|
||||
getcstat = '-';
|
||||
|
||||
if(paintmode && mousepressed) {
|
||||
int x = (mousex - cd->xcenter - xc - x0) / siz;
|
||||
int y = (mousey - cd->ycenter - yc - y0) / siz;
|
||||
if(fmap[y][x] == paintmode)
|
||||
changepoint(x, y, false);
|
||||
}
|
||||
|
||||
if(showmenu) {
|
||||
dialog::init(XLAT("newconformist"));
|
||||
dialog::addBoolItem("edit shape", pointmode == 0, 'e');
|
||||
dialog::addBoolItem("set left end", pointmode == '6', 'a');
|
||||
dialog::addBoolItem("set right end", pointmode == '7', 'b');
|
||||
dialog::addBreak(50);
|
||||
dialog::addBoolItem("show the end result", viewmap, 'm');
|
||||
dialog::addBoolItem("display the band model", show_mapping, 's');
|
||||
if(show_mapping)
|
||||
dialog::addBoolItem("display the grid on model", show_mgrid, 'g');
|
||||
else
|
||||
dialog::addBreak(100);
|
||||
dialog::addBreak(50);
|
||||
if(show_mapping)
|
||||
dialog::addSelItem("mapping split", fts(mapping_split), 'y');
|
||||
else
|
||||
dialog::addBreak(100);
|
||||
dialog::addSelItem("double precision", its(isize(fmap[0])) + "x" + its(isize(fmap)), 'd');
|
||||
#if CAP_NCONF
|
||||
dialog::addItem("solving method", 'l');
|
||||
#endif
|
||||
dialog::addItem("shapes", 't');
|
||||
dialog::addItem("hide the menu", 'v');
|
||||
dialog::addItem("stop", 'x');
|
||||
dialog::display();
|
||||
}
|
||||
else
|
||||
displayButton(vid.xres - 8, 8 + vid.fsize, XLAT("(v) menu"), 'v', 16);
|
||||
|
||||
if(algo_ticks)
|
||||
displaystr(8, 8 + vid.fsize, 0, vid.fsize * 2, format("%d.%03d", algo_ticks/1000, algo_ticks%1000), 0xFFFFFF, 0);
|
||||
|
||||
keyhandler = [=] (int sym, int uni) {
|
||||
// dialog::handleNavigation(sym, uni);
|
||||
if(uni == 'z')
|
||||
prepare_ncee_map();
|
||||
|
||||
if(uni == 'x') {
|
||||
popScreen();
|
||||
// rug::rugged = true;
|
||||
rug::close();
|
||||
}
|
||||
if(uni == 'e') pointmode = 0;
|
||||
if(uni == 'a') pointmode = '6';
|
||||
if(uni == 'b') pointmode = '7';
|
||||
#if CAP_NCONF
|
||||
if(uni == 'l') pushScreen(pick_algorithm);
|
||||
#endif
|
||||
// if(uni == 'w') edit_whatever('f', 0);
|
||||
if(uni == 'd') doublemap();
|
||||
if(uni == 'm') viewmap = !viewmap;
|
||||
if(uni == 's') show_mapping = !show_mapping;
|
||||
if(uni == 'g') show_mgrid = !show_mgrid;
|
||||
if(uni == 't') pushScreen(conf_shapes);
|
||||
if(uni == 'y') dialog::editNumber(mapping_split, 0, 1, 0.05, 0.75, "", ""), dialog::dialogflags = 0, dialog::numberdark = dialog::DONT_SHOW;
|
||||
if(uni == '-') {
|
||||
int x = (mousex - cd->xcenter - xc - x0) / siz;
|
||||
int y = (mousey - cd->ycenter - yc - y0) / siz;
|
||||
if(x < 0 || y < 0 || x >= X || y >= Y) return;
|
||||
paintmode = fmap[y][x];
|
||||
changepoint(x, y, true);
|
||||
}
|
||||
if(uni == 'v') showmenu = !showmenu;
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void nconf_view(int i) {
|
||||
if(i == 1)
|
||||
show_mapping = false, viewmap = false;
|
||||
else if(i == 2)
|
||||
show_mapping = false, viewmap = true;
|
||||
else if(i == 3)
|
||||
show_mapping = true, viewmap = true, show_mgrid = true;
|
||||
else if(i == 4)
|
||||
showmenu = false;
|
||||
else if(i == 5)
|
||||
showmenu = true;
|
||||
else if(i == 6)
|
||||
reset_vxy(), algo_ticks = 0;
|
||||
#if CAP_NCONF
|
||||
else if(i == 7)
|
||||
nconf_solve(), algo_ticks = 0;
|
||||
else if(i == 8)
|
||||
nconf_prepare(false);
|
||||
else if(i == 9)
|
||||
nconf_prepare(true);
|
||||
#endif
|
||||
else if(i == 10)
|
||||
doublemap();
|
||||
else if(i == 11)
|
||||
fmap = gensquare(13, 13), reset_vxy();
|
||||
else if(i == 12)
|
||||
fmap = gensquare(15, 8), reset_vxy();
|
||||
else if(i == 13)
|
||||
fmap = gensquare(19, 7), reset_vxy();
|
||||
else if(i == 14)
|
||||
fmap = snake, reset_vxy();
|
||||
}
|
||||
}
|
||||
|
||||
int niceArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-ncee")) {
|
||||
PHASE(3);
|
||||
pushScreen(ncee);
|
||||
showstartmenu = false;
|
||||
clearMessages();
|
||||
}
|
||||
else if(argis("-ncv")) {
|
||||
PHASE(3);
|
||||
shift();
|
||||
nconf_view(argi());
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto nhook =
|
||||
addHook(hooks_args, 100, niceArgs)
|
||||
+ 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
namespace rogueviz {
|
||||
|
||||
#if CAP_ARCM
|
||||
namespace pentagonal {
|
||||
transmatrix ts[3];
|
||||
|
||||
hyperpoint facingdir(array<hyperpoint,3>& a) {
|
||||
hyperpoint tmp = (a[1]-a[0]) ^ (a[2]-a[0]);
|
||||
tmp /= sqrt(tmp|tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
vector<pair<ld, transmatrix>> sideangles;
|
||||
|
||||
cell *p0, *t0, *t1, *t2, *cc;
|
||||
|
||||
bool snubon;
|
||||
|
||||
hyperpoint cor;
|
||||
|
||||
void kframe() {
|
||||
if(snubon) {
|
||||
queuestr(gmatrix[p0], 0.6, "P0", 0xFFFFFF, 1);
|
||||
queuestr(gmatrix[cc], 0.6, "C", 0xFFFFFF, 1);
|
||||
queuestr(gmatrix[t0], 0.6, "T0", 0xFFFFFF, 1);
|
||||
queuestr(gmatrix[t1], 0.6, "T1", 0xFFFFFF, 1);
|
||||
queuestr(gmatrix[t2], 0.6, "T2", 0xFFFFFF, 1);
|
||||
}}
|
||||
|
||||
hyperpoint xts0;
|
||||
array<hyperpoint, 3> mts;
|
||||
|
||||
rug::rugpoint *pt(hyperpoint h, hyperpoint c, int id) {
|
||||
auto r = rug::addRugpoint(C0, -1);
|
||||
r->flat = h;
|
||||
r->x1 = (1 + c[0]) / 16 + (id/8) / 8.;
|
||||
r->y1 = (1 + c[1]) / 16 + (id%8) / 8.;
|
||||
r->valid = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
hyperpoint inplane(array<hyperpoint, 3>& a, hyperpoint line) {
|
||||
hyperpoint mu = (a[1]-a[0]) ^ (a[2]-a[0]);
|
||||
// (a[0] | mu) == (line * z | mu)
|
||||
return line * (a[0] | mu) / (line | mu);
|
||||
}
|
||||
|
||||
transmatrix matrix2;
|
||||
|
||||
#if CAP_TEXTURE
|
||||
bool need_texture = true;
|
||||
texture::texture_data tdata; // = texture::config.data;
|
||||
#endif
|
||||
|
||||
int global_v, global_w;
|
||||
|
||||
void make_texture() {
|
||||
#if CAP_TEXTURE
|
||||
rug::renderonce = true;
|
||||
need_texture = false;
|
||||
tdata.whitetexture();
|
||||
int tw = tdata.twidth;
|
||||
printf("tw = %d\n", tw);
|
||||
int fw = tw / 4;
|
||||
auto pix = [&] (int k, int x, int y) -> unsigned& {
|
||||
return tdata.texture_pixels[y * tw + x + (k&3) * fw + (k>>2) * fw * tw];
|
||||
};
|
||||
for(int y=0; y<tw; y++)
|
||||
for(int x=0; x<tw; x++)
|
||||
for(int p=0; p<3; p++) {
|
||||
int ax = x / (tw/8);
|
||||
int ay = y / (tw/8);
|
||||
int bx = x % (tw/8);
|
||||
int by = y % (tw/8);
|
||||
int id = ax * 8 + ay;
|
||||
hyperpoint h = sideangles[id % isize(sideangles)].second * xts0;
|
||||
if(!sphere) {
|
||||
hyperpoint ehs[7] = {hpxyz(0,-1,-1), hpxyz(0,0,-1), hpxyz(-1,0,-1), hpxyz(-1,0,0), hpxyz(-1,-1,0), hpxyz(0,-1,0), hpxyz(0,-1,-1)};
|
||||
ld idx = (id % global_v) * 6. / global_v;
|
||||
h = ehs[int(idx)] * (1-(idx-int(idx))) + ehs[int(idx)+1] * (idx-int(idx));
|
||||
}
|
||||
ld hyp = hypot(bx-tw/16, by-tw/16) / (tw/16);
|
||||
if(hyp > 1) hyp = 1;
|
||||
part(pix(0,x,y), p) = 255 * (1 * hyp + (0.5 + h[p]/2) * (1-hyp));
|
||||
}
|
||||
|
||||
tdata.loadTextureGL();
|
||||
|
||||
rug::alternate_texture = tdata.textureid;
|
||||
#endif
|
||||
}
|
||||
|
||||
void create_model();
|
||||
|
||||
void run_snub(int v, int w) {
|
||||
snubon = false;
|
||||
global_v = v; global_w = w;
|
||||
printf("set geometry\n");
|
||||
stop_game(); autocheat = true;
|
||||
int bonus;
|
||||
if(w == 4 && v == 4) bonus = 12;
|
||||
else if(w == 4 && v == 5) bonus = 7;
|
||||
else if(w == 4 && v == 6) bonus = 4;
|
||||
else if(w == 3 && v == 6) bonus = 12;
|
||||
else if(w == 3 && v == 7) bonus = 8;
|
||||
else if(w == 3 && v == 8) bonus = 7;
|
||||
else if(w == 3 && v == 9) bonus = 6;
|
||||
else bonus = 0;
|
||||
gamerange_bonus = genrange_bonus = sightrange_bonus = bonus;
|
||||
set_geometry(gArchimedean);
|
||||
set_variation(eVariation::pure);
|
||||
arcm::current.parse("("+its(v)+",3," + its(w) + ",3,3) (2,3)(1,0)(4)");
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
specialland = laCanvas;
|
||||
patterns::whichCanvas = 'A';
|
||||
// vid.wallmode = 1;
|
||||
printf("start game\n");
|
||||
printf("distlimit = %d\n", cgi.base_distlimit);
|
||||
start_game();
|
||||
printf("ok\n");
|
||||
printf("allcells = %d\n", isize(currentmap->allcells()));
|
||||
|
||||
sideangles.clear();
|
||||
printf("gamerange = %d\n", gamerange());
|
||||
printf("genrange = %d\n", getDistLimit() + genrange_bonus);
|
||||
setdist(cwt.at, 7 - getDistLimit() - genrange_bonus, NULL);
|
||||
bfs();
|
||||
|
||||
drawthemap();
|
||||
|
||||
if(euclid || sphere) for(cell *c: currentmap->allcells())
|
||||
gmatrix[c] = arcm::archimedean_gmatrix[c->master].second;
|
||||
|
||||
cellwalker cw(currentmap->gamestart(), 0);
|
||||
p0 = cw.at;
|
||||
t0 = (cw - 1 + wstep).at;
|
||||
t1 = (cw + wstep).at;
|
||||
t2 = (cw + wstep + 1 + wstep - 1).at;
|
||||
// p1 = (cw + wstep + 1 + wstep -1 + wstep).at;
|
||||
cc = (cw - 1 + wstep - 1 + wstep).at;
|
||||
|
||||
transmatrix rel = inverse(gmatrix[p0]);
|
||||
|
||||
ts[0] = rel * gmatrix[t0] * ddspin(t0, (cw - 1 + wstep).spin);
|
||||
ts[1] = rel * gmatrix[t1];
|
||||
ts[2] = rel * gmatrix[t2] * ddspin(t2, (cw + wstep + 1 + wstep - 1).spin);
|
||||
|
||||
matrix2 = ts[2] * inverse(ts[0]);
|
||||
|
||||
for(int i=0; i<3; i++) mts[i] = ts[i] * C0;
|
||||
hyperpoint f = facingdir(mts);
|
||||
|
||||
for(cell *c: currentmap->allcells()) {
|
||||
int id = arcm::id_of(c->master);
|
||||
if(among(id, 0, 1)) for(int d=0; d<v; d++) {
|
||||
transmatrix T = rel * ggmatrix(c) * spin(2*M_PI*d/v);
|
||||
array<hyperpoint,3> hts;
|
||||
for(int i=0; i<3; i++)
|
||||
hts[i] = T * ts[i] * C0;
|
||||
// for(int i=0; i<3; i++) printf("%s ", display(hts[i]));
|
||||
hyperpoint f1 = facingdir(hts);
|
||||
|
||||
ld scalar = (f|f1);
|
||||
ld alpha = (M_PI - acos(scalar)) / degree;
|
||||
sideangles.emplace_back(alpha, T);
|
||||
}
|
||||
}
|
||||
|
||||
vector<double> sav;
|
||||
for(auto p: sideangles) sav.push_back(p.first);
|
||||
sort(sav.begin(), sav.end());
|
||||
|
||||
println(hlog, "sideangles ", sav);
|
||||
|
||||
xts0 = tC0(ts[0]);
|
||||
|
||||
println(hlog, "original ", xts0);
|
||||
|
||||
cor = rel * gmatrix[cc] * C0;
|
||||
|
||||
rug::reopen();
|
||||
for(auto p: rug::points) p->valid = true;
|
||||
rug::good_shape = true;
|
||||
|
||||
make_texture();
|
||||
|
||||
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;
|
||||
showstartmenu = false;
|
||||
snubon = true;
|
||||
rug::invert_depth = hyperbolic;
|
||||
}
|
||||
|
||||
ld x, y;
|
||||
|
||||
void create_model() {
|
||||
|
||||
if(!inHighQual) {
|
||||
x = (mousex - current_display->xcenter + .0) / vid.xres;
|
||||
y = (mousey - current_display->ycenter + .0) / vid.yres;
|
||||
}
|
||||
|
||||
int v = global_v;
|
||||
rug::clear_model();
|
||||
|
||||
ld alpha = atan2(y, x);
|
||||
ld h = hypot(x, y);
|
||||
|
||||
hyperpoint chk = ts[0] * xspinpush0(alpha, h);
|
||||
|
||||
mts[0] = chk;
|
||||
mts[1] = spin(-2*M_PI/v) * chk;
|
||||
mts[2] = matrix2 * chk;
|
||||
|
||||
hyperpoint c[5];
|
||||
for(int i=0; i<5; i++)
|
||||
c[i] = hpxy(sin(2 * i * M_PI/5), cos(2 * i * M_PI/5));
|
||||
|
||||
hyperpoint tria[5];
|
||||
tria[0] = mts[0];
|
||||
tria[1] = inplane(mts, C0);
|
||||
tria[2] = mts[1];
|
||||
tria[3] = mts[2];
|
||||
tria[4] = inplane(mts, cor);
|
||||
|
||||
hyperpoint ctr = Hypc;
|
||||
for(int i=0; i<5; i++) ctr += tria[i];
|
||||
ctr = inplane(mts, ctr);
|
||||
|
||||
transmatrix tester = spin(1.1) * xpush(1);
|
||||
|
||||
int idh = 0;
|
||||
|
||||
for(hyperpoint h: {ctr, tria[0], tria[1], tria[2], tria[3], tria[4], ctr}) {
|
||||
int good1 = 0, good2 = 0;
|
||||
// printf("%d: ", idh);
|
||||
for(int i=0; i<5; i++) {
|
||||
array<hyperpoint, 3> testplane;
|
||||
testplane[0] = tester * h;
|
||||
testplane[1] = tester * tria[i];
|
||||
testplane[2] = tester * tria[(i+1)%5];
|
||||
hyperpoint f = facingdir(testplane);
|
||||
if(f[0] > -1e-6 || std::isnan(f[0])) good1++;
|
||||
if(f[0] < +1e-6 || std::isnan(f[0])) good2++;
|
||||
}
|
||||
// printf("\n");
|
||||
if(good1 == 5 || good2 == 5) {ctr = h; break; }
|
||||
idh++;
|
||||
}
|
||||
|
||||
// printf("idh = %d\n", idh);
|
||||
|
||||
printf("createmodel with ticks = %d\n", ticks);
|
||||
|
||||
transmatrix t = hyperbolic ? hr::cspin(0, 2, M_PI) * xpush(sin(ticks * M_PI * 2 / anims::period)) : hr::cspin(0, 2, ticks * M_PI * 2 / anims::period);
|
||||
|
||||
hyperpoint hs = hyperbolic ? hpxyz(0,0,-1) : hpxyz(0,0,0);
|
||||
|
||||
if(euclid) t = Id;
|
||||
|
||||
int id = 0;
|
||||
for(auto& p: sideangles) {
|
||||
auto& T = p.second;
|
||||
array<rug::rugpoint*,5> hts;
|
||||
auto cpt = pt(hs + t * T * ctr, C0, id);
|
||||
|
||||
for(int s=0; s<5; s++)
|
||||
hts[s] = pt(hs + t * T * tria[s], c[s], id);
|
||||
|
||||
for(int s=0; s<5; s++)
|
||||
rug::addTriangle(cpt, hts[s], hts[(s+1)%5]);
|
||||
|
||||
id++;
|
||||
if(!sphere) id %= global_v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-snub")) {
|
||||
PHASE(3);
|
||||
shift();
|
||||
run_snub(argi(), 3);
|
||||
}
|
||||
else if(argis("-snub4")) {
|
||||
PHASE(3);
|
||||
shift();
|
||||
run_snub(argi(), 4);
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool frame() {
|
||||
if(snubon && rug::rugged) {
|
||||
create_model();
|
||||
nomenukey = true;
|
||||
displaychr(current_display->xcenter, current_display->ycenter, 0, 10, 'X', 0xFFFFFF);
|
||||
clearMessages();
|
||||
nohelp = true;
|
||||
playerfound = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handleKey(int sym, int uni) {
|
||||
if(snubon) {
|
||||
if(among(uni, '3', '4', '5', '6', '7', '8', '9') && (cmode & sm::NORMAL)) {
|
||||
run_snub(uni - '0', 3);
|
||||
return true;
|
||||
}
|
||||
if(among(uni, '#', '$', '%', '&', '^') && (cmode & sm::NORMAL)) {
|
||||
if(uni == '^') uni = '&';
|
||||
run_snub(uni - 32, 4);
|
||||
return true;
|
||||
}
|
||||
if(uni == 'a' && (cmode & sm::NORMAL)) {
|
||||
rug::close();
|
||||
mapeditor::drawplayer = false;
|
||||
return true;
|
||||
}
|
||||
if(uni == 's' && rug::rugged && (cmode & sm::NORMAL)) {
|
||||
vid.fov += 30;
|
||||
if(vid.fov >= 180) vid.fov = 60;
|
||||
}
|
||||
if(uni == 'i' && rug::rugged && (cmode & sm::NORMAL)) {
|
||||
rug::invert_depth = !rug::invert_depth;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
auto xhook = addHook(hooks_args, 100, readArgs)
|
||||
+ addHook(hooks_handleKey, 0, handleKey)
|
||||
+ addHook(hooks_prestats, 0, frame)
|
||||
+ addHook(clearmemory, 40, [] () { snubon = false; } );
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
// See: http://www.roguetemple.com/z/hyper/rogueviz.php
|
||||
|
||||
namespace rogueviz {
|
||||
using namespace hr;
|
||||
|
||||
enum eVizkind { kNONE, kAnyGraph, kTree, kSpiral, kSAG, kCollatz, kFullNet, kKohonen, kFlocking };
|
||||
extern eVizkind kind;
|
||||
|
||||
extern bool on;
|
||||
void drawExtra();
|
||||
void close();
|
||||
|
||||
void init();
|
||||
|
||||
struct edgetype {
|
||||
double visible_from;
|
||||
double visible_from_hi;
|
||||
double visible_from_help;
|
||||
unsigned color, color_hi;
|
||||
string name;
|
||||
};
|
||||
|
||||
static const unsigned DEFAULT_COLOR = 0x471293B5;
|
||||
|
||||
extern edgetype default_edgetype;
|
||||
|
||||
extern vector<shared_ptr<edgetype>> edgetypes;
|
||||
|
||||
struct edgeinfo {
|
||||
int i, j;
|
||||
double weight, weight2;
|
||||
vector<glvertex> prec;
|
||||
basic_textureinfo tinf;
|
||||
cell *orig;
|
||||
int lastdraw;
|
||||
edgetype *type;
|
||||
edgeinfo(edgetype *t) { orig = NULL; lastdraw = -1; type = t; }
|
||||
};
|
||||
|
||||
struct rvimage {
|
||||
basic_textureinfo tinf;
|
||||
texture::texture_data tdata;
|
||||
vector<hyperpoint> vertices;
|
||||
};
|
||||
|
||||
struct colorpair {
|
||||
color_t color1, color2;
|
||||
char shade;
|
||||
shared_ptr<rvimage> img;
|
||||
colorpair(color_t col = 0xC0C0C0FF) { shade = 0; color1 = color2 = col; }
|
||||
};
|
||||
|
||||
struct vertexdata {
|
||||
vector<pair<int, edgeinfo*> > edges;
|
||||
string name;
|
||||
colorpair cp;
|
||||
edgeinfo *virt;
|
||||
bool special;
|
||||
int data;
|
||||
string *info;
|
||||
shmup::monster *m;
|
||||
vertexdata() { virt = NULL; m = NULL; info = NULL; special = false; }
|
||||
};
|
||||
|
||||
extern vector<vertexdata> vdata;
|
||||
|
||||
void storeall(int from = 0);
|
||||
|
||||
namespace anygraph {
|
||||
extern double R, alpha, T;
|
||||
extern vector<pair<double, double> > coords;
|
||||
|
||||
void fixedges();
|
||||
void read(string fn, bool subdiv = true, bool doRebase = true, bool doStore = true);
|
||||
extern int N;
|
||||
}
|
||||
|
||||
extern bool showlabels;
|
||||
|
||||
extern bool rog3;
|
||||
extern bool rvwarp;
|
||||
#if CAP_TOUR
|
||||
namespace rvtour {
|
||||
extern tour::slide rvslides[];
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace kohonen {
|
||||
extern int samples;
|
||||
int showsample(int id);
|
||||
int showsample(string id);
|
||||
void describe(cell *c);
|
||||
void steps();
|
||||
void showMenu();
|
||||
bool handleMenu(int sym, int uni);
|
||||
void clear();
|
||||
}
|
||||
|
||||
namespace staircase {
|
||||
extern bool on;
|
||||
void showMenu();
|
||||
void make_staircase();
|
||||
}
|
||||
|
||||
namespace banachtarski {
|
||||
extern bool on;
|
||||
void init_bantar();
|
||||
void bantar_anim();
|
||||
extern bool bmap;
|
||||
extern void init_bantar_map();
|
||||
}
|
||||
|
||||
namespace pentagonal {
|
||||
void run_snub(int v, int w);
|
||||
}
|
||||
|
||||
extern colorpair dftcolor;
|
||||
namespace collatz { extern double s2, s3, p2, p3; void start(); }
|
||||
namespace tree { void read(string fn); }
|
||||
namespace sag { extern ld edgepower, edgemul;
|
||||
void read(string fn);
|
||||
void loadsnake(const string& fn);
|
||||
}
|
||||
void readcolor(const string& cfname);
|
||||
extern bool on;
|
||||
|
||||
void close();
|
||||
extern bool showlabels;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
// Hyperbolic Rogue: staircase simulation in RogueViz
|
||||
// Copyright (C) 2011-2018 Zeno and Tehora Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// Kohonen's self-organizing networks.
|
||||
// This is a part of RogueViz, not a part of HyperRogue.
|
||||
|
||||
namespace rogueviz { namespace staircase {
|
||||
|
||||
ld scurvature = 0;
|
||||
ld acurvature = 0;
|
||||
|
||||
ld global_r;
|
||||
|
||||
ld szoom = 5;
|
||||
|
||||
ld progress = 0;
|
||||
|
||||
ld strafex, strafey;
|
||||
|
||||
hyperpoint spcoord(hyperpoint h) {
|
||||
ld phi = h[0], y = h[1], z = h[2], r = global_r;
|
||||
dynamicval<eGeometry> gw(geometry, rug::gwhere == gElliptic ? gSphere : rug::gwhere);
|
||||
hyperpoint inh = xpush(-acurvature*(y + r - frac(progress))/szoom) * xspinpush0(M_PI/2, acurvature*z);
|
||||
hyperpoint i = inh * (hdist0(inh) / hypot_d(2, inh));
|
||||
ld aphi = (r+phi + floor(progress))*M_PI/6;
|
||||
return hpxyz(i[1] * sin(aphi), i[1] * cos(aphi), i[0]);
|
||||
}
|
||||
|
||||
rug::rugpoint *pt(hyperpoint h, hyperpoint c) {
|
||||
auto r = rug::addRugpoint(C0, -1);
|
||||
r->flat = spcoord(h);
|
||||
r->x1 = c[0];
|
||||
r->y1 = c[1];
|
||||
r->valid = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
void addRect(hyperpoint h, hyperpoint hx, hyperpoint hy, hyperpoint v, hyperpoint vx, hyperpoint vy, int ix, int iy) {
|
||||
vector<vector<rug::rugpoint*> > rps(iy+1, vector<rug::rugpoint*> (ix+1));
|
||||
for(int y=0; y<=iy; y++)
|
||||
for(int x=0; x<=ix; x++) {
|
||||
rps[y][x] = pt(h+hx*x/ix+hy*y/iy, v+vx*x/ix+vy*y/iy);
|
||||
}
|
||||
for(int y=0; y<iy; y++)
|
||||
for(int x=0; x<ix; x++)
|
||||
rug::addTriangle(rps[y][x], rps[y+1][x], rps[y][x+1]),
|
||||
rug::addTriangle(rps[y+1][x+1], rps[y][x+1], rps[y+1][x]);
|
||||
}
|
||||
|
||||
void addTri(hyperpoint h, hyperpoint hx, hyperpoint hy, hyperpoint v, hyperpoint vx, hyperpoint vy, int i) {
|
||||
vector<vector<rug::rugpoint*> > rps(i+1, vector<rug::rugpoint*> (i+1));
|
||||
for(int y=0; y<=i; y++)
|
||||
for(int x=0; x<=i; x++) {
|
||||
if(x+y <= i)
|
||||
rps[y][x] = pt(h+hx*x/i+hy*y/i, v+vx*x/i+vy*y/i);
|
||||
}
|
||||
for(int y=0; y<i; y++)
|
||||
for(int x=0; x<i; x++) {
|
||||
if(x+y < i)
|
||||
rug::addTriangle(rps[y][x], rps[y+1][x], rps[y][x+1]);
|
||||
if(x+y+2 <= i)
|
||||
rug::addTriangle(rps[y+1][x+1], rps[y][x+1], rps[y+1][x]);
|
||||
}
|
||||
}
|
||||
|
||||
bool need_texture = true;
|
||||
|
||||
#if CAP_TEXTURE
|
||||
texture::texture_data tdata; // = texture::config.data;
|
||||
#endif
|
||||
|
||||
void make_texture() {
|
||||
#if CAP_TEXTURE
|
||||
printf("make texture\n");
|
||||
need_texture = false;
|
||||
tdata.whitetexture();
|
||||
int tw = tdata.twidth;
|
||||
printf("tw = %d\n", tw);
|
||||
int fw = tw / 4;
|
||||
auto pix = [&] (int k, int x, int y) -> unsigned& {
|
||||
return tdata.texture_pixels[y * tw + x + (k&3) * fw + (k>>2) * fw * tw];
|
||||
};
|
||||
for(int y=0; y<tw; y++)
|
||||
for(int x=0; x<tw; x++)
|
||||
pix(0,x,y) = rand();
|
||||
for(int y=0; y<=fw; y++)
|
||||
for(int x=0; x<=fw; x++) {
|
||||
typedef long long ll;
|
||||
pix(0,x,y) = 0xFF000000 + 0x10101 * ((x*ll(fw-x)*y*(fw-y)*255)/ll(fw/2)/(fw/2)/(fw-fw/2)/(fw-fw/2));
|
||||
pix(2,x,y) = 0xFF400000 + 0x10000 * (y * 63 / fw);
|
||||
pix(8,x,y) = 0xFF101010;
|
||||
pix(10,x,y) = 0xFF000000 + gradient(0, 0xFFD500, 0, x*(fw-x), fw*fw/4);
|
||||
pix(5,x,y) = 0xFF000000 + gradient(0, 0x804000, -1, sin(2*M_PI*8*y/fw), 1);
|
||||
pix(7,x,y) = 0xFF000000 + gradient(0, 0x808080, 0, x*ll(fw-x)*y*(fw-y), ll(fw/2)*(fw/2)*(fw-fw/2)*(fw-fw/2));
|
||||
}
|
||||
|
||||
tdata.loadTextureGL();
|
||||
#endif
|
||||
}
|
||||
|
||||
int savetex;
|
||||
|
||||
#if ISWEB
|
||||
int prec = 1;
|
||||
int maxr = 100;
|
||||
#else
|
||||
int prec = 4;
|
||||
|
||||
int maxr = 1000;
|
||||
#endif
|
||||
|
||||
bool on;
|
||||
|
||||
void make_staircase() {
|
||||
|
||||
// vid.stereo_mode = current_display->sODS;
|
||||
rug::no_fog = true;
|
||||
|
||||
println(hlog, "scurvature = ", scurvature, " progress = ", progress, " strafe=", strafex, ",", strafey);
|
||||
rug::renderonce = true;
|
||||
rug::rug_perspective = true;
|
||||
if(scurvature > -1e-6 && scurvature < 1e-6) {
|
||||
rug::gwhere = gEuclid;
|
||||
acurvature = 1;
|
||||
}
|
||||
else if(scurvature < 0) {
|
||||
rug::gwhere = gNormal;
|
||||
acurvature = -scurvature;
|
||||
}
|
||||
else {
|
||||
rug::gwhere = gSphere;
|
||||
acurvature = scurvature;
|
||||
}
|
||||
rug::ruggospeed = acurvature;
|
||||
vid.ipd = 0.15 * acurvature;
|
||||
if(!rug::rugged || !staircase::on) {
|
||||
staircase::on = true;
|
||||
rug::reopen();
|
||||
}
|
||||
if(need_texture) {
|
||||
make_texture();
|
||||
#if CAP_TEXTURE
|
||||
rug::alternate_texture = tdata.textureid;
|
||||
#endif
|
||||
}
|
||||
rug::clear_model();
|
||||
printf("compute\n");
|
||||
for(int r=-maxr; r<maxr; r++) {
|
||||
if(scurvature < -1e-6 && abs(r * acurvature) > 7*12) continue;
|
||||
if(scurvature > 1e-6 && abs(acurvature*r/szoom) > M_PI) continue;
|
||||
global_r = r;
|
||||
// step
|
||||
addRect(hpxyz(0,0,1), hpxyz(0,0,1), hpxyz(1,0,0), hpxy(0,0), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
||||
// step connection
|
||||
addRect(hpxyz(1,0,1), hpxyz(0,0,1), hpxyz(0,1,0), hpxy(0.75,0.25), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
||||
// triangle inner side
|
||||
addTri(hpxyz(1,0,1), hpxyz(0,1,0), hpxyz(-1,0,0), hpxy(.5,0), hpxy(.125,.125), hpxy(0,.125), prec);
|
||||
// rectangle under triangle
|
||||
addRect(hpxyz(0,0,1), hpxyz(1,1,0), hpxyz(0,1,0), hpxy(.5,.125), hpxy(.125,0), hpxy(0,.125), prec, prec);
|
||||
// barrier post
|
||||
addRect(hpxyz(.45,0,1.1), hpxyz(.1,.1,0), hpxyz(0,-3,0), hpxy(0,.5), hpxy(.25,0), hpxy(0,.25), 2, prec);
|
||||
// barrier
|
||||
addRect(hpxyz(.45,-3,1), hpxyz(0,0,.2), hpxyz(1,1,0), hpxy(.5,.5), hpxy(.25,0), hpxy(0,.25), 1, prec);
|
||||
// outer wall
|
||||
addRect(hpxyz(0,0,2), hpxyz(1,1,0), hpxyz(0,12,0), hpxy(.25,.25), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
||||
// lower wall
|
||||
addRect(hpxyz(0,1,1), hpxyz(1,1,0), hpxyz(0,0,1), hpxy(.5,0), hpxy(.25,0), hpxy(0,.25), prec, prec);
|
||||
}
|
||||
printf("push\n");
|
||||
rug::push_all_points(0, strafex * acurvature);
|
||||
rug::push_all_points(1, strafey * acurvature);
|
||||
for(auto p: rug::points) p->valid = true;
|
||||
rug::good_shape = true;
|
||||
printf("done (%d points)\n", isize(rug::points));
|
||||
rug::lowrug = 1e-2 * acurvature;
|
||||
rug::hirug = 1e3 * acurvature;
|
||||
}
|
||||
|
||||
// -0.50 .. 0.16
|
||||
|
||||
int ctick;
|
||||
|
||||
void check() {
|
||||
if(ctick && ctick < ticks) {
|
||||
calcparam();
|
||||
make_staircase();
|
||||
ctick = 0;
|
||||
}
|
||||
if(on && !rug::rugged) {
|
||||
on = false;
|
||||
rug::alternate_texture = 0;
|
||||
rug::no_fog = false;
|
||||
rug::ruggospeed = 1;
|
||||
staircase::on = false;
|
||||
}
|
||||
}
|
||||
|
||||
void showMenu() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("Spiral Staircase"), iinf[itPalace].color, 150, 0);
|
||||
|
||||
dialog::addSelItem(" " + XLAT("X"), fts(strafex), 'x');
|
||||
dialog::addSelItem(" " + XLAT("Y"), fts(strafey), 'y');
|
||||
dialog::addSelItem(" " + XLAT("curvature"), fts(scurvature), 'c');
|
||||
|
||||
dialog::addBreak(100);
|
||||
dialog::addItem(XLAT("disable menu"), SDLK_ESCAPE);
|
||||
dialog::addBoolItem(XLAT("low quality"), prec == 1, '1');
|
||||
dialog::addBoolItem(XLAT("medium quality"), prec == 2, '2');
|
||||
#if !ISWEB
|
||||
dialog::addBoolItem(XLAT("high quality"), prec == 4, '3');
|
||||
#endif
|
||||
dialog::addItem(XLAT("take me back"), 'q');
|
||||
|
||||
dialog::display();
|
||||
keyhandler = [] (int sym, int uni) {
|
||||
dialog::handleNavigation(sym, uni);
|
||||
|
||||
if(uni == 'x') {
|
||||
dialog::editNumber(strafex, -1, 1, .05, 1, XLAT("X"),
|
||||
XLAT("Also changed with keys A/D")
|
||||
);
|
||||
dialog::reaction = [] () { ctick = ticks + 500; };
|
||||
}
|
||||
else if(uni == 'y') {
|
||||
dialog::editNumber(strafey, -1, 1, .05, 1, XLAT("Y"),
|
||||
XLAT("Also changed with keys W/S")
|
||||
);
|
||||
dialog::reaction = [] () { ctick = ticks + 500; };
|
||||
}
|
||||
else if(uni == 'c') {
|
||||
dialog::editNumber(scurvature, -1, 1, .05, 1, XLAT("curvature"),
|
||||
XLAT("Also changed with keys K/L. Press G for the golden spiral")
|
||||
);
|
||||
dialog::reaction = [] () { ctick = ticks + 500; };
|
||||
}
|
||||
else if(uni == 'w') {
|
||||
strafey += .1;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == 's') {
|
||||
strafey -= .1;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == 'd') {
|
||||
strafex += .1;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == 'a') {
|
||||
strafex -= .1;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == 'k') {
|
||||
scurvature += .02;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == 'l') {
|
||||
scurvature -= .02;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == 'p') {
|
||||
progress += .1;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == 'g') {
|
||||
scurvature = -4 * log((sqrt(5)+1)/2) / 2.4;
|
||||
ctick = ticks + 200;
|
||||
}
|
||||
else if(uni == '1') {
|
||||
prec = 1, maxr = 100;
|
||||
make_staircase();
|
||||
}
|
||||
else if(uni == '2') {
|
||||
prec = 2, maxr = 300;
|
||||
make_staircase();
|
||||
}
|
||||
#if !ISWEB
|
||||
else if(uni == '3') {
|
||||
prec = 4, maxr = 1000;
|
||||
make_staircase();
|
||||
}
|
||||
#endif
|
||||
else if(uni == 'q') {
|
||||
ctick = 0;
|
||||
rug::close();
|
||||
popScreen();
|
||||
}
|
||||
else if(doexiton(sym, uni)) popScreen();
|
||||
};
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
// #1: load the samples
|
||||
|
||||
if(argis("-stair")) {
|
||||
showstartmenu = false;
|
||||
ctick = ticks + 2000;
|
||||
pushScreen(showMenu);
|
||||
}
|
||||
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int phooks = addHook(hooks_args, 100, readArgs)
|
||||
+ addHook(hooks_fixticks, 100, check);
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,92 @@
|
||||
// non-Euclidean sunflower spirals (aka golden spirals or Fibonacci spirals)
|
||||
// Copyright (C) 2018 Zeno and Tehora Rogue, see 'hyper.cpp' for details
|
||||
|
||||
// use: commandline parameter -sunflower <quantity> <density>
|
||||
// e.g.: hyper -sunflower 10000 0.01
|
||||
|
||||
// for spherical geometry, density is set automatically to cover the whole sphere
|
||||
|
||||
namespace hr {
|
||||
|
||||
namespace sunflower {
|
||||
|
||||
int qty = 100;
|
||||
ld density = 1, zdensity;
|
||||
|
||||
static const int maxfib = 300000;
|
||||
|
||||
hyperpoint ps[maxfib];
|
||||
|
||||
hyperpoint p(int i) {
|
||||
ld step = M_PI * (3 - sqrt(5));
|
||||
return spin(i * step) * xpush(sphere ? (i+.5) * M_PI / qty : euclid ? sqrt((i+.5) * density) : acosh(1 + (i+.5) * density)) * C0;
|
||||
}
|
||||
|
||||
int inext[maxfib], inext2[maxfib];
|
||||
|
||||
const vector<int> fibs =
|
||||
{1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811};
|
||||
|
||||
bool sunflower_cell(cell *c, transmatrix V) {
|
||||
density = zdensity / 100;
|
||||
if(c == cwt.at) {
|
||||
for(int i=0; i<qty; i++) ps[i] = V * p(i);
|
||||
|
||||
for(int i=0; i<qty; i++) {
|
||||
ld ba = 99;
|
||||
ld bb = 99;
|
||||
int bi = 0, bj = 0;
|
||||
for(int a: fibs) {
|
||||
if(a>i) break;
|
||||
if(hdist(ps[i], ps[i-a]) < ba)
|
||||
bb = ba, bj = bi, ba = hdist(ps[i], ps[i-a]), bi = i-a;
|
||||
else if(hdist(ps[i], ps[i-a]) < bb)
|
||||
bb = hdist(ps[i], ps[i-a]), bj = i-a;
|
||||
}
|
||||
inext[i] = bi;
|
||||
inext2[i] = bj;
|
||||
}
|
||||
|
||||
for(int i=0; i<qty; i++) {
|
||||
if(inext[inext[i]] == inext2[i] || inext2[inext[i]] == inext2[i] || inext[inext2[i]] == inext[i] || inext2[inext2[i]] == inext[i]) {
|
||||
curvepoint(ps[i]);
|
||||
curvepoint(ps[inext[i]]);
|
||||
curvepoint(ps[inext2[i]]);
|
||||
queuecurve(0xFFFFFFFF, 0x00C000FF, PPR::LINE);
|
||||
}
|
||||
else {
|
||||
curvepoint(ps[i]);
|
||||
curvepoint(ps[inext[i]]);
|
||||
curvepoint(ps[inext[i] + inext2[i] - i]);
|
||||
curvepoint(ps[inext2[i]]);
|
||||
queuecurve(0xFFFFFFFF, 0x0000C0FF, PPR::LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-sunflower")) {
|
||||
shift(); qty = argi();
|
||||
shift(); zdensity = argf() * 100;
|
||||
patterns::whichShape = '9';
|
||||
nohud = true;
|
||||
addHook(hooks_drawcell, 100, sunflower_cell);
|
||||
addHook(hooks_mainmenu, 100, [] () {
|
||||
dialog::addItem("sunflower", 1001);
|
||||
dialog::add_action([] () { dialog::editNumber(zdensity, 0, 1, .1, 1, "density", "density"); });
|
||||
});
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto hook = addHook(hooks_args, 100, readArgs);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
// RogueViz -- source code for creating videos and animations
|
||||
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
namespace rogueviz {
|
||||
|
||||
#if CAP_SDL && CAP_SHOT
|
||||
|
||||
// see: https://www.youtube.com/watch?v=4Vu3F95jpQ4&t=6s (Collatz)
|
||||
// see: https://www.youtube.com/watch?v=mDG3_f8R2Ns (SAG boardgames)
|
||||
// see: https://www.youtube.com/watch?v=WSyygk_3j9o (SAG roguelikes)
|
||||
// see: https://www.youtube.com/watch?v=HWQkDkeEUeM (SAG programming languages)
|
||||
|
||||
void rvvideo(const string &fname) {
|
||||
if(kind == kCollatz) {
|
||||
sightrange_bonus = 3;
|
||||
genrange_bonus = 3;
|
||||
dronemode = true; vid.camera_angle = -45; rog3 = true; patterns::whichShape = '8';
|
||||
vid.aurastr = 512;
|
||||
|
||||
collatz::lookup(763, 60);
|
||||
|
||||
history::create_playerpath(), models::rotation = 1;
|
||||
// pmodel = mdBand;
|
||||
|
||||
#define STORYCOUNT 24
|
||||
#define T(m,ss) (60*24*(m)+24*(ss))
|
||||
#define FRAMECOUNT T(4,55)
|
||||
|
||||
printf("framecount = %d\n", FRAMECOUNT);
|
||||
|
||||
struct storydata { int s; int e; const char *text; } story[] = {
|
||||
{T(0,14), T(0,17), "I am flying above a tree of numbers."},
|
||||
{T(0,17), T(0,20), "It starts with the number 1."},
|
||||
{T(0,20), T(0,23), "Each number n branches left to 2n."},
|
||||
{T(0,23), T(0,28), "And it branches right to (2n-1)/3 if possible."},
|
||||
|
||||
{T(1, 8), T(1,11), "What I am flying above is not a plane."},
|
||||
{T(1,11), T(1,14), "It is not a sphere either."},
|
||||
{T(1,14), T(1,17), "To be honest, the space I live in..."},
|
||||
{T(1,17), T(1,20), "...is not even Euclidean."},
|
||||
|
||||
{T(2,12), T(2,15), "Look, angles of a triangle add up to..."},
|
||||
{T(2,15), T(2,18), "...less than 180 degrees in this world."},
|
||||
{T(2,18), T(2,21), "6/7 of 180 degrees, to be exact."},
|
||||
{T(2,21), T(2,24), "Do you see the regular heptagons?"},
|
||||
{T(2,36), T(2,42), "And all these lines are straight."},
|
||||
|
||||
{T(3, 8), T(3,11), "Lots of space in my world."},
|
||||
{T(3,11), T(3,14), "In 105 steps from the root..."},
|
||||
{T(3,14), T(3,17), "...there are trillions of numbers."},
|
||||
{T(3,17), T(3,20), "That would not fit in your world."},
|
||||
|
||||
{T(4,0), T(4,3), "Is every positive number somewhere in the tree?"},
|
||||
{T(4,3), T(4,6), "Your mathematicians do not know this yet."},
|
||||
{T(4,6), T(4,10), "Will you find the answer?"},
|
||||
|
||||
{T(4,44), T(4,54), "music: Ambient Flow, by Indjenuity"},
|
||||
|
||||
{T(2,6), T(2,27), "@triangles"},
|
||||
{T(2,27), T(2,42), "@network"},
|
||||
|
||||
{0, T(0,7), "@fi"},
|
||||
{T(4,48), T(4,55), "@fo"},
|
||||
|
||||
{0,0,NULL}
|
||||
};
|
||||
|
||||
int drawtris=0, drawnet=0;
|
||||
|
||||
for(int i=0; i<FRAMECOUNT; i++) {
|
||||
const char *caption = NULL;
|
||||
int fade = 255;
|
||||
|
||||
bool dt = false, dn = false;
|
||||
|
||||
for(int j=0; story[j].text; j++) if(i >= story[j].s && i <= story[j].e) {
|
||||
if(story[j].text[0] != '@')
|
||||
caption = story[j].text;
|
||||
else if(story[j].text[1] == 't')
|
||||
dt = true;
|
||||
else if(story[j].text[1] == 'n')
|
||||
dn = true;
|
||||
else if(story[j].text[2] == 'i')
|
||||
fade = 255 * (i - story[j].s) / (story[j].e-story[j].s);
|
||||
else if(story[j].text[2] == 'o')
|
||||
fade = 255 * (story[j].e - i) / (story[j].e-story[j].s);
|
||||
}
|
||||
|
||||
if(dt && drawtris < 255) drawtris++;
|
||||
else if(drawtris && !dt) drawtris--;
|
||||
|
||||
linepatterns::setColor(linepatterns::patZebraTriangles, 0x40FF4000 + drawtris);
|
||||
|
||||
if(dn && drawnet < 255) drawnet++;
|
||||
else if(drawnet && !dn) drawnet--;
|
||||
|
||||
linepatterns::setColor(linepatterns::patZebraLines, 0xFF000000 + drawnet);
|
||||
|
||||
vid.grid = drawnet;
|
||||
|
||||
history::phase = 1 + (isize(history::v)-3) * i * .95 / FRAMECOUNT;
|
||||
history::movetophase();
|
||||
|
||||
char buf[500];
|
||||
snprintf(buf, 500, fname.c_str(), i);
|
||||
|
||||
if(i == 0) drawthemap();
|
||||
shmup::turn(100);
|
||||
printf("%s\n", buf);
|
||||
shot::shoty = 1080; shot::shotx = 1920;
|
||||
shot::caption = caption;
|
||||
shot::fade = fade;
|
||||
shot::take(buf);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
for(int i=0; i<1800; i++) {
|
||||
char buf[500];
|
||||
snprintf(buf, 500, fname.c_str(), i);
|
||||
shmup::pc[0]->base = currentmap->gamestart();
|
||||
shmup::pc[0]->at = spin(i * 2 * M_PI / (58*30.)) * xpush(1.7);
|
||||
if(i == 0) drawthemap();
|
||||
shmup::turn(100);
|
||||
if(i == 0) drawthemap();
|
||||
centerpc(100);
|
||||
printf("%s\n", buf);
|
||||
shot::take(buf);
|
||||
}
|
||||
}
|
||||
|
||||
string its05(int i) { char buf[64]; sprintf(buf, "%05d", i); return buf; }
|
||||
|
||||
#define TSIZE 4096
|
||||
|
||||
// see: https://www.youtube.com/watch?v=HZNRo6mr5pk
|
||||
|
||||
void staircase_video(int from, int num, int step) {
|
||||
resetbuffer rb;
|
||||
renderbuffer rbuf(TSIZE, TSIZE, true);
|
||||
vid.stereo_mode = sODS;
|
||||
|
||||
for(int i=from; i<num; i+=step) {
|
||||
ld t = i * 1. / num;
|
||||
t = pow(t, .3);
|
||||
staircase::scurvature = t * t * (t-.95) * 4;
|
||||
staircase::progress = i / 30.;
|
||||
|
||||
staircase::strafex = (sin(i / 240.) - sin(i / 501.)) / 2.5;
|
||||
staircase::strafey = (cos(i / 240.) - cos(i / 501.)) / 2.5;
|
||||
|
||||
staircase::make_staircase();
|
||||
|
||||
rbuf.enable();
|
||||
dynamicval<int> vx(vid.xres, TSIZE);
|
||||
dynamicval<int> vy(vid.yres, TSIZE);
|
||||
dynamicval<int> vxc(current_display->xcenter, TSIZE/2);
|
||||
dynamicval<int> vyc(current_display->ycenter, TSIZE/2);
|
||||
printf("draw scene\n");
|
||||
rug::drawRugScene();
|
||||
|
||||
IMAGESAVE(rbuf.render(), ("staircase/" + its05(i) + IMAGEEXT).c_str());
|
||||
printf("GL %5d/%5d\n", i, num);
|
||||
}
|
||||
|
||||
rb.reset();
|
||||
}
|
||||
|
||||
#undef TSIZE
|
||||
|
||||
#define TSIZE 2048
|
||||
|
||||
// see: https://twitter.com/ZenoRogue/status/1001127253747658752
|
||||
// see also: https://twitter.com/ZenoRogue/status/1000043540985057280 (older version)
|
||||
|
||||
void bantar_record() {
|
||||
resetbuffer rb;
|
||||
renderbuffer rbuf(TSIZE, TSIZE, true);
|
||||
|
||||
int fr = 0;
|
||||
|
||||
for(int i=0; i < 10000; i += 33) {
|
||||
if(i % 1000 == 999) i++;
|
||||
ticks = i;
|
||||
|
||||
rbuf.enable();
|
||||
vid.xres = vid.yres = TSIZE;
|
||||
banachtarski::bantar_frame();
|
||||
|
||||
IMAGESAVE(rbuf.render(), ("bantar/" + its05(fr) + IMAGEEXT).c_str());
|
||||
printf("GL %5d/%5d\n", i, 10000);
|
||||
fr++;
|
||||
}
|
||||
|
||||
rb.reset();
|
||||
}
|
||||
#undef TSIZE
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int videoArgs() {
|
||||
using namespace arg;
|
||||
if(argis("-rvvideo")) {
|
||||
shift(); rvvideo(arg::args());
|
||||
}
|
||||
else if(argis("-staircase_video")) {
|
||||
staircase_video(0, 128*30, 1); // goal: 168*30
|
||||
}
|
||||
else if(argis("-bantar_record")) {
|
||||
using namespace banachtarski;
|
||||
PHASE(3);
|
||||
peace::on = true;
|
||||
airmap.clear();
|
||||
ForInfos if(cci.second.c->monst == moAirElemental)
|
||||
cci.second.c->monst = moFireElemental;
|
||||
bantar_record();
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto rv_hooks = addHook(hooks_args, 100, videoArgs);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user