2020-03-29 12:37:14 +00:00
|
|
|
#include "rogueviz.h"
|
|
|
|
|
2018-09-03 14:34:32 +00:00
|
|
|
namespace rogueviz {
|
|
|
|
|
2019-05-06 23:08:49 +00:00
|
|
|
#if CAP_ARCM
|
2018-09-03 14:34:32 +00:00
|
|
|
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) {
|
2020-07-29 21:34:00 +00:00
|
|
|
auto r = rug::addRugpoint(shiftless(C0), -1);
|
2020-04-16 19:01:03 +00:00
|
|
|
r->native = h;
|
2018-09-03 14:34:32 +00:00
|
|
|
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)");
|
2019-05-27 05:18:18 +00:00
|
|
|
check_cgi();
|
|
|
|
cgi.require_basics();
|
2018-09-03 14:34:32 +00:00
|
|
|
specialland = laCanvas;
|
|
|
|
patterns::whichCanvas = 'A';
|
|
|
|
// vid.wallmode = 1;
|
|
|
|
printf("start game\n");
|
2019-05-27 05:18:18 +00:00
|
|
|
printf("distlimit = %d\n", cgi.base_distlimit);
|
2018-09-03 14:34:32 +00:00
|
|
|
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())
|
2020-07-29 21:34:00 +00:00
|
|
|
gmatrix[c] = shiftless(arcm::archimedean_gmatrix[c->master].second);
|
2018-09-03 14:34:32 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-07-29 21:34:00 +00:00
|
|
|
transmatrix rel = inverse(gmatrix[p0].T);
|
2018-09-03 14:34:32 +00:00
|
|
|
|
2020-07-29 21:34:00 +00:00
|
|
|
ts[0] = rel * gmatrix[t0].T * ddspin(t0, (cw - 1 + wstep).spin);
|
|
|
|
ts[1] = rel * gmatrix[t1].T;
|
|
|
|
ts[2] = rel * gmatrix[t2].T * ddspin(t2, (cw + wstep + 1 + wstep - 1).spin);
|
2018-09-03 14:34:32 +00:00
|
|
|
|
|
|
|
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++) {
|
2020-07-29 21:34:00 +00:00
|
|
|
transmatrix T = rel * ggmatrix(c).T * spin(2*M_PI*d/v);
|
2018-09-03 14:34:32 +00:00
|
|
|
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);
|
2018-11-08 17:18:25 +00:00
|
|
|
ld alpha = (M_PI - acos(scalar)) / degree;
|
2018-09-03 14:34:32 +00:00
|
|
|
sideangles.emplace_back(alpha, T);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<double> sav;
|
|
|
|
for(auto p: sideangles) sav.push_back(p.first);
|
|
|
|
sort(sav.begin(), sav.end());
|
|
|
|
|
2018-11-24 16:01:49 +00:00
|
|
|
println(hlog, "sideangles ", sav);
|
2018-09-03 14:34:32 +00:00
|
|
|
|
|
|
|
xts0 = tC0(ts[0]);
|
|
|
|
|
2018-11-24 16:01:49 +00:00
|
|
|
println(hlog, "original ", xts0);
|
2018-09-03 14:34:32 +00:00
|
|
|
|
2020-07-29 21:34:00 +00:00
|
|
|
cor = rel * gmatrix[cc].T * C0;
|
2018-09-03 14:34:32 +00:00
|
|
|
|
|
|
|
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;
|
2020-04-17 18:45:00 +00:00
|
|
|
vid.rug_config.model = hyperbolic ? mdPerspective : mdEquidistant;
|
2018-09-03 14:34:32 +00:00
|
|
|
showstartmenu = false;
|
|
|
|
snubon = true;
|
|
|
|
rug::invert_depth = hyperbolic;
|
|
|
|
}
|
|
|
|
|
2019-07-12 21:18:38 +00:00
|
|
|
ld x, y;
|
|
|
|
|
2018-09-03 14:34:32 +00:00
|
|
|
void create_model() {
|
|
|
|
|
2019-07-12 21:18:38 +00:00
|
|
|
if(!inHighQual) {
|
|
|
|
x = (mousex - current_display->xcenter + .0) / vid.xres;
|
|
|
|
y = (mousey - current_display->ycenter + .0) / vid.yres;
|
|
|
|
}
|
|
|
|
|
2018-09-03 14:34:32 +00:00
|
|
|
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);
|
2018-09-03 20:35:32 +00:00
|
|
|
if(f[0] > -1e-6 || std::isnan(f[0])) good1++;
|
|
|
|
if(f[0] < +1e-6 || std::isnan(f[0])) good2++;
|
2018-09-03 14:34:32 +00:00
|
|
|
}
|
|
|
|
// printf("\n");
|
|
|
|
if(good1 == 5 || good2 == 5) {ctr = h; break; }
|
|
|
|
idh++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// printf("idh = %d\n", idh);
|
2019-07-12 21:18:38 +00:00
|
|
|
|
|
|
|
printf("createmodel with ticks = %d\n", ticks);
|
2018-09-03 14:34:32 +00:00
|
|
|
|
2019-09-05 22:29:40 +00:00
|
|
|
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);
|
2018-09-03 14:34:32 +00:00
|
|
|
|
|
|
|
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;
|
2018-11-17 18:24:02 +00:00
|
|
|
displaychr(current_display->xcenter, current_display->ycenter, 0, 10, 'X', 0xFFFFFF);
|
2018-09-03 14:34:32 +00:00
|
|
|
clearMessages();
|
|
|
|
nohelp = true;
|
|
|
|
playerfound = true;
|
2018-09-04 22:18:22 +00:00
|
|
|
return true;
|
2018-09-03 14:34:32 +00:00
|
|
|
}
|
2018-09-04 22:18:22 +00:00
|
|
|
return false;
|
2018-09-03 14:34:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool handleKey(int sym, int uni) {
|
|
|
|
if(snubon) {
|
2019-07-12 21:18:38 +00:00
|
|
|
if(among(uni, '3', '4', '5', '6', '7', '8', '9') && (cmode & sm::NORMAL)) {
|
2018-09-03 14:34:32 +00:00
|
|
|
run_snub(uni - '0', 3);
|
|
|
|
return true;
|
|
|
|
}
|
2019-07-12 21:18:38 +00:00
|
|
|
if(among(uni, '#', '$', '%', '&', '^') && (cmode & sm::NORMAL)) {
|
2018-09-03 14:34:32 +00:00
|
|
|
if(uni == '^') uni = '&';
|
|
|
|
run_snub(uni - 32, 4);
|
|
|
|
return true;
|
|
|
|
}
|
2019-07-12 21:18:38 +00:00
|
|
|
if(uni == 'a' && (cmode & sm::NORMAL)) {
|
2018-09-03 14:34:32 +00:00
|
|
|
rug::close();
|
|
|
|
mapeditor::drawplayer = false;
|
|
|
|
return true;
|
|
|
|
}
|
2019-07-12 21:18:38 +00:00
|
|
|
if(uni == 's' && rug::rugged && (cmode & sm::NORMAL)) {
|
2018-11-17 18:24:02 +00:00
|
|
|
vid.fov += 30;
|
|
|
|
if(vid.fov >= 180) vid.fov = 60;
|
2018-09-03 14:34:32 +00:00
|
|
|
}
|
2019-07-12 21:18:38 +00:00
|
|
|
if(uni == 'i' && rug::rugged && (cmode & sm::NORMAL)) {
|
2018-09-03 14:34:32 +00:00
|
|
|
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)
|
2020-04-11 18:40:12 +00:00
|
|
|
+ addHook(hooks_clearmemory, 40, [] () { snubon = false; } )
|
2021-03-30 19:48:04 +00:00
|
|
|
+ addHook(pres::hooks_build_rvtour, 142, [] (string s, vector<tour::slide>& v) {
|
|
|
|
if(s != "mixed") return;
|
2020-03-29 11:52:10 +00:00
|
|
|
using namespace tour;
|
|
|
|
v.push_back(
|
2021-03-30 19:48:04 +00:00
|
|
|
tour::slide{"Pentagonal Exploration", 62, LEGAL::NONE | QUICKGEO,
|
2020-03-29 11:52:10 +00:00
|
|
|
"Pentagonal Exploration explained at: http://www.roguetemple.com/z/sims/snub/\n\n"
|
|
|
|
"Move the mouse nearer and further away from the X.\n\n"
|
|
|
|
"Press 3 4 5 6 7 8 9 shift+4 shift+5 shift+6 to change the geometry.",
|
|
|
|
|
|
|
|
[] (presmode mode) {
|
|
|
|
if(mode == 1) {
|
|
|
|
pentagonal::run_snub(5, 3);
|
|
|
|
}
|
|
|
|
if(mode == 3) {
|
|
|
|
printf("stopping\n");
|
|
|
|
set_geometry(gNormal);
|
|
|
|
set_variation(eVariation::bitruncated);
|
|
|
|
rug::close();
|
|
|
|
start_game();
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
);
|
|
|
|
});
|
2018-09-03 14:34:32 +00:00
|
|
|
|
|
|
|
}
|
2019-05-06 23:08:49 +00:00
|
|
|
#endif
|
2018-09-03 14:34:32 +00:00
|
|
|
}
|