mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-23 21:07:17 +00:00
nilrider:: first commit
This commit is contained in:
parent
e25b8b94c2
commit
920bf96088
312
rogueviz/nilrider/level.cpp
Normal file
312
rogueviz/nilrider/level.cpp
Normal file
@ -0,0 +1,312 @@
|
||||
namespace nilrider {
|
||||
|
||||
void level::init() {
|
||||
if(initialized) return;
|
||||
initialized = true;
|
||||
|
||||
unil_texture = new texture::texture_data;
|
||||
|
||||
auto& tex = *unil_texture;
|
||||
|
||||
real_minx = HUGE_VAL;
|
||||
real_miny = HUGE_VAL;
|
||||
real_maxx = -HUGE_VAL;
|
||||
real_maxy = -HUGE_VAL;
|
||||
|
||||
if(flags & nrlPolar)
|
||||
scale = 1;
|
||||
else
|
||||
scale = abs(maxx - minx) / isize(map_tiles[0]);
|
||||
|
||||
println(hlog, "SCALE IS ", this->scale);
|
||||
|
||||
int tY = isize(map_tiles);
|
||||
int tX = isize(map_tiles[0]);
|
||||
|
||||
tex.twidth = tex.tx = tX * 64;
|
||||
tex.theight = tex.ty = tY * 64;
|
||||
tex.stretched = false;
|
||||
tex.strx = tex.tx;
|
||||
tex.stry = tex.ty;
|
||||
tex.base_x = 0;
|
||||
tex.base_y = 0;
|
||||
tex.whitetexture();
|
||||
println(hlog, "tX=", tX, " tY=", tY, " tex=", tex.tx, "x", tex.ty);
|
||||
|
||||
for(int y=0; y<tex.ty; y++)
|
||||
for(int x=0; x<tex.tx; x++) {
|
||||
int bx = x / 64;
|
||||
int by = y / 64;
|
||||
char bmch = map_tiles[by][bx];
|
||||
int sx = (x % 64) / 4;
|
||||
int sy = (y % 64) / 4;
|
||||
if(bmch == '!') continue;
|
||||
char smch = submaps[bmch][sy][sx];
|
||||
tex.get_texture_pixel(x, y) = bcols[smch];
|
||||
tex.get_texture_pixel(x, y) |= 0xFF000000;
|
||||
tex.get_texture_pixel(x, y) ^= hrand(0x1000000) & 0xF0F0F;
|
||||
// (x * 256 / TEXSIZE + (((y * 256) / TEXSIZE) << 8)) | 0xFF000000;
|
||||
}
|
||||
tex.loadTextureGL();
|
||||
|
||||
start.where = mappt(startx+.5, starty+.5, 1);
|
||||
start.t = 0;
|
||||
current = start;
|
||||
println(hlog, "start.where = ", start.where);
|
||||
println(hlog, "current.where = ", current.where, " : ", format("%p", ¤t));
|
||||
|
||||
for(int s=0; s<2; s++) {
|
||||
cgi.bshape(s == 0 ? shFloor : shPlanFloor, PPR::WALL);
|
||||
shFloor.flags |= POLY_TRIANGLES;
|
||||
shPlanFloor.flags |= POLY_TRIANGLES;
|
||||
|
||||
auto pt = [&] (int x, int y) {
|
||||
if(s == 0) uniltinf.tvertices.push_back(glhr::makevertex(x * 1. / tX / 16, y * 1. / tY / 16, 0));
|
||||
hyperpoint h = mappt(x, y, 16);
|
||||
real_minx = min(real_minx, h[0]);
|
||||
real_maxx = max(real_maxx, h[0]);
|
||||
real_miny = min(real_miny, h[1]);
|
||||
real_maxy = max(real_maxy, h[1]);
|
||||
if(s == 1) h[2] = h[3] = 1;
|
||||
// h[2] = h[0] * h[1] / 2 + .1;
|
||||
// h[3] = 1;
|
||||
cgi.hpcpush(h);
|
||||
// println(hlog, "entered ", h);
|
||||
// cgi.hpcpush(hyperpoint(rand() % 10 - 5, rand() % 10 - 5, rand() % 10 - 5, 1));
|
||||
};
|
||||
|
||||
for(int y=0; y<tY * 16; y++)
|
||||
for(int x=0; x<tX * 16; x++) {
|
||||
char bmch = map_tiles[y/16][x/16];
|
||||
if(bmch == '!') continue;
|
||||
pt(x, y);
|
||||
pt(x, y+1);
|
||||
pt(x+1, y);
|
||||
pt(x+1, y+1);
|
||||
pt(x+1, y);
|
||||
pt(x, y+1);
|
||||
}
|
||||
cgi.finishshape();
|
||||
}
|
||||
|
||||
if(1) {
|
||||
cgi.bshape(shField, PPR::WALL);
|
||||
shField.flags |= POLY_TRIANGLES;
|
||||
|
||||
auto pt = [&] (hyperpoint p) {
|
||||
hyperpoint h = mappt(p[0], p[1], 16);
|
||||
h[2] += p[2];
|
||||
cgi.hpcpush(h);
|
||||
// cgi.hpcpush(hyperpoint(rand() % 10 - 5, rand() % 10 - 5, rand() % 10 - 5, 1));
|
||||
};
|
||||
|
||||
for(int y=0; y<tY * 16; y++)
|
||||
for(int x=0; x<tX * 16; x++) {
|
||||
int bx = x / 16;
|
||||
int by = y / 16;
|
||||
char bmch = map_tiles[by][bx];
|
||||
if(bmch == 'f' && (x&1) && (y&1)) {
|
||||
for(int s=0; s<4; s++) {
|
||||
hyperpoint st = point3(x+.1, y+.1, 0);
|
||||
hyperpoint a = spin(90*degree*s) * point3(.1, .1, 0);
|
||||
hyperpoint b = spin(90*degree*(s+1)) * point3(.1, .1, 0);
|
||||
hyperpoint hi = point3(0, 0, 1);
|
||||
for(int z=0; z<3; z++) {
|
||||
ld z1 = (3-z) / 3.;
|
||||
ld z2 = (2-z) / 3.;
|
||||
pt(st + a * z1 + hi*z);
|
||||
pt(st + b * z1 + hi*z);
|
||||
pt(st + a * z2 + hi*(z+1));
|
||||
pt(st + a * z2 + hi*(z+1));
|
||||
pt(st + b * z1 + hi*z);
|
||||
pt(st + b * z2 + hi*(z+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cgi.finishshape();
|
||||
}
|
||||
|
||||
if(1) {
|
||||
cgi.bshape(shCastle, PPR::WALL);
|
||||
shCastle.flags |= POLY_TRIANGLES;
|
||||
|
||||
for(int y=0; y<tY; y++)
|
||||
for(int x=0; x<tX; x++) {
|
||||
char bmch = map_tiles[y][x];
|
||||
if(bmch == 'r') {
|
||||
for(int s=0; s<4; s++) {
|
||||
hyperpoint ctr = mappt(x+.5, y+.5, 1);
|
||||
ctr[2] += safe_alt(ctr) + .5 * scale;
|
||||
ld need = safe_alt(ctr, -1) / scale / scale;
|
||||
int max_y = need * 2 + 1;
|
||||
|
||||
hyperpoint a = spin(90*degree*s) * point3(1, 0, 0);
|
||||
hyperpoint b = spin(90*degree*s) * point3(0, 1, 0);
|
||||
|
||||
auto pt = [&] (ld af, ld bf, ld yf) {
|
||||
hyperpoint ha = a * af * scale; ha[3] = 1;
|
||||
hyperpoint hb = b * bf * scale; hb[3] = 1;
|
||||
hyperpoint res = rgpushxto0(ctr) * rgpushxto0(ha) * rgpushxto0(hb) * point31(0, 0, yf * scale * scale);
|
||||
cgi.hpcpush(res);
|
||||
};
|
||||
|
||||
auto ptf = [&] (ld af, ld bf, ld yf) {
|
||||
pt(af, bf, yf);
|
||||
castle_tinf.tvertices.push_back(glhr::makevertex(bf, yf*4, 0));
|
||||
};
|
||||
|
||||
auto ptc = [&] (ld af, ld bf, ld yf, ld xt, ld yt) {
|
||||
pt(af, bf, yf);
|
||||
castle_tinf.tvertices.push_back(glhr::makevertex(xt, yt, 0));
|
||||
};
|
||||
|
||||
for(int w=0; w<2; w++)
|
||||
for(int as=0; as<8; as++)
|
||||
for(int y=0; y<max_y; y++) {
|
||||
ld xf = w ? .4 : .5;
|
||||
ld y1 = -y/2.;
|
||||
ld y2 = -(y+1)/2.;
|
||||
ld asd = (as-4) / 8.;
|
||||
ld asd1 = (as-3) / 8.;
|
||||
auto oasd = asd / 4;
|
||||
if(w) asd *= .8, asd1 *= .8, oasd *= .8 * .8;
|
||||
ptf(xf, asd, y1 - oasd);
|
||||
ptf(xf, asd1, y1 - oasd);
|
||||
ptf(xf, asd, y2 - oasd);
|
||||
ptf(xf, asd, y2 - oasd);
|
||||
ptf(xf, asd1, y1 - oasd);
|
||||
ptf(xf, asd1, y2 - oasd);
|
||||
}
|
||||
|
||||
ld x1 = 1/32.;
|
||||
ld x2 = 1/4. + x1;
|
||||
ld y1 = 1/32.;
|
||||
ld y2 = 1/8. + x1;
|
||||
|
||||
for(int as=0; as<8; as++) {
|
||||
ld asd = (as-4) / 8.;
|
||||
ld asd1 = (as-3) / 8.;
|
||||
ld asdw = asd * .8;
|
||||
ld asdw1 = asd1 * .8;
|
||||
ld asd2 = (as-5) / 8.;
|
||||
//ld asdw2 = asd2 * .8;
|
||||
ld oasd = asd / 4;
|
||||
ld oasdw = oasd * .8 * .8;
|
||||
ld oasd2 = asd2 / 4;
|
||||
ld oasdw2 = oasd2 * .8 * .8;
|
||||
/* tops */
|
||||
ptc(.5, asd, -oasd, x1, y1);
|
||||
ptc(.5, asd1, - oasd, x1, y2);
|
||||
ptc(.4, asdw, -oasdw, x2, y1);
|
||||
ptc(.4, asdw, -oasdw, x2, y1);
|
||||
ptc(.5, asd1, - oasd, x1, y2);
|
||||
ptc(.4, asdw1, -oasdw, x2, y2);
|
||||
/* sides */
|
||||
ptc(.5, asd, -oasd, x1, y1);
|
||||
ptc(.5, asd, -oasd2, x1, y2);
|
||||
ptc(.4, asdw, -oasdw, x2, y1);
|
||||
ptc(.4, asdw, -oasdw, x2, y1);
|
||||
ptc(.5, asd, -oasd2, x1, y2);
|
||||
ptc(.4, asdw, -oasdw2, x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(bmch == 'o') {
|
||||
hyperpoint h = mappt(x+.5, y+.5, 1);
|
||||
h[2] += safe_alt(h) + 1;
|
||||
statues.emplace_back(statue{rgpushxto0(h), &shBall, 0xFFFFFFFF});
|
||||
}
|
||||
|
||||
if(bmch == 'x') {
|
||||
hyperpoint h = mappt(x+.5, y+.5, 1);
|
||||
statues.emplace_back(statue{rgpushxto0(h), &shGeostatue, 0xFFFFFFFF});
|
||||
}
|
||||
}
|
||||
cgi.finishshape();
|
||||
// println(hlog, shFloor[i].s, " to ", shFloor[i].e);
|
||||
}
|
||||
|
||||
cgi.extra_vertices();
|
||||
init_plan();
|
||||
}
|
||||
|
||||
/* convert ASCII map coordinates to Heisenberg coordinates */
|
||||
hyperpoint level::mappt(ld x, ld y, int s) {
|
||||
int tY = isize(map_tiles);
|
||||
int tX = isize(map_tiles[0]);
|
||||
x /= s;
|
||||
y /= s;
|
||||
hyperpoint h;
|
||||
h[0] = lerp(minx, maxx, x / tX);
|
||||
h[1] = lerp(miny, maxy, y / tY);
|
||||
if(flags & nrlPolar)
|
||||
tie(h[0], h[1]) = make_pair(h[1] * sin(h[0]), h[1] * cos(h[0]));
|
||||
h[2] = surface(h);
|
||||
h[3] = 1;
|
||||
return h;
|
||||
};
|
||||
|
||||
/*
|
||||
plan.emplace_back(start.where, hpxy(0, 1));
|
||||
plan.emplace_back(mappt(4.5, 10.5), hpxy(1, 1));
|
||||
plan.emplace_back(mappt(0.01, 3, 1), hpxy(0, -2));
|
||||
plan.emplace_back(mappt(2, 3.99, 1), hpxy(4, 0));
|
||||
plan.emplace_back(mappt(42, 3.99, 1), hpxy(4, 0));
|
||||
*/
|
||||
|
||||
void level::init_plan() {
|
||||
plan.emplace_back(start.where, hpxy(0, -1));
|
||||
plan.emplace_back(mappt(6.8, 10.2, 1), hpxy(1.5, -1.5));
|
||||
plan.emplace_back(mappt(10.5, 10.5, 1), hpxy(1.5, 1.5));
|
||||
plan.emplace_back(mappt(10.5, 4.5, 1), hpxy(-1.5, 1.5));
|
||||
plan.emplace_back(mappt(4.5, 4.5, 1), hpxy(-1.5, 1.5));
|
||||
plan.emplace_back(mappt(4.5, 2, 1), hpxy(1.5, 0.5));
|
||||
plan.emplace_back(mappt(10.5, 2, 1), hpxy(1.5, -0.5));
|
||||
plan.emplace_back(mappt(10.5, 4.5, 1), hpxy(-2, 0));
|
||||
plan.emplace_back(mappt(6.5, 6.5, 1), hpxy(-1.5, -1.5));
|
||||
plan.emplace_back(mappt(4.5, 10.5, 1), hpxy(1.5, -1.5));
|
||||
plan.emplace_back(mappt(10.5, 9.5, 1), hpxy(1.5, 1.5));
|
||||
/* plan.emplace_back(mappt(0.01, 3, 1), hpxy(0, -2));
|
||||
plan.emplace_back(mappt(2, 3.99, 1), hpxy(4, 0));
|
||||
plan.emplace_back(mappt(42, 3.99, 1), hpxy(4, 0));
|
||||
*/
|
||||
current = start;
|
||||
timer = 0;
|
||||
}
|
||||
|
||||
ld level::safe_alt(hyperpoint h, ld mul) {
|
||||
ld maxv = 0;
|
||||
for(int x: {-1, 0, 1})
|
||||
for(int y: {-1, 0, 1}) {
|
||||
hyperpoint c = sym_to_heis(point31(x*.5*scale, y*.5*scale, 0));
|
||||
hyperpoint j = rgpushxto0(h) * c;
|
||||
maxv = max(maxv, mul * (surface(j) - j[2]));
|
||||
}
|
||||
return maxv;
|
||||
}
|
||||
|
||||
void level::draw_level(const shiftmatrix& V) {
|
||||
if(false) for(int i=0; i<6; i++) {
|
||||
auto &poly = queuepoly(V * rgpushxto0(start.where) * cpush(2, 0.3 + 0.3 * sin(ticks / 500.)), shMini[i], 0xFFFF00FF);
|
||||
poly.tinf = &floor_texture_vertices[cgi.shFloor.id];
|
||||
ensure_vertex_number(*poly.tinf, poly.cnt);
|
||||
}
|
||||
|
||||
if(true) {
|
||||
auto& poly = queuepoly(V, shCastle, 0xC02020FF);
|
||||
poly.tinf = &castle_tinf;
|
||||
castle_tinf.texture_id = castle_texture->textureid;
|
||||
}
|
||||
|
||||
for(auto st: statues) queuepoly(V * st.T, *st.shape, st.color);
|
||||
|
||||
queuepoly(V, shField, 0xFFFF00FF);
|
||||
|
||||
auto& poly = queuepoly(V, shFloor, 0xFFFFFFFF); // 0xFFFFFFFF);
|
||||
poly.tinf = &uniltinf;
|
||||
uniltinf.texture_id = unil_texture->textureid;
|
||||
}
|
||||
|
||||
}
|
430
rogueviz/nilrider/levels.cpp
Normal file
430
rogueviz/nilrider/levels.cpp
Normal file
@ -0,0 +1,430 @@
|
||||
namespace nilrider {
|
||||
|
||||
ld f_heisenberg0(hyperpoint h) { return 0; }
|
||||
|
||||
ld rot_plane(hyperpoint h) {
|
||||
return h[0] * h[1] / 2;
|
||||
}
|
||||
|
||||
ld f_rot_well(hyperpoint h) {
|
||||
return h[0] * h[1] / 2 + h[0] * h[0] + h[1] * h[1];
|
||||
}
|
||||
|
||||
ld long_x(hyperpoint h) {
|
||||
return h[0] * h[1];
|
||||
}
|
||||
|
||||
ld geodesics_0(hyperpoint h) {
|
||||
ld r = hypot_d(2, h);
|
||||
ld phi = atan2(h[1], h[0]);
|
||||
|
||||
ld z = (phi / 2 / M_PI) * (M_PI * r * r + 2 * M_PI);
|
||||
return z + rot_plane(h);
|
||||
}
|
||||
|
||||
ld geodesics_at_4(hyperpoint h) {
|
||||
ld r = 4;
|
||||
ld phi = atan2(h[1], h[0]);
|
||||
|
||||
ld z = (phi / 2 / M_PI) * (M_PI * r * r + 2 * M_PI);
|
||||
return z + rot_plane(h);
|
||||
}
|
||||
|
||||
map<char, color_t> bcols = {
|
||||
{' ', 0xFF101010},
|
||||
{'W', 0xFFFFFFFF},
|
||||
{'g', 0xFF008000},
|
||||
{'h', 0xFF20A020},
|
||||
{'r', 0xFFFF4040},
|
||||
{'u', 0xFF4040FF},
|
||||
{'b', 0xFF804000},
|
||||
{'l', 0xFF0000C0},
|
||||
{'f', 0xFF603000},
|
||||
{'F', 0xFF804000},
|
||||
{'2', 0xFF404040},
|
||||
{'4', 0xFF808080},
|
||||
{'6', 0xFFC0C0C0},
|
||||
};
|
||||
|
||||
map<char, array<string, 16> > submaps = {
|
||||
{'o', {
|
||||
"WWWWWWWWWWWWWWWW",
|
||||
"W22222222222222W",
|
||||
"W22222666622222W",
|
||||
"W22266222266222W",
|
||||
"W22622222222622W",
|
||||
"W22622222222622W",
|
||||
"W26222222222262W",
|
||||
"W262222WW222262W",
|
||||
"W262222WW222262W",
|
||||
"W26222222222262W",
|
||||
"W22622222222622W",
|
||||
"W22622222222622W",
|
||||
"W22266222266222W",
|
||||
"W22222666622222W",
|
||||
"W22222222222222W",
|
||||
"WWWWWWWWWWWWWWWW"
|
||||
}},
|
||||
{'x', {
|
||||
"WWWWWWWWWWWWWWWW",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"W22222622622222W",
|
||||
"W222222rW222222W",
|
||||
"W222222Wr222222W",
|
||||
"W22222622622222W",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"W22222222222222W",
|
||||
"WWWWWWWWWWWWWWWW"
|
||||
}},
|
||||
{'b', {
|
||||
" ",
|
||||
" rrr rrr rrr rrr",
|
||||
" ",
|
||||
"rr rrr rrr rrr r",
|
||||
" ",
|
||||
" rrr rrr rrr rrr",
|
||||
" ",
|
||||
"rr rrr rrr rrr r",
|
||||
" ",
|
||||
" rrr rrr rrr rrr",
|
||||
" ",
|
||||
"rr rrr rrr rrr r",
|
||||
" ",
|
||||
" rrr rrr rrr rrr",
|
||||
" ",
|
||||
"rr rrr rrr rrr r",
|
||||
}},
|
||||
{'f', {
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
"FfFfFfFfFfFfFfFf",
|
||||
"fFfFfFfFfFfFfFfF",
|
||||
}},
|
||||
{'l', {
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
"llllllllllllllll",
|
||||
}},
|
||||
{'g', {
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
}},
|
||||
{'G', {
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghWhghg",
|
||||
"ghghrhghghWlWhgh",
|
||||
"hghrWrhghghWhghg",
|
||||
"ghghrhghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghlhghghghg",
|
||||
"ghghghlWlhghghgh",
|
||||
"hghghghlhghghghg",
|
||||
"ghghghghghghgrgh",
|
||||
"hghglghghghgrWrg",
|
||||
"ghglWlghghghgrgh",
|
||||
"hghglghghghghghg",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
}},
|
||||
{'r', {
|
||||
"rrrrrrrrrrrrrrru",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"ubbbbbbbbbbbbbbu",
|
||||
"urrrrrrrrrrrrrrr",
|
||||
}},
|
||||
{'*', {
|
||||
"WWWWWW WW WWWWWW",
|
||||
"W W",
|
||||
"W W",
|
||||
"W W",
|
||||
"W W",
|
||||
"W rr W",
|
||||
" rr ",
|
||||
"W r r W",
|
||||
"W r r W",
|
||||
" r r ",
|
||||
"W r r W",
|
||||
"W rrrrrrrr W",
|
||||
"W W",
|
||||
"W W",
|
||||
"W W",
|
||||
"WWWWWW WW WWWWWW",
|
||||
}},
|
||||
{'+', {
|
||||
"gh WW gh",
|
||||
"hg WW hg",
|
||||
" WW ",
|
||||
" ",
|
||||
" ",
|
||||
" WW ",
|
||||
" WW ",
|
||||
"WWW WWWWWW WWW",
|
||||
"WWW WWWWWW WWW",
|
||||
" WW ",
|
||||
" WW ",
|
||||
" ",
|
||||
" ",
|
||||
" WW ",
|
||||
"gh WW gh",
|
||||
"hg WW hg",
|
||||
}},
|
||||
{'-', {
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
"WWW WWWWWW WWW",
|
||||
"WWW WWWWWW WWW",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
"ghghghghghghghgh",
|
||||
"hghghghghghghghg",
|
||||
}},
|
||||
{'|', {
|
||||
"gh WW gh",
|
||||
"hg WW hg",
|
||||
"gh WW gh",
|
||||
"hg hg",
|
||||
"gh gh",
|
||||
"hg WW hg",
|
||||
"gh WW gh",
|
||||
"hg WW hg",
|
||||
"gh WW gh",
|
||||
"hg WW hg",
|
||||
"gh WW gh",
|
||||
"hg hg",
|
||||
"gh gh",
|
||||
"hg WW hg",
|
||||
"gh WW gh",
|
||||
"hg WW hg",
|
||||
}},
|
||||
};
|
||||
|
||||
level rotplane(
|
||||
"Trying to be horizontal", 'r', 0,
|
||||
"All the lines going through the center are horizontal.",
|
||||
-7.5*dft_block, 7.5*dft_block, 8.5*dft_block, -8.5*dft_block,
|
||||
{
|
||||
"ggggggggggggggg!",
|
||||
"ggggggfffgggggg!",
|
||||
"ggggggfffgggggg!",
|
||||
"gggg|ggggg|gggg!",
|
||||
"ggg-+-----+-ggg!",
|
||||
"gggg|ggggf|gggg!",
|
||||
"ggGg|g+ggg|grgG!",
|
||||
"gGgg|g|xgo|gggg!",
|
||||
"ggGg|g|ggg|grgg!",
|
||||
"gggg|g|ggg|gggg!",
|
||||
"gg--+-+---+--gg!",
|
||||
"gggg|ggggg|gggg!",
|
||||
"gggggggGGgggggg!",
|
||||
"ggggggggggggggg!",
|
||||
"ggggggggggggggg!",
|
||||
"!!!!!!!!!!!!!!!!"
|
||||
},
|
||||
6, 6,
|
||||
rot_plane
|
||||
);
|
||||
|
||||
level longtrack(
|
||||
"A Long Track", 'l', 0,
|
||||
"The main street is horizontal, as well as the lines orthogonal to it.",
|
||||
0*dft_block, +2.5*dft_block, 64*dft_block, -1.5*dft_block,
|
||||
{
|
||||
"gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg",
|
||||
"gggggggrgggggggrggggggggrGggggggggGGggggGGGgggggGGGGggggggggggGG",
|
||||
"g+------------------------------------------------------------+G",
|
||||
"gggggfffffggggggggggggggggggggggggggggggggggggggggggggggggggggGG"
|
||||
},
|
||||
0, 1,
|
||||
long_x
|
||||
);
|
||||
|
||||
level geodesical(
|
||||
"Roads are Geodesics", 'g', nrlPolar,
|
||||
"All the roads here are helical geodesics.",
|
||||
-45*degree, 3*dft_block, 225*degree, 0,
|
||||
// -8*dft_block, +8*dft_block, +8*dft_block, 0,
|
||||
{
|
||||
"ffffffffffffffff",
|
||||
"----------------",
|
||||
"----------------",
|
||||
"----------------",
|
||||
"----------------",
|
||||
"----------------",
|
||||
"----------------",
|
||||
"bbbbbbbbbbbbbbbb",
|
||||
},
|
||||
0, 6,
|
||||
geodesics_0
|
||||
);
|
||||
|
||||
level geodesical4(
|
||||
"Helical Geodesic", 's', nrlPolar,
|
||||
"The main road here is a helical geodesic. Orthogonal lines are horizontal.",
|
||||
-80*degree, 8.5*dft_block, 260*degree, 0.5*dft_block,
|
||||
// -8*dft_block, +8*dft_block, +8*dft_block, 0,
|
||||
{
|
||||
"!!!!!!!!!!!!!!!!",
|
||||
"ffffffffffffffff",
|
||||
"gggggggggggggggg",
|
||||
"ggGggggggggGgggg",
|
||||
"+--------------+",
|
||||
"gggggGggggGggggg",
|
||||
"gggGgggggGgggggg",
|
||||
"ffffffffffffffff",
|
||||
},
|
||||
0, 5,
|
||||
geodesics_at_4
|
||||
);
|
||||
|
||||
level heisenberg0(
|
||||
"Heisenberg Zero", 'z', 0,
|
||||
"This is the plane z=0 in the Heisenberg group model of Nil. The roads are x=0, y=0 axes.",
|
||||
-7.5*dft_block, 7.5*dft_block, 8.5*dft_block, -8.5*dft_block,
|
||||
{
|
||||
"ggggggg|ggggggg!",
|
||||
"grggggg|gggggrg!",
|
||||
"ggggggg|ggggggg!",
|
||||
"gggffgg|ggggggg!",
|
||||
"gggffgg|ggfrggg!",
|
||||
"ggggggg|gggggGg!",
|
||||
"ggggggg|ggggggg!",
|
||||
"-------+-------!",
|
||||
"ggggggg|ggggggg!",
|
||||
"gggGgog|ggggggg!",
|
||||
"ggggggg|ggrgrgg!",
|
||||
"gggGgGg|ggggggg!",
|
||||
"ggggggg|ggggggg!",
|
||||
"grggggg|gggggrg!",
|
||||
"ggggggg|ggggggg!",
|
||||
"!!!!!!!!!!!!!!!!"
|
||||
},
|
||||
8, 8,
|
||||
f_heisenberg0
|
||||
);
|
||||
|
||||
level rotwell(
|
||||
"Deep Well", 'd', 0,
|
||||
"Can you escape this well?",
|
||||
-7.5*dft_block, 7.5*dft_block, 8.5*dft_block, -8.5*dft_block,
|
||||
{
|
||||
"ggggggggggggggg!",
|
||||
"gogggggggggggog!",
|
||||
"ggggg--*--ggggg!",
|
||||
"gggg*ggggg*gggg!",
|
||||
"ggg*ggGfGgg*ggg!",
|
||||
"gg|ggfgggfgg|gg!",
|
||||
"gg|gGgggggGg|gg!",
|
||||
"gg*gfggxggfg*gg!",
|
||||
"gg|gGgggggGg|gg!",
|
||||
"gg|ggfgggfgg|gg!",
|
||||
"ggg*ggGfGgg*ggg!",
|
||||
"gggg*ggggg*gggg!",
|
||||
"ggggg--*--ggggg!",
|
||||
"gogggggggggggog!",
|
||||
"ggggggggggggggg!",
|
||||
"!!!!!!!!!!!!!!!!"
|
||||
},
|
||||
8, 8,
|
||||
f_rot_well
|
||||
);
|
||||
|
||||
level labyrinth(
|
||||
"Labyrinth", 'l', 0,
|
||||
"Go clockwise. The squares of this level have half of their usual length.",
|
||||
-7.5*dft_block/2, 7.5*dft_block/2, 8.5*dft_block/2, -8.5*dft_block/2,
|
||||
{
|
||||
"ogggrfffffffffo!",
|
||||
"g*ggrgggggggggg!",
|
||||
"ggggrgggggggggg!",
|
||||
"ggggrgggggggggg!",
|
||||
"ggggrgggrrggggg!",
|
||||
"ggggrgGGGrrgggg!",
|
||||
"ggggrGgggGrgggg!",
|
||||
"ggggrGgxgGrgggg!",
|
||||
"ggggrGgggGrgggg!",
|
||||
"ggggrrGGGrrgggg!",
|
||||
"gggggrrrrrggggg!",
|
||||
"ggggggggggggggg!",
|
||||
"ggggggggggggggg!",
|
||||
"ggggggggggggggg!",
|
||||
"offfffffffffffo!",
|
||||
"!!!!!!!!!!!!!!!!"
|
||||
},
|
||||
8, 8,
|
||||
rot_plane
|
||||
);
|
||||
|
||||
level *curlev = &rotplane;
|
||||
|
||||
vector<level*> all_levels = {
|
||||
&rotplane, &longtrack, &geodesical, &geodesical4, &heisenberg0, &rotwell, &labyrinth
|
||||
};
|
||||
|
||||
}
|
290
rogueviz/nilrider/nilrider.cpp
Normal file
290
rogueviz/nilrider/nilrider.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
#include "nilrider.h"
|
||||
#include "statues.cpp"
|
||||
#include "timestamp.cpp"
|
||||
#include "levels.cpp"
|
||||
#include "level.cpp"
|
||||
#include "planning.cpp"
|
||||
|
||||
namespace nilrider {
|
||||
|
||||
/** is the game paused? */
|
||||
bool paused = false;
|
||||
|
||||
bool planning_mode = false;
|
||||
bool view_simulation = false;
|
||||
int simulation_start_tick;
|
||||
|
||||
void frame() {
|
||||
if(planning_mode && !view_simulation) return;
|
||||
|
||||
shiftmatrix V = ggmatrix(cwt.at);
|
||||
|
||||
curlev->draw_level(V);
|
||||
|
||||
curlev->current.draw_unilcycle(V);
|
||||
}
|
||||
|
||||
bool turn(int delta) {
|
||||
if(planning_mode && !view_simulation) return false;
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
if(keystate[SDLK_RIGHT] && !paused) curlev->current.heading_angle -= delta / 1000.;
|
||||
if(keystate[SDLK_LEFT] && !paused) curlev->current.heading_angle += delta / 1000.;
|
||||
|
||||
if(keystate[SDLK_UP] && !paused) min_gfx_slope -= delta / 1000.;
|
||||
if(keystate[SDLK_DOWN] && !paused) min_gfx_slope += delta / 1000.;
|
||||
|
||||
curlev->current.heading_angle += mouseaim_x;
|
||||
min_gfx_slope += mouseaim_y;
|
||||
|
||||
#if CAP_VR
|
||||
if(vrhr::active()) {
|
||||
curlev->current.heading_angle += vrhr::vraim_x * delta / 400;
|
||||
min_gfx_slope -= vrhr::vraim_y * delta / 400;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(min_gfx_slope < -90*degree) min_gfx_slope = -90*degree;
|
||||
if(min_gfx_slope > +90*degree) min_gfx_slope = +90*degree;
|
||||
|
||||
if(!paused && !view_simulation) for(int i=0; i<delta; i++) {
|
||||
curlev->history.push_back(curlev->current);
|
||||
bool b = curlev->current.tick(curlev);
|
||||
if(b) timer += 1. / tps;
|
||||
else curlev->history.pop_back();
|
||||
}
|
||||
|
||||
if(!paused) curlev->current.centerview(curlev);
|
||||
return false;
|
||||
}
|
||||
|
||||
void main_menu();
|
||||
|
||||
void run() {
|
||||
cmode = sm::MAP;
|
||||
clearMessages();
|
||||
dialog::init();
|
||||
if(view_simulation && !paused) {
|
||||
int ttick = gmod(ticks - simulation_start_tick, isize(curlev->history));
|
||||
timer = ttick * 1. / tps;
|
||||
curlev->current = curlev->history[ttick];
|
||||
curlev->current.centerview(curlev);
|
||||
}
|
||||
gamescreen(0);
|
||||
if(planning_mode && !view_simulation) {
|
||||
curlev->draw_planning_screen();
|
||||
if(!holdmouse) {
|
||||
auto t0 = SDL_GetTicks();
|
||||
while(SDL_GetTicks() < t0 + 100) {
|
||||
if(!curlev->simulate()) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
curlev->current.draw_instruments(timer);
|
||||
|
||||
if(paused && !planning_mode) {
|
||||
displayButton(current_display->xcenter, current_display->ycenter, mousing ? XLAT("paused -- click to unpause") : XLAT("paused -- press p to continue"), 'p', 8);
|
||||
}
|
||||
|
||||
int x = vid.fsize;
|
||||
auto show_button = [&] (char c, string s, color_t col = dialog::dialogcolor) {
|
||||
if(displayButtonS(x, vid.yres - vid.fsize, s, col, 0, vid.fsize))
|
||||
getcstat = c;
|
||||
x += textwidth(vid.fsize, s) + vid.fsize;
|
||||
};
|
||||
|
||||
if(planning_mode && !view_simulation) {
|
||||
for(auto& b: buttons) show_button(b.first, b.second, planmode == b.first ? 0xFFD500 : dialog::dialogcolor);
|
||||
show_button('s', "simulation");
|
||||
}
|
||||
|
||||
if(planning_mode && view_simulation) {
|
||||
show_button('s', "return");
|
||||
show_button('p', "pause", paused ? 0xFF0000 : dialog::dialogcolor);
|
||||
}
|
||||
|
||||
if(!planning_mode) {
|
||||
show_button('p', "pause", paused ? 0xFF0000 : dialog::dialogcolor);
|
||||
}
|
||||
|
||||
show_button('v', "menu");
|
||||
|
||||
dialog::add_key_action('v', [] {
|
||||
paused = true;
|
||||
pushScreen(main_menu);
|
||||
});
|
||||
dialog::add_key_action('p', [] {
|
||||
paused = !paused;
|
||||
if(view_simulation && !paused)
|
||||
simulation_start_tick = ticks - timer * tps;
|
||||
});
|
||||
dialog::add_key_action('-', [] {
|
||||
paused = false;
|
||||
});
|
||||
dialog::add_key_action('b', [] {
|
||||
if(planning_mode)
|
||||
simulation_start_tick += 500;
|
||||
else {
|
||||
for(int i=0; i<500; i++) if(!curlev->history.empty()) curlev->history.pop_back();
|
||||
curlev->current = curlev->history.back();
|
||||
timer = isize(curlev->history) * 1. / tps;
|
||||
}
|
||||
});
|
||||
if(planning_mode) dialog::add_key_action('s', [] {
|
||||
view_simulation = !view_simulation;
|
||||
paused = false;
|
||||
simulation_start_tick = ticks;
|
||||
});
|
||||
dialog::display();
|
||||
|
||||
keyhandler = [] (int sym, int uni) {
|
||||
if(paused) handlePanning(sym, uni);
|
||||
if(planning_mode && !view_simulation && curlev->handle_planning(sym, uni)) return;
|
||||
dialog::handleNavigation(sym, uni);
|
||||
};
|
||||
}
|
||||
|
||||
int speedlimit = 0;
|
||||
vector<string> speedlimit_names = {"none", "yellow", "green", "full"};
|
||||
|
||||
void pick_level() {
|
||||
clearMessages();
|
||||
dialog::init(XLAT("select the track"), 0xC0C0FFFF, 150, 100);
|
||||
for(auto l: all_levels) {
|
||||
dialog::addItem(l->name, l->hotkey);
|
||||
dialog::add_action([l] {
|
||||
curlev = l;
|
||||
recompute_plan_transform = true;
|
||||
l->init();
|
||||
popScreen();
|
||||
});
|
||||
}
|
||||
dialog::addBreak(100);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
void pick_game() {
|
||||
clearMessages();
|
||||
dialog::init(XLAT("how do you want to play?"), 0xC0C0FFFF, 150, 100);
|
||||
dialog::addSelItem("selected track", curlev->name, 't');
|
||||
dialog::add_action_push(pick_level);
|
||||
dialog::addInfo(curlev->longdesc);
|
||||
dialog::addBreak(100);
|
||||
add_edit(speedlimit);
|
||||
add_edit(planning_mode);
|
||||
dialog::addBreak(100);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
void settings() {
|
||||
dialog::init(XLAT("settings"), 0xC0C0FFFF, 150, 100);
|
||||
dialog::addItem("RogueViz settings", 'r');
|
||||
dialog::add_key_action('r', [] {
|
||||
pushScreen(showSettings);
|
||||
});
|
||||
dialog::addBreak(100);
|
||||
dialog::display();
|
||||
dialog::addBack();
|
||||
}
|
||||
|
||||
reaction_t on_quit = [] { exit(0); };
|
||||
|
||||
void main_menu() {
|
||||
clearMessages();
|
||||
dialog::init(XLAT("Nil Rider"), 0xC0C0FFFF, 150, 100);
|
||||
|
||||
dialog::addItem("continue", 'c');
|
||||
dialog::add_action(popScreen);
|
||||
|
||||
if(!planning_mode) {
|
||||
dialog::addItem("restart", 'r');
|
||||
dialog::add_action([] {
|
||||
curlev->current = curlev->start;
|
||||
timer = 0;
|
||||
paused = false;
|
||||
popScreen();
|
||||
});
|
||||
|
||||
dialog::addItem("view the replay", 'v');
|
||||
dialog::add_action([] {
|
||||
});
|
||||
|
||||
dialog::addItem("save the replay", 'e');
|
||||
dialog::add_action([] {
|
||||
});
|
||||
}
|
||||
else {
|
||||
dialog::addItem("save this plan", 's');
|
||||
dialog::add_action([] {
|
||||
});
|
||||
}
|
||||
|
||||
dialog::addItem("change track or game settings", 't');
|
||||
dialog::add_action_push(pick_game);
|
||||
|
||||
dialog::addItem("change other settings", 'o');
|
||||
dialog::add_action_push(settings);
|
||||
|
||||
dialog::addItem("quit", 'q');
|
||||
dialog::add_action([] {
|
||||
on_quit();
|
||||
});
|
||||
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
bool on;
|
||||
|
||||
void initialize() {
|
||||
|
||||
check_cgi();
|
||||
cgi.prepare_shapes();
|
||||
|
||||
init_statues();
|
||||
|
||||
curlev->init();
|
||||
|
||||
param_enum(planning_mode, "nil_planning", "nil_planning", false)
|
||||
-> editable({{"manual", "control the unicycle manually"}, {"planning", "try to plan the optimal route!"}}, "game mode", 'p');
|
||||
|
||||
param_enum(speedlimit, "nil_speedlimit", "nil_speedlimit", 0)
|
||||
-> editable({
|
||||
{"no limit", "reach the goals as fast as you wan"},
|
||||
{"yellow", "your speed must be in the yellow zone to collect"},
|
||||
{"green", "your speed must be in the green zone to collect"},
|
||||
{"full", "you must fully stop to collect"}
|
||||
}, "speed limit", 's');
|
||||
|
||||
rv_hook(hooks_frame, 100, frame);
|
||||
rv_hook(shmup::hooks_turn, 100, turn);
|
||||
on = true;
|
||||
on_cleanup_or_next([] { on = false; });
|
||||
pushScreen(run);
|
||||
}
|
||||
|
||||
auto celldemo = arg::add3("-unilcycle", initialize) + arg::add3("-unilplan", [] { planning_mode = true; }) + arg::add3("-viewsim", [] { view_simulation = true; })
|
||||
+ arg::add3("-oqc", [] { on_quit = popScreenAll; })
|
||||
+ arg::add3("-fullsim", [] {
|
||||
/* for animations */
|
||||
popScreenAll();
|
||||
rv_hook(anims::hooks_anim, 100, [] {
|
||||
int ttick = ticks % isize(curlev->history);
|
||||
timer = ttick * 1. / tps;
|
||||
curlev->current = curlev->history[ttick];
|
||||
curlev->current.centerview(curlev);
|
||||
anims::moved();
|
||||
});
|
||||
}) + arg::add3("-unillevel", [] {
|
||||
arg::shift();
|
||||
for(auto l: all_levels) if(appears(l->name, arg::args())) curlev = l;
|
||||
if(on) curlev->init();
|
||||
})
|
||||
+ arg::add3("-simplemodel", [] {
|
||||
nisot::geodesic_movement = false;
|
||||
pmodel = mdPerspective;
|
||||
pconf.rotational_nil = 0;
|
||||
});
|
||||
|
||||
|
||||
}
|
130
rogueviz/nilrider/nilrider.h
Normal file
130
rogueviz/nilrider/nilrider.h
Normal file
@ -0,0 +1,130 @@
|
||||
#include "../rogueviz.h"
|
||||
|
||||
namespace nilrider {
|
||||
|
||||
using namespace rogueviz;
|
||||
|
||||
struct level;
|
||||
|
||||
struct timestamp {
|
||||
hyperpoint where; /**< the current position of the unicycle */
|
||||
ld heading_angle; /**< the current heading angle */
|
||||
ld vel; /**< the current velocity in units per second */
|
||||
ld circpos; /**< controls the wheel graphics */
|
||||
ld slope; /**< the current slope */
|
||||
ld t; /**< planning spline parameter */
|
||||
bool tick(level*);/**< one tick of the simulation -- returns false if the unicycle has stopped or crashed */
|
||||
void centerview(level*);
|
||||
void draw_unilcycle(const shiftmatrix&);
|
||||
void draw_instruments(ld t);
|
||||
ld energy_in_squares();
|
||||
};
|
||||
|
||||
struct planpoint {
|
||||
hyperpoint at;
|
||||
hyperpoint vel;
|
||||
planpoint(hyperpoint a, hyperpoint v): at(a), vel(v) {};
|
||||
};
|
||||
|
||||
constexpr flagtype nrlPolar = Flag(1);
|
||||
|
||||
struct statue {
|
||||
transmatrix T;
|
||||
hpcshape *shape;
|
||||
color_t color;
|
||||
};
|
||||
|
||||
struct level {
|
||||
string name;
|
||||
char hotkey;
|
||||
string longdesc;
|
||||
flagtype flags;
|
||||
ld minx, miny, maxx, maxy;
|
||||
vector<string> map_tiles;
|
||||
ld startx, starty;
|
||||
ld scale;
|
||||
std::function<ld(hyperpoint h)> surface;
|
||||
|
||||
bool initialized;
|
||||
|
||||
level(string name, char hotkey, flagtype flags, string longdesc, ld minx, ld miny, ld maxx, ld maxy, const vector<string>& mt, ld sx, ld sy, const std::function<ld(hyperpoint h)>& surf) :
|
||||
name(name), hotkey(hotkey), longdesc(longdesc), flags(flags), minx(minx), miny(miny), maxx(maxx), maxy(maxy), map_tiles(mt), startx(sx), starty(sy), surface(surf) { initialized = false; }
|
||||
|
||||
ld real_minx, real_miny, real_maxx, real_maxy;
|
||||
|
||||
/* data */
|
||||
hpcshape shFloor; /**< the 3D model of floor */
|
||||
hpcshape shPlanFloor; /**< the 3D model of floor for planning */
|
||||
hpcshape shField; /**< the 3D model of the 'field' */
|
||||
hpcshape shCastle; /**< the 3D model of the 'castle' */
|
||||
|
||||
vector<statue> statues;
|
||||
|
||||
/** the texture data used for the ground */
|
||||
texture::texture_data *unil_texture;
|
||||
|
||||
/** the texture used for the ground */
|
||||
basic_textureinfo uniltinf;
|
||||
|
||||
/** the texture used for the ground */
|
||||
basic_textureinfo castle_tinf;
|
||||
|
||||
/** starting timestamp */
|
||||
timestamp start;
|
||||
|
||||
/** current timestamp */
|
||||
timestamp current;
|
||||
|
||||
/** initialize textures and start */
|
||||
void init();
|
||||
|
||||
vector<timestamp> history;
|
||||
|
||||
/** plan for the planning mode */
|
||||
vector<planpoint> plan;
|
||||
void init_plan();
|
||||
bool simulate();
|
||||
void draw_planning_screen();
|
||||
void draw_level(const shiftmatrix& V);
|
||||
shiftmatrix plan_transform;
|
||||
|
||||
hyperpoint get_spline(ld t);
|
||||
hyperpoint mappt(ld x, ld y, int s);
|
||||
ld safe_alt(hyperpoint h, ld mul = 1);
|
||||
void compute_plan_transform();
|
||||
bool handle_planning(int sym, int uni);
|
||||
};
|
||||
|
||||
/** ticks per second */
|
||||
inline const ld tps = 1000;
|
||||
|
||||
/** wheel radius */
|
||||
inline ld whrad = 0.05;
|
||||
|
||||
/** epsilon used to measure slope */
|
||||
inline ld slope_eps = 0.01;
|
||||
|
||||
/** gravity acceleration constant, in units per second squared */
|
||||
inline ld gravity = 1 / 16.;
|
||||
|
||||
/** the distance of camera from the wheel */
|
||||
inline ld whdist = 0.5;
|
||||
|
||||
/** minimum slope for rendering */
|
||||
inline ld min_gfx_slope = +M_PI/2;
|
||||
|
||||
/** current slope for rendering */
|
||||
inline ld gfx_slope = 0;
|
||||
|
||||
/** the timer */
|
||||
inline ld timer = 0;
|
||||
|
||||
/** default block unit */
|
||||
inline double dft_block = 1;
|
||||
|
||||
extern map<char, color_t> bcols;
|
||||
extern map<char, array<string, 16> > submaps;
|
||||
|
||||
hyperpoint sym_to_heis(hyperpoint H);
|
||||
|
||||
}
|
287
rogueviz/nilrider/planning.cpp
Normal file
287
rogueviz/nilrider/planning.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
namespace nilrider {
|
||||
|
||||
hyperpoint get_spline(ld t);
|
||||
|
||||
bool level::simulate() {
|
||||
if(history.empty())
|
||||
history.push_back(start);
|
||||
auto at = history.back();
|
||||
|
||||
if(at.t >= isize(plan) - 1.001) return false;
|
||||
|
||||
ld goal_t;
|
||||
|
||||
if(1) {
|
||||
int steps = 20;
|
||||
ld min_t, max_t;
|
||||
|
||||
if(isize(history) == 1) {
|
||||
steps = 60;
|
||||
min_t = at.t;
|
||||
max_t = at.t + 0.5;
|
||||
}
|
||||
else {
|
||||
ld ldiff = history.back().t - history[history.size() - 2].t;
|
||||
min_t = at.t;
|
||||
max_t = min<ld>(at.t + ldiff + .1, isize(plan)-1);
|
||||
}
|
||||
|
||||
auto f = [&] (ld t) {
|
||||
hyperpoint h = get_spline(t);
|
||||
auto copy = at;
|
||||
copy.heading_angle = atan2(h[1] - at.where[1], h[0] - at.where[0]);
|
||||
copy.tick(this);
|
||||
return sqhypot_d(2, copy.where-h);
|
||||
};
|
||||
|
||||
string seq = "";
|
||||
|
||||
for(int i=0; i<steps; i++) {
|
||||
ld t1 = min_t * .6 + max_t * .4;
|
||||
ld t2 = min_t * .4 + max_t * .6;
|
||||
auto e1 = f(t1);
|
||||
auto e2 = f(t2);
|
||||
if(e1 < e2) max_t = t2, seq += "B";
|
||||
else min_t = t1, seq += "A";
|
||||
}
|
||||
|
||||
goal_t = (min_t + max_t) / 2;
|
||||
}
|
||||
|
||||
hyperpoint h = get_spline(goal_t);
|
||||
at.heading_angle = atan2(h[1] - at.where[1], h[0] - at.where[0]);
|
||||
history.back() = at;
|
||||
|
||||
if(!at.tick(this)) return false;
|
||||
at.t = goal_t;
|
||||
history.push_back(at);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hyperpoint level::get_spline(ld t) {
|
||||
int i = t;
|
||||
if(i == isize(plan) - 1) return plan.back().at;
|
||||
ld tf = t - i;
|
||||
return plan[i].at * (1-tf) * (1-tf) * (1+2*tf) + plan[i+1].at * (tf*tf * (3-2*tf)) + plan[i].vel * tf * (1-tf) * (1-tf) - plan[i+1].vel * tf * tf * (1-tf);
|
||||
}
|
||||
|
||||
hyperpoint mousept;
|
||||
ld box;
|
||||
ld closest_t;
|
||||
|
||||
char planmode = 'p';
|
||||
vector<pair<char, string> > buttons = {
|
||||
{'p', "pan"}, {'a', "add"}, {'m', "move"}, {'i', "insert"}, {'d', "delete"}
|
||||
};
|
||||
|
||||
bool recompute_plan_transform = true;
|
||||
|
||||
void level::compute_plan_transform() {
|
||||
dynamicval<eModel> pm(pmodel, mdDisk);
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
dynamicval<bool> ga(vid.always3, false);
|
||||
dynamicval<geometryinfo1> gi(ginf[gEuclid].g, giEuclid2);
|
||||
auto& cd = current_display;
|
||||
auto sId = shiftless(Id);
|
||||
ld pix = 1 / (2 * cgi.hcrossf / cgi.crossf);
|
||||
ld scale_x = (vid.xres - 2 * vid.fsize) / abs(real_maxx-real_minx);
|
||||
ld scale_y = (vid.yres - 2 * vid.fsize) / abs(real_maxy-real_miny);
|
||||
ld scale = min(scale_x, scale_y);
|
||||
plan_transform = sId * atscreenpos(cd->xcenter, cd->ycenter, pix * scale) * eupush(-(real_minx+real_maxx)/2, (real_miny+real_maxy)/2) * MirrorY;
|
||||
}
|
||||
|
||||
void level::draw_planning_screen() {
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
dynamicval<eModel> pm(pmodel, mdDisk);
|
||||
dynamicval<bool> ga(vid.always3, false);
|
||||
dynamicval<geometryinfo1> gi(ginf[gEuclid].g, giEuclid2);
|
||||
initquickqueue();
|
||||
|
||||
if(recompute_plan_transform) {
|
||||
compute_plan_transform();
|
||||
recompute_plan_transform = false;
|
||||
}
|
||||
|
||||
auto& T = plan_transform;
|
||||
|
||||
auto scr_to_map = [&] (hyperpoint h) {
|
||||
transmatrix mousef = inverse(unshift(T)) * atscreenpos(h[0], h[1], 1);
|
||||
h = mousef * C0;
|
||||
h /= h[2];
|
||||
return h;
|
||||
};
|
||||
|
||||
mousept = scr_to_map(hpxy(mousex, mousey));
|
||||
|
||||
box = scr_to_map(hpxy(mousex + 5, mousey))[0] - mousept[0];
|
||||
|
||||
/* draw the map */
|
||||
auto& p = queuepolyat(T, shPlanFloor, 0xFFFFFFFF, PPR::FLOOR);
|
||||
p.tinf = &uniltinf;
|
||||
uniltinf.texture_id = unil_texture->textureid;
|
||||
|
||||
auto draw_sq = [&] (hyperpoint h, color_t col, PPR prio) {
|
||||
curvepoint(hpxy(h[0]+box, h[1]+box));
|
||||
curvepoint(hpxy(h[0]+box, h[1]-box));
|
||||
curvepoint(hpxy(h[0]-box, h[1]-box));
|
||||
curvepoint(hpxy(h[0]-box, h[1]+box));
|
||||
curvepoint(hpxy(h[0]+box, h[1]+box));
|
||||
queuecurve(T, 0xFF, col, prio);
|
||||
};
|
||||
|
||||
auto draw_line = [&] (hyperpoint h1, hyperpoint h2, color_t col, PPR prio) {
|
||||
curvepoint(hpxy(h1[0], h1[1]));
|
||||
curvepoint(hpxy(h2[0], h2[1]));
|
||||
queuecurve(T, col, 0, prio);
|
||||
};
|
||||
|
||||
/* draw the plan */
|
||||
for(auto& pp: plan) {
|
||||
draw_sq(pp.at - pp.vel, 0xFF8080FF, PPR::ITEM);
|
||||
draw_sq(pp.at + pp.vel, 0x80FF80FF, PPR::ITEM);
|
||||
draw_sq(pp.at, 0xFFFF00FF, PPR::ITEM);
|
||||
draw_line(pp.at - pp.vel, pp.at + pp.vel, 0x80, PPR::BFLOOR);
|
||||
}
|
||||
|
||||
bool after = false;
|
||||
|
||||
if(history.empty()) history.push_back(start);
|
||||
|
||||
closest_t = history.back().t;
|
||||
ld closest_dist = box * 2;
|
||||
|
||||
vid.linewidth *= 3;
|
||||
int ps = isize(plan);
|
||||
for(int t=0; t<=100*(ps-1); t++) {
|
||||
ld tt = t / 100.;
|
||||
if(tt > history.back().t && !after) {
|
||||
queuecurve(T, 0xFFFFFFC0, 0, PPR::LIZEYE);
|
||||
after = true;
|
||||
}
|
||||
hyperpoint h = get_spline(tt);
|
||||
curvepoint(hpxy(h[0], h[1]));
|
||||
ld dist = sqhypot_d(2, h - mousept);
|
||||
if(dist < closest_dist) closest_dist = dist, closest_t = tt;
|
||||
}
|
||||
queuecurve(T, after ? 0xFF8080C0 : 0xFFFFFFC0, 0, PPR::LIZEYE);
|
||||
vid.linewidth /= 3;
|
||||
|
||||
if(!history.empty()) {
|
||||
int mint = 0, maxt = isize(history)-1;
|
||||
while(mint < maxt) {
|
||||
int t = (mint + maxt + 1) / 2;
|
||||
if(history[t].t > closest_t) maxt = t-1;
|
||||
else mint = t;
|
||||
}
|
||||
|
||||
current = history[mint];
|
||||
timer = mint * 1. / tps;
|
||||
}
|
||||
|
||||
draw_sq(get_spline(closest_t), 0x8080FFFF, PPR::ITEM);
|
||||
draw_sq(current.where, 0xFF8000FF, PPR::ITEM);
|
||||
draw_sq(mousept, 0x8080FFFF, PPR::ITEM);
|
||||
|
||||
quickqueue();
|
||||
|
||||
glflush();
|
||||
getcstat = '-';
|
||||
}
|
||||
|
||||
hyperpoint mousept_drag;
|
||||
|
||||
int move_id = -1, move_dir = 0;
|
||||
|
||||
bool level::handle_planning(int sym, int uni) {
|
||||
if(sym == PSEUDOKEY_WHEELUP || sym == SDLK_PAGEUP) {
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
plan_transform.T = atscreenpos(mousex, mousey, 1.2) * inverse(atscreenpos(mousex, mousey, 1)) * plan_transform.T;
|
||||
return true;
|
||||
}
|
||||
if(sym == PSEUDOKEY_WHEELDOWN || sym == SDLK_PAGEDOWN) {
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
plan_transform.T = atscreenpos(mousex, mousey, 1) * inverse(atscreenpos(mousex, mousey, 1.2)) * plan_transform.T;
|
||||
return true;
|
||||
}
|
||||
for(auto& b: buttons) if(uni == b.first) { planmode = uni; return true; }
|
||||
auto clean_history_to = [&] (int i) {
|
||||
while(history.size() > 1 && history.back().t > i) history.pop_back();
|
||||
};
|
||||
switch(planmode) {
|
||||
case 'p':
|
||||
if(uni == '-' && !holdmouse) {
|
||||
mousept_drag = mousept;
|
||||
holdmouse = true;
|
||||
return true;
|
||||
}
|
||||
else if(uni == '-' && holdmouse) {
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
plan_transform.T = plan_transform.T * eupush(mousept-mousept_drag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case 'a':
|
||||
if(uni == '-' && !holdmouse) {
|
||||
plan.emplace_back(mousept, hpxy(0, 0));
|
||||
holdmouse = true;
|
||||
return true;
|
||||
}
|
||||
else if(uni == '-' && holdmouse) {
|
||||
plan.back().vel = mousept - plan.back().at;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case 'm': case 'd': {
|
||||
if(!holdmouse) {
|
||||
ld len = box * 2;
|
||||
move_id = -1;
|
||||
auto check = [&] (hyperpoint h, int id, int dir) {
|
||||
ld d = sqhypot_d(2, h - mousept);
|
||||
if(d < len) { len = d; move_id = id; move_dir = dir; }
|
||||
};
|
||||
int next_id = 0;
|
||||
for(auto p: plan) {
|
||||
check(p.at, next_id, 0);
|
||||
check(p.at + p.vel, next_id, 1);
|
||||
check(p.at - p.vel, next_id, -1);
|
||||
next_id++;
|
||||
}
|
||||
}
|
||||
if(uni == '-' && planmode == 'd' && move_id > 0) {
|
||||
plan.erase(plan.begin() + move_id);
|
||||
clean_history_to(move_id - 1);
|
||||
return true;
|
||||
}
|
||||
else if(uni == '-' && planmode == 'm' && (move_id + move_dir * move_dir > 0) && !holdmouse) {
|
||||
holdmouse = true;
|
||||
println(hlog, "moving ", tie(move_id, move_dir));
|
||||
return true;
|
||||
}
|
||||
else if(uni == '-' && planmode == 'm' && holdmouse) {
|
||||
println(hlog, "moving further ", tie(move_id, move_dir));
|
||||
if(move_dir == 0) plan[move_id].at = mousept;
|
||||
else plan[move_id].vel = move_dir * (mousept - plan[move_id].at);
|
||||
println(hlog, "set to ", tie(plan[move_id].at, plan[move_id].vel));
|
||||
clean_history_to(move_id - 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 'i': {
|
||||
if(uni == '-') {
|
||||
planpoint pt(C0, C0);
|
||||
pt.at = get_spline(closest_t);
|
||||
pt.vel = (get_spline(closest_t + 1e-3) - pt.at) / 1e-3;
|
||||
plan.insert(plan.begin() + int(ceil(closest_t)), pt);
|
||||
clean_history_to(int(closest_t));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
148
rogueviz/nilrider/statues.cpp
Normal file
148
rogueviz/nilrider/statues.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
namespace hr {
|
||||
namespace bricks {
|
||||
|
||||
void draw_ro();
|
||||
|
||||
extern void build(bool in_pair);
|
||||
|
||||
struct brick {
|
||||
euc::coord co;
|
||||
color_t col;
|
||||
int walls;
|
||||
hyperpoint location;
|
||||
hpcshape shRotWall[6];
|
||||
};
|
||||
|
||||
extern vector<brick> bricks;
|
||||
}
|
||||
}
|
||||
|
||||
namespace nilrider {
|
||||
|
||||
hpcshape shMini[6];
|
||||
|
||||
void create_minitriangle() {
|
||||
using namespace bricks;
|
||||
hyperpoint ctr = Hypc;
|
||||
for(auto& b: bricks::bricks) ctr += b.location;
|
||||
ctr /= ctr[3];
|
||||
transmatrix B = gpushxto0(ctr);
|
||||
|
||||
ld radius = 0;
|
||||
ld sca = .18;
|
||||
|
||||
for(int f=0; f<6; f++) {
|
||||
cgi.bshape(shMini[f], PPR::WALL);
|
||||
shMini[f].flags |= POLY_TRIANGLES;
|
||||
|
||||
for(auto& b: bricks::bricks) {
|
||||
transmatrix V = eupush(b.location);
|
||||
|
||||
int which = b.walls;
|
||||
if(!((1<<f) & which)) continue;
|
||||
|
||||
auto& sh = b.shRotWall[f];
|
||||
for(int i=sh.s; i<sh.e; i++) {
|
||||
hyperpoint p = B * V * cgi.hpc[i];
|
||||
p[0] *= sca;
|
||||
p[1] *= sca;
|
||||
p[2] *= sca*sca;
|
||||
cgi.hpcpush(p);
|
||||
radius = max(radius, sqhypot_d(2, p));
|
||||
}
|
||||
}
|
||||
cgi.finishshape();
|
||||
}
|
||||
cgi.extra_vertices();
|
||||
println(hlog, "radius = ", radius);
|
||||
}
|
||||
|
||||
/** the texture data used for the castle walls */
|
||||
texture::texture_data *castle_texture;
|
||||
|
||||
void create_castle() {
|
||||
if(!castle_texture) {
|
||||
castle_texture = new texture::texture_data;
|
||||
auto& tex = *castle_texture;
|
||||
tex.twidth = 16;
|
||||
tex.theight = 16;
|
||||
tex.stretched = false;
|
||||
tex.strx = tex.tx;
|
||||
tex.stry = tex.ty;
|
||||
tex.base_x = 0;
|
||||
tex.base_y = 0;
|
||||
tex.whitetexture();
|
||||
for(int y=0; y<16; y++)
|
||||
for(int x=0; x<16; x++)
|
||||
tex.get_texture_pixel(x, y) = bcols[submaps['b'][y][x]];
|
||||
tex.loadTextureGL();
|
||||
}
|
||||
|
||||
bricks::build(false);
|
||||
create_minitriangle();
|
||||
}
|
||||
|
||||
hpcshape shBall;
|
||||
|
||||
bool open_grid(int x, int y) {
|
||||
return among(y&3, 1, 2) || among(x&3, 0, 3);
|
||||
}
|
||||
|
||||
bool closed_grid(int x, int y) {
|
||||
return among(y&3, 0, 3) || among(x&3, 0, 3);
|
||||
}
|
||||
|
||||
template<class T1, class T2> void add_statue(const T1& grid, const T2& f) {
|
||||
auto pt = [&] (int x, int y) {
|
||||
ld x1 = x * M_PI / 16.;
|
||||
ld y1 = y * M_PI / 32.;
|
||||
cgi.hpcpush(f(x1,y1));
|
||||
};
|
||||
for(int y=-16; y<16; y++)
|
||||
for(int x=-16; x<16; x++) if(grid(x,y)) {
|
||||
pt(x, y);
|
||||
pt(x, y+1);
|
||||
pt(x+1, y);
|
||||
pt(x+1, y);
|
||||
pt(x, y+1);
|
||||
pt(x+1, y+1);
|
||||
}
|
||||
}
|
||||
|
||||
hpcshape shGeostatue;
|
||||
|
||||
void init_statues() {
|
||||
create_minitriangle();
|
||||
create_castle();
|
||||
|
||||
cgi.bshape(shBall, PPR::WALL);
|
||||
shBall.flags |= POLY_TRIANGLES;
|
||||
add_statue(open_grid, [] (ld lon, ld lat) { return direct_exp(point3(cos(lat)*sin(lon)*.5, cos(lat)*cos(lon)*.5, sin(lat)*.5)); });
|
||||
cgi.finishshape();
|
||||
cgi.extra_vertices();
|
||||
cgi.add_texture(shBall);
|
||||
|
||||
cgi.bshape(shGeostatue, PPR::WALL);
|
||||
shGeostatue.flags |= POLY_TRIANGLES;
|
||||
for(int i=0; i<8; i++) {
|
||||
hyperpoint z = point31(0, 1e-6, 8);
|
||||
hyperpoint ih = inverse_exp(shiftless(z));
|
||||
ih = spin(i * 45 * degree) * ih;
|
||||
add_statue(closed_grid, [&] (ld lon, ld lat) {
|
||||
lat = lat * .75;
|
||||
hyperpoint h = direct_exp(ih * (.5 + lat / M_PI));
|
||||
return rgpushxto0(h) * sym_to_heis(point31(sin(lon)*.1, cos(lon)*.1, 0));
|
||||
});
|
||||
}
|
||||
cgi.finishshape();
|
||||
cgi.extra_vertices();
|
||||
cgi.add_texture(shGeostatue);
|
||||
|
||||
for(ld z: vector<ld> {M_PI/2+1e-2, M_PI+1e-2, M_PI*2+1e-2, 7, 10})
|
||||
for(hyperpoint h: {point31(0, 0, z), point31(1e-3, 0, z), point31(1e-6, 0, z), point31(0, 1e-6, z)}) {
|
||||
hyperpoint i = inverse_exp(shiftless(h));
|
||||
println(hlog, i, " @ ", hypot_d(3, i));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
244
rogueviz/nilrider/timestamp.cpp
Normal file
244
rogueviz/nilrider/timestamp.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
namespace nilrider {
|
||||
|
||||
ld timestamp::energy_in_squares() { return vel * vel / (2 * gravity); }
|
||||
|
||||
/** convert rotationally symmetric to Heisenberg model */
|
||||
EX hyperpoint sym_to_heis(hyperpoint H) {
|
||||
if(nil) {
|
||||
H[2] += H[0] * H[1] / 2;
|
||||
}
|
||||
return H;
|
||||
}
|
||||
|
||||
void timestamp::draw_unilcycle(const shiftmatrix& V) {
|
||||
const int points = 60;
|
||||
const int spoke_each = 5;
|
||||
hyperpoint whpoint[points+1];
|
||||
|
||||
transmatrix Ta = cspin(0, 1, -heading_angle);
|
||||
transmatrix Tb = cspin(0, 2, -slope);
|
||||
|
||||
hyperpoint base = Ta * Tb * point31(0, 0, whrad);
|
||||
|
||||
for(int a=0; a<points; a++) {
|
||||
ld beta = 360 * degree * a / points + circpos;
|
||||
whpoint[a] = base + Ta * point3(whrad*sin(beta),0,whrad*cos(beta));
|
||||
}
|
||||
whpoint[points] = whpoint[0];
|
||||
|
||||
hyperpoint hub[2];
|
||||
const ld hublen = whrad / 2;
|
||||
for(int a=0; a<2; a++) {
|
||||
hub[a] = base + Ta * point3(0, hublen*(a?1:-1), 0);
|
||||
}
|
||||
|
||||
for(int a=0; a<points; a+=spoke_each) for(int b=0; b<2; b++) {
|
||||
curvepoint(hub[b]);
|
||||
for(int b=0; b<=spoke_each; b++)
|
||||
curvepoint(whpoint[a+b]);
|
||||
curvepoint(hub[b]);
|
||||
if(a&1)
|
||||
queuecurve(V * rgpushxto0(where), 0xFFFFFFFF, 0xFFFF40FF, PPR::WALL);
|
||||
else
|
||||
queuecurve(V * rgpushxto0(where), 0xFFFFFFFF, 0xFF4040FF, PPR::WALL);
|
||||
}
|
||||
|
||||
if(1) {
|
||||
curvepoint(base + Ta * point3(hublen, 0, whrad+hublen));
|
||||
curvepoint(base + Ta * point3(0, -hublen, whrad+hublen));
|
||||
curvepoint(base + Ta * point3(0, +hublen, whrad+hublen));
|
||||
curvepoint(base + Ta * point3(hublen, 0, whrad+hublen));
|
||||
queuecurve(V * rgpushxto0(where), 0xFF, 0x303030FF, PPR::WALL);
|
||||
|
||||
for(auto& y: {hublen, -hublen}) {
|
||||
curvepoint(base + Ta * point3(hublen * .1, -y, 0));
|
||||
curvepoint(base + Ta * point3(hublen * -.1, -y, 0));
|
||||
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen / 2));
|
||||
curvepoint(base + Ta * point3(hublen * .1, 0, whrad + hublen / 2));
|
||||
curvepoint(base + Ta * point3(hublen * .1, -y, 0));
|
||||
queuecurve(V * rgpushxto0(where), 0xFF, 0x303030FF, PPR::WALL);
|
||||
|
||||
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen / 2));
|
||||
curvepoint(base + Ta * point3(hublen * .1, 0, whrad + hublen / 2));
|
||||
curvepoint(base + Ta * point3(hublen * .1, 0, whrad + hublen));
|
||||
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen));
|
||||
curvepoint(base + Ta * point3(hublen * -.1, 0, whrad + hublen / 2));
|
||||
queuecurve(V * rgpushxto0(where), 0xFF, 0x303030FF, PPR::WALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool tick_debug = false;
|
||||
|
||||
bool timestamp::tick(level *lev) {
|
||||
|
||||
const ld eps = slope_eps;
|
||||
|
||||
hyperpoint wnext = where;
|
||||
wnext[0] += cos(heading_angle) * eps;
|
||||
wnext[1] += sin(heading_angle) * eps;
|
||||
wnext[2] = lev->surface(wnext);
|
||||
|
||||
wnext = gpushxto0(where) * wnext;
|
||||
slope = atan(wnext[2] / eps);
|
||||
|
||||
auto ovel = vel;
|
||||
|
||||
vel -= sin(slope) * gravity / tps;
|
||||
if(vel < 0) {
|
||||
vel = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto mvel = (vel + ovel) / 2;
|
||||
where[0] += cos(heading_angle) * mvel * cos(slope) / tps;
|
||||
where[1] += sin(heading_angle) * mvel * cos(slope) / tps;
|
||||
where[2] = lev->surface(where);
|
||||
circpos += mvel / whrad / tps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void timestamp::centerview(level *lev) {
|
||||
// static bool once = false; if(once) return; once = true;
|
||||
auto w = where;
|
||||
w[2] += 0.2 * lev->scale;
|
||||
hyperpoint front = rgpushxto0(w) * sym_to_heis(hyperpoint(1e-3 * cos(heading_angle), 1e-3*sin(heading_angle), 0, 1));
|
||||
hyperpoint up = w; up[2] += 1e-3;
|
||||
|
||||
set_view(w, front, up);
|
||||
|
||||
transmatrix T = View;
|
||||
|
||||
ld gfx_slope = binsearch(-90*degree, min(slope, min_gfx_slope), [&] (ld slope) {
|
||||
View = T;
|
||||
rotate_view(cspin(1, 2, slope));
|
||||
for(int i=0; i<8; i++) {
|
||||
shift_view(ztangent(whdist * lev->scale / 8.));
|
||||
hyperpoint p = inverse(View) * C0;
|
||||
ld room = p[2] - lev->surface(p);
|
||||
if(room < .1 * lev->scale) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
View = T;
|
||||
rotate_view(cspin(1, 2, gfx_slope));
|
||||
shift_view(ztangent(whdist * lev->scale));
|
||||
centerover = cwt.at;
|
||||
playermoved = false;
|
||||
}
|
||||
|
||||
void timestamp::draw_instruments(ld t) {
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
dynamicval<eModel> pm(pmodel, mdDisk);
|
||||
dynamicval<bool> ga(vid.always3, false);
|
||||
dynamicval<geometryinfo1> gi(ginf[gEuclid].g, giEuclid2);
|
||||
initquickqueue();
|
||||
|
||||
ld rad = 40;
|
||||
|
||||
ld cx = rad * 2;
|
||||
ld cy = rad * 2;
|
||||
|
||||
auto sId = shiftless(Id);
|
||||
|
||||
ld pix = 1 / (2 * cgi.hcrossf / cgi.crossf);
|
||||
|
||||
// clinometer
|
||||
|
||||
cx += rad * 1.2;
|
||||
|
||||
for(int i=-90; i<=90; i++)
|
||||
curvepoint(atscreenpos(cx+cos(i * degree)*rad, cy-sin(i*degree)*rad, 1) * C0);
|
||||
|
||||
curvepoint(atscreenpos(cx, cy+rad, 1) * C0);
|
||||
queuecurve(sId, 0x000000FF, 0xFFFFFF80, PPR::ZERO);
|
||||
|
||||
curvepoint(hpxy(0, 0));
|
||||
curvepoint(hpxy(rad, 0));
|
||||
/* curvepoint(hpxy(rad/4, 0));
|
||||
curvepoint(hpxy(0, rad));
|
||||
curvepoint(hpxy(-rad/4, 0));
|
||||
curvepoint(hpxy(rad/4, 0)); */
|
||||
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(min_gfx_slope), 0x40, 0x40, PPR::ZERO);
|
||||
|
||||
curvepoint(hpxy(rad/4, 0));
|
||||
curvepoint(hpxy(0, rad));
|
||||
curvepoint(hpxy(-rad/4, 0));
|
||||
curvepoint(hpxy(rad/4, 0));
|
||||
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(90 * degree + slope), 0xFF, 0x40C040FF, PPR::ZERO);
|
||||
|
||||
// compass
|
||||
|
||||
cx -= rad * 1.2;
|
||||
|
||||
for(int i=0; i<360; i++)
|
||||
curvepoint(atscreenpos(cx-cos(i * degree)*rad, cy-sin(i*degree)*rad, 1) * C0);
|
||||
|
||||
queuecurve(sId, 0x000000FF, 0xFFFFFF80, PPR::ZERO);
|
||||
|
||||
for(int d: {1}) {
|
||||
|
||||
// d == +1: direction arrow
|
||||
// d == -1: compass
|
||||
|
||||
curvepoint(hpxy(rad/4, 0));
|
||||
curvepoint(hpxy(0, rad));
|
||||
curvepoint(hpxy(-rad/4, 0));
|
||||
|
||||
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(d * (90*degree + heading_angle)), 0xFF, d > 0 ? 0x0000FFFF : 0xFF0000FF, PPR::ZERO);
|
||||
|
||||
curvepoint(hpxy(rad/4, 0));
|
||||
curvepoint(hpxy(0, -rad));
|
||||
curvepoint(hpxy(-rad/4, 0));
|
||||
curvepoint(hpxy(rad/4, 0));
|
||||
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(d * (90*degree + heading_angle)), 0xFF, 0xFFFFFFFF, PPR::ZERO);
|
||||
}
|
||||
|
||||
// speed meter
|
||||
|
||||
cx += rad * 3.4;
|
||||
|
||||
for(int i=0; i<360; i++)
|
||||
curvepoint(atscreenpos(cx-cos(i * degree)*rad, cy-sin(i*degree)*rad, 1) * C0);
|
||||
queuecurve(sId, 0x000000FF, 0xFFFFFF80, PPR::ZERO);
|
||||
|
||||
auto e_to_angle = [] (ld energy) {
|
||||
return 135*degree - 3 * atan(energy/10);
|
||||
};
|
||||
|
||||
vector<ld> short_lines = {2, 3, 4, 6, 7, 8, 9, 30, 40, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
|
||||
|
||||
for(auto h: short_lines) {
|
||||
auto a = e_to_angle(h);
|
||||
curvepoint(hpxy(-sin(a)*rad*.95, -cos(a)*rad*.95));
|
||||
curvepoint(hpxy(-sin(a)*rad*.85, -cos(a)*rad*.85));
|
||||
queuecurve(sId * atscreenpos(cx, cy, pix), 0xFF, 0, PPR::ZERO);
|
||||
}
|
||||
|
||||
vector<ld> long_lines = {0, 1, 5, 10, 20, 50};
|
||||
|
||||
for(auto h: long_lines) {
|
||||
auto a = e_to_angle(h);
|
||||
curvepoint(hpxy(-sin(a)*rad*.95, -cos(a)*rad*.95));
|
||||
curvepoint(hpxy(-sin(a)*rad*.75, -cos(a)*rad*.75));
|
||||
queuecurve(sId * atscreenpos(cx, cy, pix), 0xFF, 0, PPR::ZERO);
|
||||
displaystr(cx -sin(a)*rad*.65, cy -cos(a)*rad*.65, 0, 8, its(h), 0, 8);
|
||||
}
|
||||
|
||||
curvepoint(hpxy(rad/4, 0));
|
||||
curvepoint(hpxy(0, -rad));
|
||||
curvepoint(hpxy(-rad/4, 0));
|
||||
curvepoint(hpxy(rad/4, 0));
|
||||
queuecurve(sId * atscreenpos(cx, cy, pix) * spin(e_to_angle(energy_in_squares())), 0xFF, 0xFF8080FF, PPR::ZERO);
|
||||
|
||||
quickqueue();
|
||||
glflush();
|
||||
|
||||
string s = format("%d:%02d.%02d", int(t / 60), int(t) % 60, int(frac(t) * 100));
|
||||
|
||||
displaystr(vid.xres - vid.fsize, vid.fsize*2, 0, vid.fsize * 2, s, 0, 16);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user