mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-07 22:49:54 +00:00
1876 lines
65 KiB
C++
1876 lines
65 KiB
C++
#include "rogueviz.h"
|
|
|
|
// for this video: https://youtu.be/Rhjv_PazzZE
|
|
|
|
namespace hr {
|
|
|
|
/** load Chess? */
|
|
EX bool with_chess = false;
|
|
/** load other models? */
|
|
EX bool with_models = false;
|
|
/** including the CGtrader models? (not included here) */
|
|
EX bool cgtrader_models = false;
|
|
/** floor disabled */
|
|
EX bool no_floor = false;
|
|
/** do not include the models inside the house for faster transition */
|
|
EX bool light_models = false;
|
|
|
|
/** higher periods needs to be set to display scaffold correctly */
|
|
int periods = 1;
|
|
|
|
/** how many chess moves performed */
|
|
int chess_moves = 0;
|
|
|
|
namespace smoothcam {
|
|
using namespace rogueviz::smoothcam;
|
|
}
|
|
|
|
vector<pair<hyperpoint, hyperpoint>> map54_edges;
|
|
vector<hyperpoint> map54_nodes;
|
|
|
|
vector<pair<hyperpoint, hyperpoint>> map534_edges;
|
|
vector<hyperpoint> map534_nodes;
|
|
|
|
struct embset {
|
|
string name;
|
|
geom3::eSpatialEmbedding se;
|
|
ld walls, scale, depth, eye, sun, sky, star;
|
|
};
|
|
|
|
embset current() {
|
|
embset e;
|
|
e.name = "current";
|
|
e.se = geom3::spatial_embedding;
|
|
e.scale = geom3::euclid_embed_scale;
|
|
auto actscale = e.scale;
|
|
if(e.se == geom3::seDefault) { e.scale = 0; actscale = 1; }
|
|
e.walls = vid.wall_height / actscale;
|
|
e.depth = vid.depth / e.walls;
|
|
e.eye = (vid.eye-vid.depth) / e.walls;
|
|
e.sun = vid.sun_size / e.walls;
|
|
e.sky = vid.sky_height;
|
|
e.star = vid.star_height;
|
|
e.se = geom3::spatial_embedding;
|
|
return e;
|
|
}
|
|
|
|
void activate(const embset& e) {
|
|
if(GDIM == 2) invoke_embed(geom3::seDefault);
|
|
embset c = current();
|
|
auto wh = vid.wall_height;
|
|
geom3::changing_embedded_settings = true;
|
|
geom3::switch_always3();
|
|
geom3::euclid_embed_scale = e.se == geom3::seDefault ? 1 : e.scale;
|
|
vid.wall_height = e.walls * geom3::euclid_embed_scale;
|
|
vid.depth = e.depth * vid.wall_height;
|
|
vid.eye = vid.depth + e.eye * vid.wall_height;
|
|
vid.sun_size = e.sun * vid.wall_height;
|
|
vid.sky_height = e.sky;
|
|
vid.star_height = e.star;
|
|
geom3::spatial_embedding = e.se;
|
|
geom3::switch_always3();
|
|
geom3::changing_embedded_settings = false;
|
|
if(e.se != c.se) {
|
|
if(vid.usingGL) resetGL();
|
|
}
|
|
delete_sky();
|
|
if(vid.wall_height * wh < 0) View = MirrorY * View;
|
|
pmodel = default_model();
|
|
};
|
|
|
|
embset lerp(const embset& a, const embset& b, ld f) {
|
|
embset e;
|
|
e.name = lalign(0, "lerp(", a, ", ", b, ", ", f, ")");
|
|
e.se = b.se;
|
|
e.scale = lerp(a.scale, b.scale, f);
|
|
e.walls = lerp(a.walls, b.walls, f);
|
|
e.depth = lerp(a.depth, b.depth, f);
|
|
e.eye = lerp(a.eye, b.eye, f);
|
|
e.sun = lerp(a.sun, b.sun, f);
|
|
e.sky = lerp(a.sky, b.sky, f);
|
|
e.star = lerp(a.star, b.star, f);
|
|
return e;
|
|
}
|
|
|
|
void print(hstream& hs, const embset& e) {
|
|
print(hlog, "embset{.name=\"", e.name, "\", .se=eEmbeddingMethod(", int(e.se), "), .walls=", e.walls, ", .scale=", e.scale, ", .depth=", e.depth, ", .eye=", e.eye, ", .sun=", e.sun, ", .sky=", e.sky, ", .star=", e.star, "}");
|
|
}
|
|
|
|
embset edefault = embset{.name="default", .se=geom3::seDefault, .walls=1.2, .scale=0, .depth=0, .eye=1.5, .sun=0.333333, .sky=10, .star=9};
|
|
embset edefaulti = embset{.name="default", .se=geom3::seDefault, .walls=-1.2, .scale=0, .depth=0, .eye=-1.5, .sun=0.333333, .sky=10, .star=9};
|
|
// embset eincyl = embset{.name="in cylinder", .se=geom3::seCylinderE, .walls=0.75, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.6};
|
|
embset eincyl = embset{.name="in cylinder E", .se=geom3::seCylinderE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset eoutcyl = embset{.name="out cylinder E", .se=geom3::seCylinderE, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.3, .sky=10, .star=9};
|
|
embset eouthoro = embset{.name="out horosphere", .se=geom3::seLowerCurvature, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5};
|
|
embset einhoro = embset{.name="in horosphere", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
|
|
embset einhoro_small = embset{.name="in horosphere (small sky)", .se=geom3::seLowerCurvature, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=18, .star=17};
|
|
embset esolv = embset{.name="solv", .se=geom3::seSol, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
|
|
embset einnih = embset{.name="in NIH", .se=geom3::seNIH, .walls=-1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
|
|
embset eoutnih = embset{.name="out NIH", .se=geom3::seNIH, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=8, .star=7.5};
|
|
embset eclifford = embset{.name="Clifford", .se=geom3::seCliffordTorus, .walls=1.2, .scale=M_PI/10, .depth=-0.0561826, .eye=1.5, .sun=0.25, .sky=2.55, .star=2.3};
|
|
embset enil = embset{.name="Nil flat", .se=geom3::seNil, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
|
|
embset esl2 = embset{.name="SL(2,R) flat", .se=geom3::seSL2, .walls=1.2, .scale=0.1, .depth=0, .eye=1.5, .sun=0.25, .sky=12, .star=11};
|
|
embset eincylh = embset{.name="in cylinderH", .se=geom3::seCylinderH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset eincylhe = embset{.name="in cylinderHE", .se=geom3::seCylinderHE, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset eincylnil = embset{.name="in cylinder Nil", .se=geom3::seCylinderNil, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset eincylsl = embset{.name="in cylinder SL(2,R)", .se=geom3::seCylinderSL2, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset einhorocyl = embset{.name="in horocylinder", .se=geom3::seCylinderHoro, .walls=-1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=8, .star=7.5};
|
|
embset eouthorocyl = embset{.name="out horocylinder", .se=geom3::seCylinderHoro, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=4, .star=3.5};
|
|
embset eprodh_flat = embset{.name="hyperbolic product (flat)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset eprodh_concave = embset{.name="hyperbolic product (concave)", .se=geom3::seProductH, .walls=1.2, .scale=M_PI/10, .depth=1, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset eprods_flat = embset{.name="spherical product (flat)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
embset eprods_concave = embset{.name="spherical product (concave)", .se=geom3::seProductS, .walls=1.2, .scale=M_PI/10, .depth=0.8333, .eye=1.5, .sun=0.10472, .sky=2.6, .star=2.4};
|
|
|
|
embset& edok() { return vid.wall_height > 0 ? edefault : edefaulti; }
|
|
|
|
vector<embset> embsets = {
|
|
edefault,
|
|
eincyl, eoutcyl, eouthoro, einhoro, einhoro_small, esolv, eclifford, einnih, eoutnih,
|
|
enil, esl2, eincylh, eincylhe, eincylnil, eincylsl,
|
|
einhorocyl, eouthorocyl, eprodh_flat, eprodh_concave, eprods_flat, eprods_concave
|
|
};
|
|
|
|
ld fix_chess = 0;
|
|
|
|
int draw_digger = 0;
|
|
|
|
bool move_cat = false;
|
|
|
|
vector<string> xmap = {
|
|
{"......B..........p#"},
|
|
{".................p#"},
|
|
{"..xxxxxxxx.......p#"},
|
|
{"..xxxxxxxx..T....p#"},
|
|
{"..xxxxxxxx.....T.p#"},
|
|
{"..xxxxxxxx...~~..p#"},
|
|
{"..xxxxxxxx..~uv~.p#"},
|
|
{"..xxxxxxxx..~vu~.p#"},
|
|
{"..xxxxxxxx..~~~~.p#"},
|
|
{"..xxxxxxxx......Tp#"},
|
|
{".............T...p#"},
|
|
{"......C..........p#"},
|
|
{"......p..........p#"},
|
|
{".>>>..p..DDDDDDD.p#"},
|
|
{".>>>..pK.DddddrD.p#"},
|
|
{".>>>..pK.DdddtdD.p#"},
|
|
{"......pK.DdddddD.p#"},
|
|
{"..e...p..DOD+DOD.p#"},
|
|
{"......p.....p....p#"},
|
|
{"....^.pppppppppppp#"},
|
|
};
|
|
|
|
namespace embchess {
|
|
|
|
void build_map();
|
|
|
|
ld hmul;
|
|
|
|
set<cell*> domek1, domek2;
|
|
|
|
vector<cell*> ac, bac;
|
|
|
|
using namespace rogueviz::objmodels;
|
|
|
|
void prepare_tf();
|
|
|
|
hyperpoint adjust(hyperpoint h) {
|
|
h = cspin90(1, 2) * h * 40. + point3(-0.5, -0.5, 0);
|
|
return h;
|
|
}
|
|
|
|
hyperpoint rechess(hyperpoint h) {
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, 0.01-h[2]/4 * hmul * 2 / 0.6) + fix_chess;
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
|
|
struct split_model_data : gi_extension {
|
|
map<pair<int, int>, vector<shared_ptr<object>>> objs_at;
|
|
void render(const shiftmatrix& V, int x, int y);
|
|
};
|
|
|
|
struct chessmodel : public model {
|
|
|
|
void process_triangle(vector<hyperpoint>& hys, vector<hyperpoint>& tot, bool textured, object *co) override {
|
|
|
|
for(auto& h: hys) h = adjust(h);
|
|
|
|
hyperpoint norm = (hys[1] - hys[0]) ^ (hys[2] - hys[0]);
|
|
norm /= hypot_d(3, norm);
|
|
ld y = .5 + (.2 * norm[0] + .16 * norm[1] + .14 * norm[2]);
|
|
glvertex shade = glhr::makevertex(0, y, 0);
|
|
glvertex shadecol = glhr::makevertex(y, y, y);
|
|
|
|
auto elen = [] (hyperpoint a, hyperpoint b) { return ceil(hypot_d(3, a-b) * 5); };
|
|
|
|
int parts = max( max(elen(hys[0], hys[1]), elen(hys[0], hys[2])), elen(hys[1], hys[1]) );
|
|
// if(parts > 8) println(hlog, "parts = ", parts, " levels = ", tie(hys[0][2], hys[1][2], hys[2][2]), " .. ", hys);
|
|
// if(parts > 8) return;
|
|
|
|
auto tri = [&] (int a, int b) {
|
|
cgi.hpcpush(rechess(hys[0] + (hys[1] - hys[0]) * a / parts + (hys[2] - hys[0]) * b / parts));
|
|
if(textured) {
|
|
co->tv.tvertices.push_back(glhr::pointtogl(tot[0] + (tot[1] - tot[0]) * a / parts + (tot[2] - tot[0]) * b / parts));
|
|
co->tv.colors.push_back(shadecol);
|
|
}
|
|
else {
|
|
co->tv.tvertices.push_back(shade);
|
|
}
|
|
};
|
|
|
|
for(int a=0; a<parts; a++)
|
|
for(int b=0; b<parts-a; b++) {
|
|
tri(a, b);
|
|
tri(a+1, b);
|
|
tri(a, b+1);
|
|
if(a+b < parts-1) {
|
|
tri(a, b+1);
|
|
tri(a+1, b);
|
|
tri(a+1, b+1);
|
|
}
|
|
}
|
|
}
|
|
|
|
chessmodel(string a, string b) : model(a,b) {}
|
|
|
|
void split(model_data& md, split_model_data& smd);
|
|
|
|
split_model_data& get_split() {
|
|
auto& md = (unique_ptr<split_model_data>&) cgi.ext[fname + "-SPLIT"];
|
|
|
|
if(!md) {
|
|
md = std::make_unique<split_model_data>();
|
|
auto& md0 = get();
|
|
split(md0, *md);
|
|
}
|
|
|
|
return *md;
|
|
}
|
|
};
|
|
|
|
bool ispiece(color_t col) {
|
|
return among(col, color_t(0xFFFFFFFF), color_t(0x202020FF), color_t(0x2B2B2BFF));
|
|
}
|
|
|
|
void chessmodel::split(model_data& md, split_model_data& smd) {
|
|
cgi.extra_vertices();
|
|
map<pair<int, int>, map<color_t, vector<pair<hyperpoint, glvertex>>>> mm;
|
|
for(auto& obj: md.objs) {
|
|
for(int i=obj->sh.s; i<obj->sh.e; i+=3) {
|
|
hyperpoint ctr = Hypc;
|
|
array<hyperpoint, 3> hs;
|
|
for(int j=0; j<3; j++) hs[j] = GDIM == 2 ? cgi.hpc[i+j] : cgi.emb->actual_to_logical(cgi.hpc[i+j]);
|
|
ctr += hs[0];
|
|
ctr += hs[1];
|
|
ctr += hs[2];
|
|
ctr /= 3;
|
|
int x = floor(ctr[0] + .5);
|
|
int y = floor(ctr[1] + .5);
|
|
int ax = x + 6, ay = y + 6;
|
|
if(chess_moves >= 1 && ispiece(obj->color)) {
|
|
if(ax == 6) { if(ay == 8) ay = 6; else if(ay == 6) ay = 8; }
|
|
}
|
|
if(chess_moves >= 2 && ispiece(obj->color)) {
|
|
if(ax == 6) { if(ay == 3) ay = 5; else if(ay == 5) ay = 3; }
|
|
}
|
|
if(chess_moves >= 3 && ispiece(obj->color)) {
|
|
if(ax == 8) { if(ay == 9) ay = 7, ax = 7; }
|
|
}
|
|
for(int j=0; j<3; j++)
|
|
mm[{ax,ay}][obj->color].emplace_back(hs[j] - hyperpoint(x, y, 0, 0), obj->tv.tvertices[i+j-obj->sh.s]);
|
|
}
|
|
}
|
|
for(auto& a: mm)
|
|
for(auto& b: a.second) {
|
|
auto& objs = smd.objs_at[a.first];
|
|
objs.push_back(make_shared<object>());
|
|
auto co = &*objs.back();
|
|
cgi.bshape(co->sh, PPR::THORNS);
|
|
cgi.last->flags |= POLY_TRIANGLES;
|
|
cgi.last->texture_offset = 0;
|
|
cgi.last->tinf = &co->tv;
|
|
co->tv.texture_id = floor_textures->renderedTexture;
|
|
if(GDIM == 2) cgi.last->tinf = nullptr;
|
|
co->color = b.first;
|
|
if(co->color == 0xCCCCCCFF) co->color = GDIM == 2 ? 0 : 0xFFE080FF;
|
|
else if(co->color == 0x5B5B5BFF) co->color = GDIM == 2 ? 0 : 0x807020FF;
|
|
// else for(auto& v: b.second) v.first = cspin180(0, 1) * v.first;
|
|
for(auto v: b.second) {
|
|
cgi.hpcpush(GDIM == 2 ? v.first : cgi.emb->logical_to_actual(v.first));
|
|
co->tv.tvertices.push_back(v.second);
|
|
}
|
|
cgi.finishshape();
|
|
}
|
|
cgi.extra_vertices();
|
|
if(0) for(auto& p: smd.objs_at) {
|
|
println(hlog, p.first, " : ", isize(p.second), " objects");
|
|
for(auto& obj: p.second) {
|
|
vector<hyperpoint> hs;
|
|
for(int i=obj->sh.s; i<obj->sh.e; i++) hs.push_back(cgi.hpc[i]);
|
|
if(isize(hs) > 3) hs.resize(3);
|
|
println(hlog, "vertices: ", obj->sh.e - obj->sh.s, " of color ", obj->color, " : ", hs);
|
|
}
|
|
}
|
|
}
|
|
|
|
void split_model_data::render(const shiftmatrix& V, int x, int y) {
|
|
for(auto& obj: objs_at[{x, y}]) if(obj->color) {
|
|
queuepoly(V, obj->sh, obj->color);
|
|
}
|
|
}
|
|
|
|
chessmodel chess("rogueviz/models/", "Polyfjord_Chess_Set.obj");
|
|
|
|
ld minz = 100, maxz = -100;
|
|
ld minx = 100, maxx = -100;
|
|
ld miny = 100, maxy = -100;
|
|
|
|
struct bunnymodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h = cspin(0, 1, 15._deg) * h;
|
|
h[0] *= 800;
|
|
h[1] *= 800;
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(-0.000333099, -0.00186996, h[2]) * hmul * 4/3.);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
bunnymodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
bunnymodel bunny("rogueviz/models/", "bunny.obj");
|
|
|
|
struct catmodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
|
|
if(0) println(hlog, "scale = 1 to ",
|
|
lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, 1) * hmul * 4/3.)
|
|
- lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, 0) * hmul * 4/3.)
|
|
);
|
|
|
|
h = cspin90(1, 2) * h;
|
|
h = cspin180(0, 1) * h;
|
|
h = cspin(1, 0, 30._deg) * h;
|
|
h[0] *= 6;
|
|
h[1] *= 6;
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00767046, -0.184471, h[2]) * hmul * 4/3.) / 8.3272 * 6;
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
void load_obj(model_data& md) override {
|
|
model::load_obj(md);
|
|
for(auto& o: md.objs) if(o->mtlname == "whiskers") o->sh.prio = PPR::TRANSPARENT_WALL;
|
|
}
|
|
catmodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
catmodel maxwellcat("rogueviz/models/", "maxwellcat.obj");
|
|
|
|
struct tulipmodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h = cspin180(0, 1) * h;
|
|
h[0] *= 400;
|
|
h[1] *= 400;
|
|
h[0] -= 0.1*2; h[1] += 0.36*2;
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0, -0.00307639, h[2]) * hmul);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
tulipmodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
tulipmodel tulip("rogueviz/models/", "tulip.obj");
|
|
tulipmodel tulip1("rogueviz/models/", "tulip1.obj");
|
|
tulipmodel tulip2("rogueviz/models/", "tulip2.obj");
|
|
|
|
struct diggermodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h[0] *= 50;
|
|
h[1] *= 50;
|
|
/* h[0] *= 400;
|
|
h[1] *= 400;
|
|
h[0] -= 0.1*2; h[1] += 0.36*2; */
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0.00027, -0.0549454, h[2]) * hmul * 1.5);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
diggermodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
diggermodel digger("rogueviz/models/", "digger.obj");
|
|
|
|
struct tablemodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h[1] -= 0.005;
|
|
h[0] *= 100;
|
|
h[1] *= 100;
|
|
/* h[0] *= 400;
|
|
h[1] *= 400;
|
|
h[0] -= 0.1*2; h[1] += 0.36*2; */
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(0, -0.008, h[2]) * hmul / 2);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
tablemodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
tablemodel table("rogueviz/models/", "table.obj");
|
|
|
|
struct cheesemodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h[0] *= 15;
|
|
h[1] *= 15;
|
|
/* h[0] *= 400;
|
|
h[1] *= 400;
|
|
h[0] -= 0.1*2; h[1] += 0.36*2; */
|
|
h[0] -= 0.2;
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, (ilerp(0.00577916, -0.01166, h[2])/3 + 1.05) * hmul / 2);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
cheesemodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
cheesemodel cheese("rogueviz/models/", "cheese.obj");
|
|
|
|
struct coffeemodel : public model {
|
|
int cid;
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h[0] += 0.00077;
|
|
h[1] += 0.011;
|
|
h[0] *= 200; h[1] *= 200;
|
|
if(cid == 1) h[0] += 0.3;
|
|
if(cid == 2) h[1] += 0.5;
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, (ilerp(-0.0083, -0.0089, h[2])) * 1.2 / 10 + .51);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
coffeemodel(string a, string b, int _id) : model(a,b), cid(_id) {}
|
|
};
|
|
|
|
/* need different file names */
|
|
coffeemodel coffee1("rogueviz/models/", "coffee.obj", 1), coffee2("rogueviz/models/", "./coffee.obj", 2);
|
|
|
|
struct lilymodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h[0] += 0.67; h[1] -= 0.36;
|
|
h[0] *= 5;
|
|
h[1] *= 5;
|
|
/* h[0] *= 400;
|
|
h[1] *= 400;
|
|
h[0] -= 0.1*2; h[1] += 0.36*2; */
|
|
h[2] = lerp(cgi.LAKE, cgi.FLOOR, ilerp(0.018, -0.0496, h[2]) * hmul);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
lilymodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
lilymodel lily("rogueviz/models/", "lily.obj");
|
|
|
|
struct duckmodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h[0] += 3.8; h[1] -= 2;
|
|
/* h[0] *= 400;
|
|
h[1] *= 400;
|
|
h[0] -= 0.1*2; h[1] += 0.36*2; */
|
|
h[2] = lerp(cgi.LAKE, cgi.FLOOR, ilerp(0.056, -0.408, h[2]) * hmul * 1.5);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
duckmodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
duckmodel duck("rogueviz/models/", "duck.obj");
|
|
|
|
struct ratmodel : public model {
|
|
hyperpoint transform(hyperpoint h) override {
|
|
h = cspin90(1, 2) * h;
|
|
h[0] *= 100;
|
|
h[1] *= 100;
|
|
h[2] *= 100;
|
|
h[0] /= 3 * 3;
|
|
h[1] /= 3 * 3;
|
|
h[2] /= 3 * 3;
|
|
h = cspin(0, 1, 135._deg) * h;
|
|
|
|
if(h[2] < minz) minz = h[2];
|
|
if(h[2] > maxz) maxz = h[2];
|
|
if(h[0] < minx) minx = h[0];
|
|
if(h[0] > maxx) maxx = h[0];
|
|
if(h[1] < miny) miny = h[1];
|
|
if(h[1] > maxy) maxy = h[1];
|
|
|
|
h[2] = lerp(cgi.FLOOR, cgi.WALL, ilerp(1/9., 1/9. - 1.2, h[2]) * hmul);
|
|
if(GDIM == 3) h = cgi.emb->logical_to_actual(h);
|
|
else h[2] = 1;
|
|
return h;
|
|
}
|
|
ratmodel(string a, string b) : model(a,b) {}
|
|
};
|
|
|
|
ratmodel rat("rogueviz/models/", "spinning-rat.obj");
|
|
|
|
bool hedge_constructed = false;
|
|
|
|
const int hx = 7;
|
|
array<char, hx*hx*hx> hedge_visited;
|
|
array<int, 6> hdirs = {1, hx, hx*hx, -1, -hx, -hx*hx};
|
|
|
|
array<vector<int>, hx*hx*hx> hedge_dirs;
|
|
|
|
int hstart;
|
|
|
|
void construct_hedge() {
|
|
for(int x=0; x<hx*hx*hx; x++) hedge_visited[x] = false;
|
|
hstart = (hx/2)+(hx/2)*hx;
|
|
hedge_visited[hstart] = true;
|
|
vector<int> inorder = {hstart};
|
|
for(int i=0; i<hx*hx*hx; i++) {
|
|
int at = inorder[i];
|
|
for(int dir: {0, 1, 3, 4, 2, 5}) {
|
|
int co = (at / abs(hdirs[dir])) % hx;
|
|
if(hdirs[dir] < 0 && co == 0) continue;
|
|
if(hdirs[dir] > 0 && co == hx-1) continue;
|
|
if(hedge_visited[at+hdirs[dir]]) continue;
|
|
hedge_visited[at+hdirs[dir]] = true;
|
|
hedge_dirs[at].push_back(dir);
|
|
inorder.push_back(at+hdirs[dir]);
|
|
}
|
|
}
|
|
/*
|
|
int qty = hx*hx*hx-1;
|
|
while(qty > 0) {
|
|
int at = hrand(hx*hx*hx);
|
|
if(!hedge_visited[at]) continue;
|
|
int dir = hrand(6);
|
|
int co = (at / abs(hdirs[dir])) % hx;
|
|
if(hdirs[dir] < 0 && co == 0) continue;
|
|
if(hdirs[dir] > 0 && co == hx-1) continue;
|
|
if(hedge_visited[at+hdirs[dir]]) continue;
|
|
hedge_visited[at+hdirs[dir]] = true;
|
|
hedge_dirs[at].push_back(dir);
|
|
qty--;
|
|
} */
|
|
}
|
|
|
|
void add_oct(transmatrix T, int idx, int face, ld len) {
|
|
array<hyperpoint, 3> p;
|
|
for(int i=0; i<3; i++) { p[i] = C03; p[i][i] = ((face>>i)&1) ? len/2 : -len/2; p[i] = cgi.emb->logical_scaled_to_intermediate * p[i]; }
|
|
hyperpoint c = (p[0] + p[1] + p[2]) / 3;
|
|
for(int f=0; f<3; f++) {
|
|
hyperpoint a = p[f] - c;
|
|
hyperpoint b = p[(f+1)%3] - c;
|
|
texture_order([&] (ld x, ld y) {
|
|
hyperpoint h = c + a * x + b * y;
|
|
hyperpoint t = T * cpush(0, h[0]) * cpush(1, h[1]) * cpush(2, h[2]) * C0;
|
|
cgi.hpcpush(t);
|
|
});
|
|
}
|
|
if(true) for(auto d: hedge_dirs[idx]) {
|
|
hyperpoint h = C0;
|
|
h[d%3] = (d<3 ? -len: len);
|
|
h = cgi.emb->logical_scaled_to_intermediate * h;
|
|
transmatrix T1 = T;
|
|
for(int i=0; i<3; i++) if(h[i]) T1 = T1 * cpush(i, h[i]);
|
|
add_oct(T1, idx + hdirs[d], face, len);
|
|
}
|
|
}
|
|
|
|
void create_hedge(model_data& md) {
|
|
if(!hedge_constructed) construct_hedge();
|
|
hyperpoint start = cgi.emb->logical_to_actual(point31(0, 0, cgi.FLOOR));
|
|
hyperpoint npt = cgi.emb->logical_to_actual(point31(0.01, 0, cgi.FLOOR));
|
|
transmatrix S = cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point31(0, 0, cgi.emb->center_z() + cgi.FLOOR));
|
|
ld len = hdist(start, npt) * 100 / 7;
|
|
len *= 3;
|
|
if(vid.wall_height < 0) len = -len;
|
|
md.objs.resize(8);
|
|
for(int i=0; i<8; i++) {
|
|
md.objs[i] = make_shared<object> ();
|
|
auto& obj = *md.objs[i];
|
|
obj.color = 0xFF00FF;
|
|
if(i & 1) obj.color ^= 0x200000;
|
|
if(i & 2) obj.color ^= 0x20000000;
|
|
if(i & 4) obj.color ^= 0x2000;
|
|
cgi.bshape(obj.sh, PPR::FLOOR_DRAGON);
|
|
cgi.last->flags |= POLY_TRIANGLES;
|
|
cgi.last->texture_offset = 0;
|
|
cgi.last->tinf = &obj.tv;
|
|
obj.tv.texture_id = floor_textures->renderedTexture;
|
|
add_oct(S * lzpush(-len/2), hstart, i, len);
|
|
cgi.finishshape();
|
|
bind_floor_texture(obj.sh, cgi.shFeatherFloor.id);
|
|
}
|
|
cgi.extra_vertices();
|
|
}
|
|
|
|
void draw_hedge(const shiftmatrix& V) {
|
|
auto& md = (unique_ptr<model_data>&) cgi.ext["hedge"];
|
|
if(!md) {
|
|
md = std::make_unique<model_data>();
|
|
create_hedge(*md);
|
|
}
|
|
md->render(V);
|
|
}
|
|
|
|
hyperpoint inverse_exp_newton(hyperpoint h, int iter) {
|
|
auto approx = inverse_exp(shiftless(h));
|
|
for(int i=0; i<iter; i++) {
|
|
transmatrix T;
|
|
ld eps = 1e-3;
|
|
hyperpoint cur = direct_exp(approx);
|
|
println(hlog, approx, " error = ", hdist(cur, h), " iteration ", i, "/", iter);
|
|
for(int i=0; i<3; i++)
|
|
set_column(T, i, direct_exp(approx + ctangent(i, eps)) - h);
|
|
set_column(T, 3, C03);
|
|
approx = approx - inverse(T) * (cur - h) * eps;
|
|
}
|
|
return approx;
|
|
}
|
|
|
|
hpcshape& get_noniso_pipe(hyperpoint target, ld width, ePipeEnd endtype) {
|
|
int id = bucketer(target) + int(157003 * log(width+.001));
|
|
if(cgi.shPipe.count(id)) return cgi.shPipe[id];
|
|
hpcshape& pipe = cgi.shPipe[id];
|
|
println(hlog, "generating pipe at target ", target, " and width ", width);
|
|
cgi.bshape(pipe, PPR::HEPTAMARK);
|
|
|
|
#if CAP_GL
|
|
auto& utt = cgi.models_texture;
|
|
if(floor_textures) {
|
|
pipe.tinf = &utt;
|
|
pipe.texture_offset = isize(utt.tvertices);
|
|
}
|
|
#endif
|
|
|
|
hyperpoint lmax = inverse_exp_newton(target, 10);
|
|
println(hlog, "error = ", hdist(direct_exp(lmax), target));
|
|
transmatrix lT;
|
|
ld length;
|
|
if(1) {
|
|
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
|
length = hdist0(lmax);
|
|
lT = rspintox(lmax);
|
|
println(hlog, "target = ", target, " lmax = ", lmax, " length = ", length, " lT = ", kz(lT));
|
|
println(hlog, "test: ", lT * xpush0(length), " vs ", lmax);
|
|
}
|
|
|
|
const int MAX_X = 32;
|
|
const int MAX_R = 20;
|
|
auto at = [&] (ld i, ld a, ld z = 1, ld s = 1) {
|
|
a += 0.5;
|
|
ld alpha = TAU * a / MAX_R;
|
|
hyperpoint p;
|
|
if(1) {
|
|
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
|
p = xpush(i * length / MAX_X) * cspin(1, 2, alpha) * ypush0(width*z);
|
|
p = lT * p;
|
|
}
|
|
p = direct_exp(p);
|
|
cgi.hpcpush(p);
|
|
#if CAP_GL
|
|
if(floor_textures) utt.tvertices.push_back(glhr::makevertex(0, true ? 0.549 - s * 0.45 * sin(alpha) : 0.999, 0));
|
|
#endif
|
|
};
|
|
for(int i=0; i<MAX_X; i++) {
|
|
for(int a=0; a<MAX_R; a++) {
|
|
at(i, a, 1);
|
|
at(i, a+1, 1);
|
|
at(i+1, a, 1);
|
|
at(i+1, a+1, 1);
|
|
at(i+1, a, 1);
|
|
at(i, a+1, 1);
|
|
}
|
|
}
|
|
|
|
if(endtype == ePipeEnd::sharp) for(int a=0; a<MAX_R; a++) for(int x: {0, MAX_X}) {
|
|
at(x, a, 1, 0);
|
|
at(x, a+1, 1, 0);
|
|
at(x, 0, 0, 0);
|
|
}
|
|
|
|
if(endtype == ePipeEnd::ball) for(int a=0; a<MAX_R; a++) for(int x=-MAX_R; x<MAX_R; x++) {
|
|
ld xb = x < 0 ? 0 : MAX_X;
|
|
ld mul = MAX_X * width/length * .9; // .9 to prevent Z-fighting
|
|
ld x0 = xb + mul * sin(x * 90._deg / MAX_R);
|
|
ld x1 = xb + mul * sin((x+1) * 90._deg / MAX_R);
|
|
ld z0 = cos(x * 90._deg / MAX_R);
|
|
ld z1 = cos((x+1) * 90._deg / MAX_R);
|
|
at(x0, a, z0, z0);
|
|
at(x0, a+1, z0, z0);
|
|
at(x1, a, z1, z1);
|
|
at(x1, a+1, z1, z1);
|
|
at(x1, a, z1, z1);
|
|
at(x0, a+1, z0, z0);
|
|
}
|
|
|
|
cgi.last->flags |= POLY_TRIANGLES | POLY_PRINTABLE;
|
|
cgi.finishshape();
|
|
cgi.extra_vertices();
|
|
return pipe;
|
|
}
|
|
|
|
void fat_line(const shiftmatrix& V1, const hyperpoint h1, const shiftmatrix& V2, const hyperpoint h2, color_t col, int prec, ld lw) {
|
|
if(nonisotropic) {
|
|
auto nV1 = V1 * rgpushxto0(h1);
|
|
hyperpoint U2 = inverse_shift(nV1, V2*rgpushxto0(h2)) * C0;
|
|
auto& p = get_noniso_pipe(U2, lw, ePipeEnd::ball);
|
|
queuepoly(nV1, p, col);
|
|
return;
|
|
}
|
|
|
|
ld d = hdist(V1.T*h1, V2.T*h2);
|
|
|
|
shiftmatrix T = V1 * rgpushxto0(h1);
|
|
transmatrix S = rspintox(inverse_shift(T, V2) * h2);
|
|
transmatrix U = rspintoc(inverse_shift(T*S, shiftless(C0)), 2, 1);
|
|
auto& p = queuepoly(T * S * U, cgi.generate_pipe(d, lw, ePipeEnd::ball), col);
|
|
p.intester = xpush0(d/2);
|
|
}
|
|
|
|
int scaffoldx = 0, scaffoldy = 0, scaffoldb = 0, scaffoldx_move = 0, scaffoldy_move;
|
|
|
|
template<class T> void draw_map54(const shiftmatrix& S, const T& f, color_t col) {
|
|
for(auto p: map54_nodes) queuepoly(S * rgpushxto0(f(p)), cgi.shSnowball, 0xFFFFFFFF);
|
|
for(auto& p: map54_edges) fat_line(S, f(p.first), S, f(p.second), (abs(p.first[1])<1e-3 && abs(p.second[1])<1e-3 && scaffoldx && scaffoldy) ? 0xFFFFFFFF : col, 2, 0.01);
|
|
}
|
|
|
|
void draw_scaffold(const shiftmatrix& V) {
|
|
ld levz = log(2);
|
|
if(nih) levz = 1;
|
|
ld levx = 1;
|
|
if(hyperbolic) levx = exp(-cgi.FLOOR);
|
|
levx *= 5;
|
|
|
|
if(scaffoldx == 1)
|
|
for(int z=-5; z<=5; z++)
|
|
for(int s=-20; s<=20; s++) {
|
|
shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(s*levx,0,0));
|
|
queuepoly(S, cgi.shSnowball, 0xFFFFFFFF);
|
|
fat_line(S, C0, S, lzpush(-levz) * C0, (s == 0 && scaffoldy) ? 0xFFFFFFFF : 0xFF0000FF, 2, 0.01);
|
|
for(int s=0; s<8; s++)
|
|
fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+0)/8.,0,0)) * C0,
|
|
S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+1)/8.,0,0)) * C0,
|
|
0x8000FFFF, 2, 0.01);
|
|
}
|
|
|
|
if(scaffoldx == 2) {
|
|
if(hyperbolic) {
|
|
draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(h[1],0,0)) * zpush(h[0]) * C0; }, 0xFFD500FF);
|
|
}
|
|
if(sol) {
|
|
draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(h[1],0,0)) * zpush(-h[0]) * C0; }, 0xFFD500FF);
|
|
}
|
|
if(nih) {
|
|
draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(-h[1]/log(2),0,0)) * zpush(h[0]/log(2)) * C0; }, 0xFFD500FF);
|
|
}
|
|
}
|
|
|
|
ld levy = 5;
|
|
if(scaffoldy == 1)
|
|
for(int z=-5; z<=5; z++)
|
|
for(int s=-20; s<=20; s++) {
|
|
shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,s*levy,0));
|
|
queuepoly(S, cgi.shSnowball, 0xFFFFFFFF);
|
|
fat_line(S, C0, S, lzpush(sol ? levz : -levz) * C0, (s == 0 && scaffoldx) ? 0xFFFFFFFF : 0x0000FFFF, 2, 0.01);
|
|
for(int s=0; s<8; s++)
|
|
fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0, levy*(s+0)/8.,0)) * C0,
|
|
S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0, levy*(s+1)/8.,0)) * C0,
|
|
0x0080FF, 2, 0.01);
|
|
}
|
|
|
|
if(scaffoldy == 2) {
|
|
if(hyperbolic) {
|
|
draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1],0)) * zpush(h[0]) * C0; }, 0x80D500FF);
|
|
}
|
|
if(sol) {
|
|
draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1],0)) * zpush(h[0]) * C0; }, 0x80D500FF);
|
|
}
|
|
if(nih) {
|
|
draw_map54(V, [] (hyperpoint h) { return cgi.emb->intermediate_to_actual_translation(point3(0,h[1]/log(3),0)) * zpush(h[0]/log(3)) * C0; }, 0x80D500FF);
|
|
}
|
|
}
|
|
|
|
if(scaffoldb == 1)
|
|
for(int z=-5; z<=5; z++)
|
|
for(int sx=-5; sx<=5; sx++)
|
|
for(int sy=-5; sy<=5; sy++) {
|
|
shiftmatrix S = V * lzpush(cgi.FLOOR + z * levz) * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(sx*levx,sy*levy,0));
|
|
queuepoly(S, cgi.shSnowball, 0xFFFFFFFF);
|
|
fat_line(S, C0, S, lzpush(-levz) * C0, 0xFF0000FF, 2, 0.01);
|
|
for(int s=0; s<8; s++) {
|
|
fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+0)/8.,0,0)) * C0,
|
|
S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(levx*(s+1)/8.,0,0)) * C0,
|
|
0xFF8000FF, 2, 0.01);
|
|
fat_line(S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,levy*(s+0)/8.,0)) * C0,
|
|
S, cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(0,levy*(s+1)/8.,0)) * C0,
|
|
0xFF8000FF, 2, 0.01);
|
|
}
|
|
}
|
|
|
|
if(scaffoldb == 2 && hyperbolic) {
|
|
for(auto h: map534_nodes) queuepoly(V * rgpushxto0(h), cgi.shSnowball, 0xFFFFFFFF);
|
|
for(auto h: map534_edges) fat_line(V, h.first, V, h.second, 0xFFFFFFFF, 2, 0.01);
|
|
}
|
|
}
|
|
|
|
/*
|
|
static bool first = true;
|
|
if(first) println(hlog, tie(minx, maxx), tie(miny, maxy), tie(minz, maxz));
|
|
first = false;
|
|
*/
|
|
|
|
string losowo = "1100002102001211";
|
|
|
|
void draw_shape(const shiftmatrix& V, vector<ld> tab, color_t col, ld mul = 1) {
|
|
int n = isize(tab);
|
|
for(int i=0; i<n; i+=2) curvepoint(hpxy(tab[i]*mul, tab[i+1]*mul));
|
|
curvepoint(hpxy(tab[0]*mul, tab[1]*mul));
|
|
queuecurve(V, 0xFF, col, PPR::MONSTER_LEG);
|
|
}
|
|
|
|
bool draw_chess_at(cell *c, const shiftmatrix& V) {
|
|
if(c->item == itHyperstone) c->item = itNone;
|
|
if(false) {
|
|
if(c == cwt.at) chess.render(V);
|
|
}
|
|
else {
|
|
auto co = euc::full_coords2(c);
|
|
char& chr = xmap[gmod(co.second, 20)][gmod(co.first, 20)];
|
|
char ch = chr;
|
|
if(no_floor && ch != '^') ch = '<';
|
|
|
|
// if(co.first == 0 && co.second == 0) bunny.render(V);
|
|
switch(ch) {
|
|
case 'r':
|
|
if(GDIM == 3 && with_models) {
|
|
rat.render(V);
|
|
static bool first = true;
|
|
if(first) println(hlog, tie(minx, maxx), tie(miny, maxy), tie(minz, maxz));
|
|
first = false;
|
|
}
|
|
else {
|
|
drawMonsterType(moMouse, c, V * spin(-135._deg), 0x804000, 0, 0x804000);
|
|
}
|
|
break;
|
|
case '<':
|
|
c->wall = waChasm;
|
|
domek1.erase(c); domek2.erase(c);
|
|
fat_line(V, cgi.emb->logical_to_actual(point31(0.5, 0.5, 0)), V, cgi.emb->logical_to_actual(point31(0.5, -0.5, 0)), 0xFFFFFFFF, 2, 0.001);
|
|
fat_line(V, cgi.emb->logical_to_actual(point31(0.5, 0.5, 0)), V, cgi.emb->logical_to_actual(point31(-0.5, 0.5, 0)), 0xFFFFFFFF, 2, 0.001);
|
|
break;
|
|
case 'u': {
|
|
if(GDIM == 3 && with_models) {
|
|
lily.render(V);
|
|
c->item = itNone;
|
|
}
|
|
else c->item = itWet;
|
|
break;
|
|
}
|
|
case 'v': {
|
|
if(GDIM == 3 && with_models) duck.render(V);
|
|
else {
|
|
draw_shape(V, {-0.164988, 0.0033671, -0.114197, 0.0638159, 0.0401905, 0.063635, 0.10735, 0.0268375, 0.10735, -0.0268375, 0.0401905, -0.063635, -0.114197, -0.0638159, -0.164988, -0.0033671, }, 0xC0C0C0FF, 2);
|
|
draw_shape(V, {-0.0753584, 0.00669852, -0.111558, 0.0184533, -0.0812589, 0.0326711, -0.161669, 0.0479953, -0.10074, 0.0780737, -0.0184331, 0.0896519, 0.0830064, 0.065399, 0.113269, 0.0335611, 0.117466, 0.0151028, 0.117466, -0.0151028, 0.113269, -0.0335611, 0.0830064, -0.065399, -0.0184331, -0.0896519, -0.10074, -0.0780737, -0.161669, -0.0479953, -0.0812589, -0.0326711, -0.111558, -0.0184533, -0.0753584, -0.00669852, }, 0x806010FF, 2);
|
|
draw_shape(V, {0.164139, 0.0109426, 0.200142, 0.0185786, 0.239985, 0.00848005, 0.239985, -0.00848005, 0.200142, -0.0185786, 0.164139, -0.0109426, }, 0xE0E000FF, 2);
|
|
draw_shape(V, {0.0820785, 0.00670028, 0.0963908, 0.0243072, 0.121722, 0.0352575, 0.159071, 0.0361908, 0.183838, 0.028672, 0.199268, 0.00844354, 0.199268, -0.00844354, 0.183838, -0.028672, 0.159071, -0.0361908, 0.121722, -0.0352575, 0.0963908, -0.0243072, 0.0820785, -0.00670}, 0x106010FF, 2);
|
|
}
|
|
break;
|
|
}
|
|
case 'B':
|
|
if(GDIM == 3 && with_models) bunny.render(V);
|
|
else {
|
|
auto V1 = V * spin270();
|
|
draw_shape(V1, {-0.272437, 0.00681093, -0.247911, 0.0339604, -0.199391, 0.0506926, -0.165034, 0.0336804, -0.151363, 0.0100908, -0.151363, -0.0100908, -0.165034, -0.0336804, -0.199391, -0.0506926, -0.247911, -0.0339604, -0.272437, -0.00681093, }, 0xFFFFFFFF, 2);
|
|
draw_shape(V1, {-0.209613, 0.00676172, -0.161797, 0.0741567, -0.107602, 0.100877, 0.0033535, 0.103959, 0.100724, 0.0738645, 0.134426, 0.0369672, 0.14796, 0.00672545, 0.14796, -0.00672545, 0.134426, -0.0369672, 0.100724, -0.0738645, 0.0033535, -0.103959, -0.107602, -0.100877, -0.161797, -0.0741567, -0.209613, -0.00676172, }, 0xC0C0C0FF, 2);
|
|
draw_shape(V1, {0.0502023, 0.0167341, 0.0737312, 0.0536227, 0.151647, 0.0876183, 0.240969, 0.0441211, 0.272441, 0.0102165, 0.272441, -0.0102165, 0.240969, -0.0441211, 0.151647, -0.0876183, 0.0737312, -0.0536227, 0.0502023, -0.0167341, }, 0xD0D0D0FF, 2);
|
|
draw_shape(V1, {0.103977, 0.0268328, 0.0267753, 0.0468568, -0.0536042, 0.063655, -0.00335237, 0.0972189, 0.094003, 0.080574, 0.144678, 0.0571982, 0.154836, 0.0437579, 0.134405, 0.0268809, }, 0xC0C0C0FF, 2);
|
|
draw_shape(V1 * MirrorY, {0.103977, 0.0268328, 0.0267753, 0.0468568, -0.0536042, 0.063655, -0.00335237, 0.0972189, 0.094003, 0.080574, 0.144678, 0.0571982, 0.154836, 0.0437579, 0.134405, 0.0268809, }, 0xC0C0C0FF, 2);
|
|
draw_shape(V1, {0.168425, 0.0235794, 0.178774, 0.0505965, 0.188982, 0.0269974, }, 0xC00000FF, 2);
|
|
draw_shape(V1 * MirrorY, {0.168425, 0.0235794, 0.178774, 0.0505965, 0.188982, 0.0269974, }, 0xC00000FF, 2);
|
|
}
|
|
break;
|
|
case 't':
|
|
if(GDIM == 2) c->wall = waRoundTable; else if(with_models && !light_models) {
|
|
c->wall = waNone;
|
|
table.render(V);
|
|
cheese.render(V);
|
|
coffee1.render(V);
|
|
coffee2.render(V);
|
|
}
|
|
break;
|
|
case 'C':
|
|
if(GDIM == 3 && with_models) maxwellcat.render(V);
|
|
else {
|
|
dynamicval<bool> b(mapeditor::drawplayer, true);
|
|
drawPlayer(moPlayer, c, V * spin90(), 0xFFFFFFFF, 0);
|
|
}
|
|
if(move_cat) {
|
|
move_cat = false;
|
|
mapeditor::drawplayer = true;
|
|
chr = '.';
|
|
cwt.at = c;
|
|
vid.sspeed = -5;
|
|
cwt.spin = 1;
|
|
vid.axes = 0;
|
|
}
|
|
break;
|
|
case 'e':
|
|
if(GDIM == 3 && draw_digger == 2) digger.render(V);
|
|
break;
|
|
case 'K': {
|
|
int a = gmod(co.first + co.second, 3);
|
|
if(GDIM == 3 && with_models) {
|
|
auto gtulip = [&] (int a, int b) -> tulipmodel& { char ch = losowo[5*a+b]; if(ch == '0') return tulip; if(ch == '1') return tulip1; if(ch == '2') return tulip2; return tulip2; };
|
|
gtulip(a, 0).render(V);
|
|
gtulip(a, 1).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(1/3., 1/3., 0)));
|
|
gtulip(a, 2).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(1/3., -1/3., 0)));
|
|
gtulip(a, 3).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(-1/3., 1/3., 0)));
|
|
gtulip(a, 4).render(V * cgi.emb->intermediate_to_actual_translation(cgi.emb->logical_to_intermediate * point3(-1/3., -1/3., 0)));
|
|
}
|
|
else {
|
|
vector<color_t> tcols = {0xFFFF80FF, 0xFF1010FF, 0xC000C0FF};
|
|
draw_shape(V*spin90(), {-0.202738, 0.0236527, -0.145213, 0.135082, -0.0438177, 0.1719, 0.0708783, 0.178883, 0.220846, 0.125712, 0.120989, 0.0705769, 0.219991, 0.00338448, 0.219991, -0.00338448, 0.120989, -0.0705769, 0.220846, -0.125712, 0.0708783, -0.178883, -0.0438177, -0.1719, -0.145213, -0.135082, -0.202738, -0.0236527}, tcols[a], 2);
|
|
}
|
|
break;
|
|
}
|
|
case 'H':
|
|
if(GDIM == 3) draw_hedge(V);
|
|
else queuepoly(V, cgi.shGem[0], 0xFF00FF);
|
|
break;
|
|
case '^': {
|
|
c->wall = no_floor ? waChasm : waNone;
|
|
auto ax = co.first - scaffoldx_move * 20;
|
|
auto ay = co.second - scaffoldy_move * 20;
|
|
if(ax >= 0 && ay >= 0 && ax < 20 && ay < 20)
|
|
draw_scaffold(V);
|
|
break;
|
|
}
|
|
case '>':
|
|
c->wall = draw_digger ? waChasm : waNone;
|
|
break;
|
|
}
|
|
if(with_chess) chess.get_split().render(V, gmod(co.first, 20), gmod(co.second, 20));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ld fov, otanfov;
|
|
|
|
void switch_fpp_fixed() {
|
|
auto& cd = current_display;
|
|
transmatrix tView;
|
|
ld ys;
|
|
|
|
tView = View;
|
|
otanfov = (cd->xsize/2) / cd->radius * 2;
|
|
auto d = vid.depth;
|
|
|
|
if(GDIM == 3) invoke_embed(geom3::seNone);
|
|
else {
|
|
invoke_embed(geom3::seDefault);
|
|
activate(edefault);
|
|
}
|
|
if(GDIM == 3) {
|
|
// pconf.camera_angle = 90;
|
|
|
|
ld tfov = vid.fov * degree / 2;
|
|
cd->tanfov = tan(tfov);
|
|
// tanfov * z + depth = fov
|
|
// z = (fov - depth) / tanfov
|
|
ld yshift = (otanfov - vid.depth) / cd->tanfov;
|
|
// drawthemap();
|
|
// centerpc(INF);
|
|
// shift_view(zpush0(yshift));
|
|
println(hlog, "yshift = ", yshift, " from ", vid.yshift);
|
|
// playermoved = false;
|
|
// vid.fov = fov;
|
|
// vid.yshift = yshift;
|
|
View = Id;
|
|
for(int a=0; a<2; a++)
|
|
for(int b=0; b<2; b++)
|
|
View[a][b] = tView[a][b];
|
|
for(int a=0; a<2; a++)
|
|
View[a][3] = tView[a][2];
|
|
println(hlog, tie(tView[2][0], tView[2][1]));
|
|
// rotate_view(cspin90(2, 1));
|
|
shift_view(zpush0(yshift));
|
|
playermoved = false;
|
|
}
|
|
else {
|
|
pconf.camera_angle = 0;
|
|
vid.yshift = 0;
|
|
ys = tView[2][3];
|
|
println(hlog, "ys = ", ys, " from ", tView);
|
|
otanfov = ys * cd->tanfov + d;
|
|
cd->radius = cd->xsize / otanfov;
|
|
pconf.scale = cd->radius / cd->scrsize;
|
|
}
|
|
if(GDIM == 2) {
|
|
View = spin90() * View;
|
|
View[0][2] = tView[0][3];
|
|
View[1][2] = tView[1][3];
|
|
}
|
|
}
|
|
|
|
void load_anim(string fname) {
|
|
fhstream f(fname, "r");
|
|
mapstream::cellbyid = ac;
|
|
while(isize(mapstream::cellbyid) < 400 * 400) for(auto c: ac) mapstream::cellbyid.push_back(c);
|
|
smoothcam::enable();
|
|
smoothcam::load_animation(f);
|
|
}
|
|
|
|
void append_anim(string fname) {
|
|
smoothcam::backup();
|
|
load_anim(fname);
|
|
smoothcam::append_backup();
|
|
}
|
|
|
|
void save_anim(string fname) {
|
|
fhstream f(fname, "w");
|
|
for(int i=0; i<isize(ac); i++) mapstream::cellids[ac[i]] = i;
|
|
smoothcam::save_animation(f);
|
|
}
|
|
|
|
void transition(ld a, ld b, int frames) {
|
|
anims::noframes = frames;
|
|
|
|
auto _edok = edok();
|
|
auto cu = current();
|
|
auto vn = glhr::vnear_default;
|
|
auto vf = glhr::vfar_default;
|
|
|
|
int lev = addHook(anims::hooks_anim, 100, [&] {
|
|
ld t = ticks / anims::period;
|
|
println(hlog, "transition, t = ", t);
|
|
indenter ind(2);
|
|
t = t * t * (3 - 2 * t);
|
|
t = lerp(a, b, t);
|
|
sightranges[geometry] = 50 * t;
|
|
glhr::vnear_default = vn * t;
|
|
glhr::vfar_default = vf * t;
|
|
activate(lerp(_edok, cu, t));
|
|
});
|
|
anims::record_video();
|
|
delHook(anims::hooks_anim, lev);
|
|
activate(cu);
|
|
sightranges[geometry] = 50;
|
|
glhr::vnear_default = vn;
|
|
glhr::vfar_default = vf;
|
|
}
|
|
|
|
void animate_forward(ld d, int frames) {
|
|
anims::noframes = frames;
|
|
|
|
ld lastt = 0;
|
|
|
|
int lev = addHook(anims::hooks_anim, 100, [&] {
|
|
println(hlog, "centerover is ", centerover);
|
|
ld t = ticks / anims::period;
|
|
t = t * t * (3 - 2 * t);
|
|
shift_view(ztangent(-(t - lastt) * d));
|
|
lastt = t;
|
|
spinEdge(100);
|
|
anims::moved();
|
|
});
|
|
anims::record_video();
|
|
delHook(anims::hooks_anim, lev);
|
|
}
|
|
|
|
void transition_test(ld t) {
|
|
|
|
auto _edok = edok();
|
|
auto cu = current();
|
|
auto vn = glhr::vnear_default;
|
|
auto vf = glhr::vfar_default;
|
|
|
|
sightranges[geometry] = 50 * t;
|
|
glhr::vnear_default = vn * t;
|
|
glhr::vfar_default = vf * t;
|
|
activate(lerp(_edok, cu, t));
|
|
}
|
|
|
|
void embset_list() {
|
|
cmode = sm::SIDE | sm::MAYDARK;
|
|
gamescreen();
|
|
dialog::init(XLAT("embset list"), 0xFFFFFFFF, 150, 0);
|
|
dialog::start_list(900, 900, '1');
|
|
for(auto& e: embsets) {
|
|
dialog::addItem(e.name, dialog::list_fake_key++);
|
|
dialog::add_action([&e] { activate(e); });
|
|
}
|
|
dialog::end_list();
|
|
dialog::addBack();
|
|
dialog::display();
|
|
}
|
|
|
|
void look_downwards() {
|
|
transmatrix T = View;
|
|
if(GDIM == 3) {
|
|
for(int i=0; i<3; i++) T[i][3] = T[3][i] = 0;
|
|
rotate_view(inverse(T));
|
|
ld x = T[3][0], y = T[3][1];
|
|
shift_view(point31(x+.5, y+.5, 0));
|
|
}
|
|
else {
|
|
for(int i=0; i<2; i++) T[i][2] = T[2][i] = 0;
|
|
rotate_view(inverse(T));
|
|
}
|
|
}
|
|
|
|
void show() {
|
|
cmode = sm::SIDE | sm::MAYDARK;
|
|
gamescreen();
|
|
dialog::init(XLAT("embchess"), 0xFFFFFFFF, 150, 0);
|
|
|
|
if(true) {
|
|
dialog::addItem("2D to 3D", 'a');
|
|
dialog::add_action(switch_fpp_fixed);
|
|
dialog::addItem("look downwards", 'l');
|
|
dialog::add_action(look_downwards);
|
|
}
|
|
if(true) {
|
|
dialog::addItem("save smoothcam animation", 's');
|
|
dialog::add_action([] { save_anim("emb/animation.sav"); });
|
|
}
|
|
if(true) {
|
|
dialog::addItem("load smoothcam animation", 'l');
|
|
dialog::add_action([] { load_anim("emb/animation.sav"); });
|
|
}
|
|
if(true) {
|
|
dialog::addItem("create smoothcam animation", 'c');
|
|
dialog::add_action([] { smoothcam::enable_and_show(); });
|
|
}
|
|
if(true) {
|
|
dialog::addBoolItem("run the animation", smoothcam::animate_on, 'r');
|
|
dialog::add_action([] {
|
|
smoothcam::animate_on = !smoothcam::animate_on;
|
|
smoothcam::last_time = HUGE_VAL;
|
|
});
|
|
}
|
|
if(true) {
|
|
dialog::addBoolItem("animation T0", false, 'a');
|
|
dialog::add_action([] { smoothcam::animate_on = false; smoothcam::handle_animation(0); });
|
|
dialog::addBoolItem("animation T1", false, 'b');
|
|
dialog::add_action([] { smoothcam::animate_on = false; smoothcam::handle_animation(1-1e-7); });
|
|
}
|
|
if(true) {
|
|
dialog::addSelItem("invert walls", fts(vid.wall_height), 'i');
|
|
dialog::add_action([] {
|
|
auto cur = current();
|
|
cur.walls = -cur.walls;
|
|
activate(cur);
|
|
});
|
|
}
|
|
if(true) {
|
|
dialog::addSelItem("closer to default", fts(geom3::euclid_embed_scale), '[');
|
|
dialog::add_action([] {
|
|
activate(lerp(edok(), current(), .99));
|
|
});
|
|
dialog::addSelItem("further from default", fts(geom3::euclid_embed_scale), ']');
|
|
dialog::add_action([] {
|
|
activate(lerp(edok(), current(), 1.01));
|
|
});
|
|
}
|
|
if(true) {
|
|
dialog::addItem("embset list", 'e');
|
|
dialog::add_action_push(embset_list);
|
|
}
|
|
if(true) {
|
|
dialog::addItem("print embset", 'p');
|
|
dialog::add_action([] {
|
|
embset e = current();
|
|
println(hlog, e);
|
|
});
|
|
}
|
|
if(false) {
|
|
dialog::addItem("transition to", 'u');
|
|
dialog::add_action([] { anims::videofile = "transition_to.mp4"; transition(0.01, 1, 60); });
|
|
}
|
|
if(false) {
|
|
dialog::addItem("transition from", 'i');
|
|
dialog::add_action([] { anims::videofile = "transition_from.mp4"; transition(1, 0.01, 60); });
|
|
}
|
|
if(true) {
|
|
static ld dist = 0;
|
|
dialog::addSelItem("measure forward distance", fts(dist), 'f');
|
|
dialog::add_action([] {
|
|
shift_view(ztangent(-0.2));
|
|
spinEdge(100);
|
|
dist += 0.2;
|
|
});
|
|
dialog::addSelItem("go backward", fts(dist), 'b');
|
|
dialog::add_action([] {
|
|
shift_view(ztangent(+0.05));
|
|
spinEdge(100);
|
|
dist += -0.05;
|
|
});
|
|
}
|
|
if(true) {
|
|
dialog::addItem("low range", 'r');
|
|
dialog::add_action([] { vid.cells_drawn_limit = 400; delete_sky(); });
|
|
dialog::addItem("mid range", 't');
|
|
dialog::add_action([] { vid.cells_drawn_limit = 2000; delete_sky(); });
|
|
dialog::addItem("high range", 'y');
|
|
dialog::add_action([] { vid.cells_drawn_limit = 20000; delete_sky(); });
|
|
dialog::addItem("extreme range", 'u');
|
|
dialog::add_action([] { vid.cells_drawn_limit = 200000; delete_sky(); });
|
|
dialog::addBoolItem_action("with models", with_models, 'm');
|
|
dialog::addBoolItem_action("with chess", with_chess, 'h');
|
|
dialog::addSelItem("draw the digger", its(draw_digger), 'g');
|
|
dialog::add_action([] { draw_digger = (1 + draw_digger) % 3; });
|
|
}
|
|
if(true) {
|
|
dialog::addSelItem("scaffolding X", its(scaffoldx), 'X');
|
|
dialog::add_action([] { scaffoldx = (1 + scaffoldx) % 3; });
|
|
dialog::addSelItem("scaffolding Y", its(scaffoldy), 'Y');
|
|
dialog::add_action([] { scaffoldy = (1 + scaffoldy) % 3; });
|
|
dialog::addSelItem("scaffolding B", its(scaffoldb), 'B');
|
|
dialog::add_action([] { scaffoldb = (1 + scaffoldb) % 3; });
|
|
dialog::addSelItem("no floor", ONOFF(no_floor), '<');
|
|
dialog::add_action([] { no_floor = !no_floor; mapeditor::drawplayer = false; build_map(); });
|
|
}
|
|
dialog::addBoolItem("move the cat", mapeditor::drawplayer, 'd');
|
|
dialog::add_action([] {
|
|
move_cat = true;
|
|
game_keys_scroll = false;
|
|
});
|
|
/* println(hlog, "sol = ", sol);
|
|
if(true) {
|
|
dialog::addItem("reset GL", 'r');
|
|
dialog::add_action([] { resetGL(); reset_all_shaders(); });
|
|
} */
|
|
|
|
dialog::addBack();
|
|
dialog::display();
|
|
}
|
|
|
|
void o_key(o_funcs& v) {
|
|
v.push_back(named_dialog("embchess options", show));
|
|
}
|
|
|
|
color_t domcol = 0xf8dba0;
|
|
color_t domcolf = 0x785b20;
|
|
color_t domroof = 0x802020;
|
|
|
|
color_t our_skycolor(cell *c) {
|
|
auto co = euc::full_coords2(c);
|
|
ld x = co.first * TAU / 20;
|
|
ld y = co.second * TAU / 20;
|
|
ld p = sin(x+2*y) + cos(3*x-y) + sin(x);
|
|
return gradient(0x4040FF, 0xFFFFFF, -3, p, 3);
|
|
}
|
|
|
|
bool chess_ceiling(celldrawer *cw) {
|
|
auto co = euc::full_coords2(cw->c);
|
|
if(co == gp::loc{0, 0})
|
|
draw_star(cw->V, cgi.shSun, 0xFFFF00FF);
|
|
if(domek2.count(cw->c)) {
|
|
color_t col = (domcol << 8) | 0xFF;
|
|
color_t wcol1 = (gradient(0, domcol, 0, .9, 1) << 8) | 0xFF;
|
|
color_t wcol2 = (gradient(0, domcol, 0, .8, 1) << 8) | 0xFF;
|
|
if(domek1.count(cw->c)) forCellIdEx(c2, i, cw->c) if(!domek1.count(c2)) {
|
|
placeSidewall(cw->c, i, SIDE_HIGH, cw->V, (i&1)?wcol1:wcol2);
|
|
placeSidewall(cw->c, i, SIDE_HIGH2, cw->V, (i&1)?wcol1:wcol2);
|
|
}
|
|
forCellIdEx(c2, i, cw->c) if(!domek2.count(c2)) {
|
|
placeSidewall(cw->c, i, SIDE_HIGH2, cw->V, (i&1)?wcol1:wcol2);
|
|
}
|
|
if(domek1.count(cw->c) != domek2.count(cw->c))
|
|
draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE_HIGH], col, PPR::REDWALL);
|
|
if(domek2.count(cw->c))
|
|
draw_shapevec(cw->c, cw->V, qfi.fshape->levels[SIDE_HIGH2], (domroof << 8) | 0xFF, PPR::REDWALL);
|
|
|
|
auto co = euc::full_coords2(cw->c);
|
|
int x = gmod(co.first, 20);
|
|
int y = gmod(co.second, 20);
|
|
char ch = xmap[y][x];
|
|
|
|
if(ch == 'O') {
|
|
placeSidewall(cw->c, 1, SIDE_HIGH, cw->V, 0xC0E0FFC0);
|
|
((dqi_poly&)(*ptds.back())).tinf = nullptr;
|
|
}
|
|
}
|
|
|
|
color_t skycol = our_skycolor(cw->c);
|
|
g_add_to_sky(cw->c, cw->V, skycol, skycol);
|
|
return true;
|
|
}
|
|
|
|
int cells_drawn = 50, split_qty = 1;
|
|
|
|
void build_map() {
|
|
for(cell *c: bac) {
|
|
c->land = laCanvas;
|
|
c->wall = waNone; // Chasm; // waNone;
|
|
c->item = itNone;
|
|
c->monst = moNone;
|
|
c->mpdist = 0;
|
|
c->landparam = 0x205020;
|
|
auto co = euc::full_coords2(c);
|
|
int x = gmod(co.first, 20);
|
|
int y = gmod(co.second, 20);
|
|
ac[x + 20*y + gmod(gdiv(co.first, 20), periods) * 400 + gmod(gdiv(co.second, 20), periods) * 400 * periods] = c;
|
|
char ch = xmap[y][x];
|
|
switch(ch) {
|
|
case 'x':
|
|
c->landparam = ((x+y) & 1) ? 0x807020 : 0xFFE080;
|
|
break;
|
|
case '1':
|
|
c->wall = waRed3;
|
|
domek2.insert(c);
|
|
c->landparam = domcol;
|
|
break;
|
|
case '2':
|
|
c->wall = waRed2;
|
|
break;
|
|
case '3':
|
|
c->wall = waRed3;
|
|
break;
|
|
case '#':
|
|
c->wall = waBarrier;
|
|
break;
|
|
case 'T':
|
|
c->wall = waCTree;
|
|
break;
|
|
case 'D':
|
|
c->wall = waWaxWall;
|
|
domek1.insert(c);
|
|
domek2.insert(c);
|
|
c->landparam = domcol;
|
|
break;
|
|
case 't':
|
|
case 'r':
|
|
case 'd':
|
|
c->wall = waNone;
|
|
domek2.insert(c);
|
|
c->landparam = domcolf;
|
|
break;
|
|
case '+':
|
|
c->wall = waNone;
|
|
domek2.insert(c);
|
|
c->landparam = domcol;
|
|
break;
|
|
case 'O':
|
|
c->wall = waWaxWall;
|
|
domek2.insert(c);
|
|
c->landparam = domcol;
|
|
break;
|
|
case 'u':
|
|
case 'v':
|
|
case '~':
|
|
c->wall = waShallow;
|
|
break;
|
|
case 'p':
|
|
c->land = laCrossroads;
|
|
floorcolors[laCrossroads] = 0x808080;
|
|
break;
|
|
// c->landparam = 0xC0C080;
|
|
case '>':
|
|
if(draw_digger) c->wall = waChasm;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void enable() {
|
|
arg::shift(); hmul = arg::argf();
|
|
|
|
stop_game();
|
|
never_invert = true;
|
|
vid.wallmode = 3;
|
|
vid.monmode = 2;
|
|
|
|
geometry = gArchimedean;
|
|
variation = eVariation::pure;
|
|
arcm::current.parse("4^5");
|
|
start_game();
|
|
resetview();
|
|
View = spin(45._deg);
|
|
if(1) {
|
|
dynamicval<int> d(min_cells_drawn, cells_drawn);
|
|
// vid.cells_generated_limit = 9999;
|
|
// vid.cells_drawn_limit = 9999;
|
|
// vid.use_smart_range = 2;
|
|
drawthemap();
|
|
}
|
|
auto f = [] (hyperpoint h) { return deparabolic13(h); };
|
|
|
|
|
|
set<cell*> seen;
|
|
for(auto c: dcal) if(gmatrix.count(c)) {
|
|
map54_nodes.push_back(f(unshift(gmatrix[c]*C0)));
|
|
seen.insert(c);
|
|
}
|
|
for(auto c: dcal) if(seen.count(c)) forCellEx(c1, c) if(seen.count(c1)) if(c1<c) {
|
|
auto h = unshift(gmatrix[c]*C0);
|
|
auto h1 = unshift(gmatrix[c1]*C0);
|
|
int qty = split_qty;
|
|
vector<hyperpoint> hs(qty+1);
|
|
hs[0] = h; hs[qty] = h1;
|
|
for(int a=qty/2; a; a/=2) for(int i=0; i<qty; i+=a*2) hs[i+a] = mid(hs[i], hs[i+2*a]);
|
|
for(int i=0; i<=qty; i++) hs[i] = f(hs[i]);
|
|
for(int i=0; i<qty; i++) map54_edges.emplace_back(hs[i], hs[i+1]);
|
|
}
|
|
println(hlog, "map54: nodes = ", isize(map54_nodes), " edges = ", isize(map54_edges));
|
|
stop_game();
|
|
|
|
geometry = gSpace435;
|
|
start_game();
|
|
resetview();
|
|
if(1) {
|
|
dynamicval<int> d(min_cells_drawn, 500);
|
|
drawthemap();
|
|
bfs();
|
|
println(hlog, "dcal size = ", isize(dcal), " size map = ", isize(gmatrix));
|
|
}
|
|
seen.clear();
|
|
for(auto c: dcal) if(gmatrix.count(c)) {
|
|
map534_nodes.push_back(unshift(gmatrix[c]*C0));
|
|
seen.insert(c);
|
|
}
|
|
for(auto c: dcal) if(seen.count(c)) forCellEx(c1, c) if(seen.count(c1)) if(c1<c) {
|
|
map534_edges.emplace_back(unshift(gmatrix[c])*C0, unshift(gmatrix[c1])*C0);
|
|
}
|
|
stop_game();
|
|
// vid.cells_drawn_limit = 400;
|
|
|
|
if(!floor_textures) make_floor_textures();
|
|
|
|
auto& T0 = euc::eu_input.user_axes;
|
|
T0[0][0] = 20 * periods;
|
|
T0[1][1] = 20 * periods;
|
|
euc::eu_input.twisted = 0;
|
|
T0[0][1] = 0;
|
|
T0[1][0] = 0;
|
|
euc::build_torus3();
|
|
geometry = gEuclidSquare;
|
|
variation = eVariation::pure;
|
|
start_game();
|
|
|
|
bac = currentmap->allcells();
|
|
ac.resize(bac.size());
|
|
build_map();
|
|
|
|
rogueviz::rv_hook(hooks_drawcell, 100, draw_chess_at);
|
|
// rogueviz::rv_hook(hooks_frame, 100, [] { restart = true; });
|
|
rogueviz::rv_hook(hooks_ceiling, 100, chess_ceiling);
|
|
rogueviz::rv_hook(hooks_o_key, 80, o_key);
|
|
rogueviz::rv_hook(hooks_handleKey, 101, [] (int sym, int uni) {
|
|
if((cmode & sm::NORMAL) && uni == 't') {
|
|
vid.sspeed = 0;
|
|
playermoved = true;
|
|
fix_whichcopy(cwt.at);
|
|
// game_keys_scroll = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
|
|
frustum_culling = false;
|
|
game_keys_scroll = true;
|
|
bright = true;
|
|
draw_sky = skyAlways;
|
|
vid.cells_generated_limit = 9999;
|
|
noshadow = true;
|
|
auto_remove_roofs = false;
|
|
vid.lake_top = 0.2;
|
|
simple_sky = true;
|
|
}
|
|
|
|
struct solv_grapher : rogueviz::pres::grapher {
|
|
|
|
solv_grapher(transmatrix U) : grapher(-2, -2, 12, 12) {
|
|
T = T * U;
|
|
using rogueviz::pres::p2;
|
|
|
|
for(int x=-1; x<=11; x++) if(x) {
|
|
line(p2(x,-2), p2(x,12), 0x8080FFFF);
|
|
line(p2(-2,x), p2(12,x), 0x8080FFFF);
|
|
}
|
|
|
|
vid.linewidth *= 2;
|
|
arrow(p2(0,-2), p2(0,12), .5);
|
|
arrow(p2(-2,0), p2(12,0), .5);
|
|
vid.linewidth /= 2;
|
|
}
|
|
};
|
|
|
|
ld geo_zero;
|
|
|
|
transmatrix xyzscale(ld x) {
|
|
transmatrix T = Id;
|
|
T[0][0] = T[1][1] = T[2][2] = x;
|
|
return T;
|
|
}
|
|
|
|
transmatrix solvscale(ld x) {
|
|
transmatrix T = Id;
|
|
T[0][0] *= exp(-x);
|
|
T[1][1] *= exp(x);
|
|
return T;
|
|
}
|
|
|
|
ld geodesic_t = 0;
|
|
|
|
void geodesic_screen(tour::presmode mode, int id) {
|
|
if(!params.count("geodesic_t")) param_f(geodesic_t, "geodesic_t");
|
|
using namespace rogueviz::pres;
|
|
if(mode == pmStart) geo_zero = ticks;
|
|
|
|
use_angledir(mode, id == 0);
|
|
|
|
static hyperpoint start, middle, target, nlh, nlh1, nlh2;
|
|
const ld coord = 10;
|
|
|
|
setCanvas(mode, '0');
|
|
if(mode == pmStart) {
|
|
slide_backup(pmodel);
|
|
slide_backup(pconf.clip_min);
|
|
slide_backup(pconf.clip_max);
|
|
slide_backup(vid.cells_drawn_limit);
|
|
stop_game(), pmodel = mdHorocyclic, geometry = gCubeTiling, variation = eVariation::pure, pconf.clip_min = -10000, pconf.clip_max = +100, start_game();
|
|
|
|
dynamicval<eGeometry> dg(geometry, gSol);
|
|
dynamicval<int> dr(nisot::rk_steps, 500);
|
|
ld x = coord;
|
|
start = C0;
|
|
middle = point31(0, x, 0);
|
|
auto bmiddle = point31(x, 0, 0);
|
|
target = point31(x, x, 0);
|
|
nlh = inverse_exp_newton(target, 200);
|
|
nlh[2] *= -1;
|
|
println(hlog, "best newton: ", hypot_d(3, nlh), " via ", nlh, " result ", nisot::numerical_exp(nlh));
|
|
nlh1 = inverse_exp(shiftless(middle));
|
|
nlh2 = inverse_exp(shiftless(bmiddle));
|
|
println(hlog, "intermediate: ", hypot_d(3, nlh1) * 2, " via ", nlh1);
|
|
println(hlog, "Pythagoras: ", x * sqrt(2));
|
|
}
|
|
|
|
add_stat(mode, [id, coord] {
|
|
cmode |= sm::SIDE;
|
|
calcparam();
|
|
|
|
vid.cells_drawn_limit = 0;
|
|
drawthemap();
|
|
|
|
// flat_model_enabler fme;
|
|
initquickqueue();
|
|
|
|
solv_grapher g(MirrorZ * ypush(5 * angle / 90._deg) * cspin(1, 2, .9 * angle / 90._deg) * spin(angle/2) * xyzscale(lerp(1, 0.8, angle / 90._deg)));
|
|
|
|
ld maxtime = 10 * sqrt(2) + 5;
|
|
auto frac_of = [&] (ld t, ld z) { return t - z * floor(t/z); };
|
|
|
|
ld t = inHighQual ? geodesic_t : frac_of((ticks - geo_zero) / 500, maxtime);
|
|
|
|
auto draw_path = [&] (auto f, color_t col) {
|
|
vid.linewidth *= 10;
|
|
for(ld t=0; t<=maxtime; t+=1/16.) curvepoint(f(t));
|
|
queuecurve(g.T, col, 0, PPR::LINE);
|
|
|
|
auto be_shadow = [&] (hyperpoint& h) {
|
|
// ld part = 1 - angle / 90._deg;
|
|
// h[0] += h[2] * part / 10;
|
|
h[2] = 0;
|
|
};
|
|
|
|
for(ld t=0; t<=25; t+=1/16.) {
|
|
hyperpoint h = f(t);
|
|
be_shadow(h);
|
|
curvepoint(h);
|
|
}
|
|
queuecurve(g.T, col & 0xFFFFFF40, 0, PPR::LINE);
|
|
vid.linewidth /= 10;
|
|
|
|
hyperpoint eaglepos = f(t);
|
|
hyperpoint next_eaglepos = f(t + 1e-2);
|
|
|
|
auto z = eaglepos[2];
|
|
|
|
// queuepolyat(g.pos(x+z * .1,y,1.5) * spin(s), cgi.shEagle, 0x40, PPR::MONSTER_SHADOW).outline = 0;
|
|
drawMonsterType(moEagle, nullptr, g.T * eupush(eaglepos) * solvscale(z) * rspintox(next_eaglepos - eaglepos) * xyzscale(2), col >> 8, t, 0);
|
|
|
|
be_shadow(eaglepos);
|
|
be_shadow(next_eaglepos);
|
|
|
|
auto& bp = cgi.shEagle;
|
|
|
|
if(bp.she > bp.shs && bp.she < bp.shs + 1000) {
|
|
auto& p = queuepolyat(g.T * eupush(eaglepos) * solvscale(z) * rspintox(next_eaglepos - eaglepos) * xyzscale(2), bp, 0x18, PPR::TRANSPARENT_SHADOW);
|
|
p.outline = 0;
|
|
p.subprio = -100;
|
|
p.offset = bp.shs;
|
|
p.cnt = bp.she - bp.shs;
|
|
p.flags &=~ POLY_TRIANGLES;
|
|
p.tinf = NULL;
|
|
return;
|
|
}
|
|
};
|
|
|
|
color_t pythagoras = 0xcd7f32FF;
|
|
color_t hyperb = 0xaaa9adFF;
|
|
color_t solv = 0xFFD500FF;
|
|
|
|
write_in_space(g.T * rgpushxto0(point31(-.5, -.5, 1)) * MirrorY * zpush(-1), 72, 1, "A", 0xFF);
|
|
write_in_space(g.T * rgpushxto0(point31(coord+.5, coord+.5, 1)) * MirrorY * zpush(-1), 72, 1, "B", 0xFF);
|
|
if(id >= 1) write_in_space(g.T * rgpushxto0(point31(0, coord+.5, 1)) * MirrorY * zpush(-1), 72, 1, "C", 0xFF);
|
|
|
|
if(id >= 0)
|
|
draw_path([&] (ld t) { return t < coord * sqrt(2) ? point31(t/sqrt(2), t/sqrt(2), 0) : target; }, pythagoras);
|
|
|
|
if(id >= 1)
|
|
draw_path([&] (ld t) {
|
|
ld len = hypot_d(3, nlh1);
|
|
dynamicval<eGeometry> g(geometry, gSol);
|
|
if(t < len)
|
|
return nisot::numerical_exp(nlh1 * t / len);
|
|
else if(t < len*2)
|
|
return rgpushxto0(middle) * nisot::numerical_exp(nlh2 * (t-len) / len);
|
|
else return target;
|
|
}, hyperb);
|
|
|
|
if(id >= 2)
|
|
draw_path([&] (ld t) {
|
|
ld len = hypot_d(3, nlh);
|
|
dynamicval<eGeometry> g(geometry, gSol);
|
|
if(t < len)
|
|
return nisot::numerical_exp(nlh * t / len);
|
|
else
|
|
return target;
|
|
}, solv);
|
|
|
|
auto cat = [] (PPR x) {
|
|
if(x == PPR::MONSTER_SHADOW) return 1;
|
|
else if(x == PPR::MONSTER_BODY) return 2;
|
|
else return 0;
|
|
};
|
|
|
|
for(int i=1; i<isize(ptds);)
|
|
if(i && cat(ptds[i]->prio) < cat(ptds[i-1]->prio)) {
|
|
swap(ptds[i], ptds[i-1]);
|
|
i--;
|
|
}
|
|
else i++;
|
|
|
|
quickqueue();
|
|
|
|
dialog::init();
|
|
dialog_may_latex("\\textsf{from $(0,0,0)$ to $(10,10,0)$}", "from (0,0,0) to (10,10,0)", forecolor, 150);
|
|
|
|
dialog::addBreak(100);
|
|
dialog_may_latex("\\textsf{XY plane}", "XY plane", pythagoras >> 8);
|
|
dialog_may_latex("\\textsf{$"+fts(coord)+"\\sqrt{2}$ (Pythagoras)}", fts(coord) + "√2 (Pythagoras)", pythagoras >> 8);
|
|
ld len = coord * sqrt(2);
|
|
dialog_may_latex("\\textsf{$" + fts(len) + "$}", fts(len), pythagoras >> 8);
|
|
|
|
if(id >= 1) {
|
|
dialog::addBreak(100);
|
|
dialog_may_latex("\\textsf{YZ + XZ}", "YZ + XZ", hyperb >> 8);
|
|
dialog_may_latex("\\textsf{hyperbolic geodesics}", "hyperbolic geodesics", hyperb >> 8);
|
|
ld len = 2 * hypot_d(3, nlh1);
|
|
dialog_may_latex("\\textsf{$" + fts(len) + "$}", fts(len), hyperb >> 8);
|
|
}
|
|
else dialog::addBreak(300);
|
|
|
|
if(id >= 2) {
|
|
dialog::addBreak(100);
|
|
dialog_may_latex("\\textsf{optimal}", "optimal", solv >> 8);
|
|
dialog_may_latex("\\textsf{no sharp bends}", "no sharp bends", solv >> 8);
|
|
ld len = hypot_d(3, nlh);
|
|
dialog_may_latex("\\textsf{$"+fts(len)+"$}", fts(len), solv >> 8);
|
|
}
|
|
else dialog::addBreak(300);
|
|
|
|
dialog::display();
|
|
|
|
return false;
|
|
});
|
|
}
|
|
|
|
ld square_diagram_size = 10;
|
|
|
|
void enable_square_diagram() {
|
|
param_f(square_diagram_size, "square_diagram_size");
|
|
rogueviz::rv_hook(hooks_frame, 100, [] {
|
|
auto p = [] (ld x, ld y) { return hpxy(x, y); };
|
|
for(int i=0; i<4; i++) {
|
|
ld si = square_diagram_size;
|
|
ld big = 100;
|
|
curvepoint(p(si, big));
|
|
curvepoint(p(si, -big));
|
|
curvepoint(p(big, -big));
|
|
curvepoint(p(big, big));
|
|
curvepoint(p(si, big));
|
|
queuecurve(shiftless(Id) * cspin(0, 1, i*90._deg), 0, 0xFF, PPR::CIRCLE).flags |= POLY_ALWAYS_IN;
|
|
}
|
|
});
|
|
}
|
|
|
|
using namespace rogueviz::pres;
|
|
|
|
string defs =
|
|
"\\def\\map{m}"
|
|
"\\def\\VofH{V}"
|
|
"\\def\\dist{\\delta}"
|
|
"\\def\\ra{\\rightarrow}"
|
|
"\\def\\bbH{\\mathbb{H}}"
|
|
"\\def\\bbE{\\mathbb{E}}"
|
|
"\\renewcommand{\\rmdefault}{\\sfdefault}\\sf"
|
|
;
|
|
|
|
slide solv_slides[] = {
|
|
{"from A to B in Solv 1", 999, LEGAL::NONE | QUICKGEO | NOTITLE,
|
|
"not written"
|
|
,
|
|
[] (presmode mode) {
|
|
println(hlog, "A mode ", int(mode));
|
|
empty_screen(mode);
|
|
geodesic_screen(mode, 0);
|
|
no_other_hud(mode);
|
|
}
|
|
},
|
|
{"from A to B in Solv 2", 999, LEGAL::NONE | QUICKGEO | NOTITLE,
|
|
"not written"
|
|
,
|
|
[] (presmode mode) {
|
|
println(hlog, "B mode ", int(mode));
|
|
empty_screen(mode);
|
|
geodesic_screen(mode, 1);
|
|
no_other_hud(mode);
|
|
}
|
|
},
|
|
{"from A to B in Solv 3", 999, LEGAL::NONE | QUICKGEO | NOTITLE,
|
|
"not written"
|
|
,
|
|
[] (presmode mode) {
|
|
println(hlog, "C mode ", int(mode));
|
|
empty_screen(mode);
|
|
geodesic_screen(mode, 2);
|
|
no_other_hud(mode);
|
|
}
|
|
},
|
|
|
|
{"Euler's polyhedron formula", 999, LEGAL::NONE | QUICKGEO | USE_SLIDE_NAME | NOTITLE,
|
|
"-show the formula",
|
|
[] (presmode mode) {
|
|
latex_slide(mode, defs+R"=(
|
|
{\color{remph}Euler's polyhedron formula: }
|
|
\begin{itemize}
|
|
\item $F+V-E = 2$
|
|
\item $F$ -- the number of {\color{remph}faces} (square grid: the number of squares $n$)
|
|
\item $V$ -- the number of {\color{remph}vertices} (square grid: also $n$)
|
|
\item $E$ -- the number of {\color{remph}edges} (square grid: $2n$)
|
|
\item $F + V - E = n + n - 2n = 0 = 2$
|
|
\end{itemize}
|
|
)=", sm::NOSCR, 150);
|
|
}},
|
|
|
|
{"final slide", 123, LEGAL::ANY | NOTITLE | QUICKSKIP | FINALSLIDE,
|
|
"FINAL SLIDE",
|
|
|
|
[] (presmode mode) {
|
|
empty_screen(mode);
|
|
add_stat(mode, [] {
|
|
dialog::init();
|
|
color_t d = dialog::dialogcolor;
|
|
|
|
dialog::addTitle("Thanks for your attention!", 0xC00000, 200);
|
|
|
|
dialog::addBreak(100);
|
|
|
|
dialog::addTitle("twitter.com/zenorogue/", d, 150);
|
|
|
|
dialog::display();
|
|
return true;
|
|
});
|
|
no_other_hud(mode);
|
|
}
|
|
},
|
|
};
|
|
|
|
auto embchess_ah =
|
|
arg::add3("-embchess", enable)
|
|
+ arg::add3("-embperiods", [] { arg::shift(); periods = arg::argi(); })
|
|
+ arg::add3("-emb-noceil", [] {
|
|
rogueviz::rv_hook(hooks_ceiling, 100, [] (celldrawer*) { return true; });
|
|
})
|
|
+ arg::add3("-chessmul", [] { arg::shift(); hmul = arg::argf(); })
|
|
+ arg::add3("-embset", [] {
|
|
arg::shift(); string ss = arg::args();
|
|
for(auto& e: embsets) if(appears(e.name, ss)) activate(e);
|
|
})
|
|
+ arg::add3("-embscaffold", [] {
|
|
arg::shift(); scaffoldx = arg::argi();
|
|
arg::shift(); scaffoldy = arg::argi();
|
|
arg::shift(); scaffoldb = arg::argi();
|
|
})
|
|
+ arg::add3("-embscaffold-move", [] {
|
|
arg::shift(); scaffoldx_move = arg::argi();
|
|
arg::shift(); scaffoldy_move = arg::argi();
|
|
})
|
|
+ arg::add3("-embwchess", [] { with_chess = !with_chess; })
|
|
+ arg::add3("-embfix", [] { arg::shift(); fix_chess = arg::argf(); })
|
|
+ arg::add3("-embwmodel", [] { with_models = !with_models; })
|
|
+ arg::add3("-embwmlight", [] { with_models = true; light_models = true; })
|
|
+ arg::add3("-embwdig", [] { arg::shift(); draw_digger = arg::argi(); })
|
|
+ arg::add3("-embload", [] { arg::shift(); load_anim(arg::args()); })
|
|
+ arg::add3("-embappend", [] { arg::shift(); append_anim(arg::args()); })
|
|
+ arg::add3("-embsave", [] { arg::shift(); save_anim(arg::args()); })
|
|
+ arg::add3("-embt0", [] { smoothcam::animate_on = false; smoothcam::handle_animation(0); playermoved = false; })
|
|
+ arg::add3("-embt1", [] { smoothcam::animate_on = false; smoothcam::handle_animation(1-1e-7); playermoved = false; })
|
|
+ arg::add3("-embmin", [] { arg::shift(); cells_drawn = arg::argi(); })
|
|
+ arg::add3("-emb-chess-moves", [] { arg::shift(); chess_moves = arg::argi(); })
|
|
+ arg::add3("-emb-sqd", enable_square_diagram)
|
|
+ arg::add3("-embtrans-test", [] { arg::shift(); transition_test(arg::argf()); })
|
|
+ arg::add3("-emb-no-floor", [] { no_floor = true; })
|
|
+ arg::add3("-embtrans", [] {
|
|
arg::shift(); anims::videofile = arg::args();
|
|
arg::shift(); ld a = arg::argf();
|
|
arg::shift(); ld b = arg::argf();
|
|
arg::shift(); int t = arg::argi();
|
|
transition(a, b, t);
|
|
})
|
|
+ arg::add3("-avp", [] { semidirect_rendering = true; vid.consider_shader_projection = false; })
|
|
+ arg::add3("-embforward", [] {
|
|
arg::shift(); int t = arg::argi();
|
|
arg::shift(); anims::videofile = arg::args();
|
|
arg::shift(); ld d = arg::argf();
|
|
animate_forward(d, t);
|
|
})
|
|
+ arg::add3("-emb-goforward", [] {
|
|
arg::shift(); ld d = arg::argf();
|
|
for(int i=0; i<1000; i++) {
|
|
shift_view(ztangent(-d / 1000.));
|
|
optimizeview();
|
|
spinEdge(100);
|
|
}
|
|
});
|
|
;
|
|
|
|
auto embchess_show =
|
|
addHook_slideshows(100, [] (tour::ss::slideshow_callback cb) {
|
|
cb(XLAT("Solv geodesics"), &solv_slides[0], 'S');
|
|
});
|
|
}}
|