1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-24 01:00:25 +00:00

3d models in product space

This commit is contained in:
Zeno Rogue 2019-08-18 13:05:47 +02:00
parent 00f4f4fca5
commit fb0f5872c8
8 changed files with 111 additions and 56 deletions

View File

@ -30,10 +30,15 @@ vector<hyperpoint> geometry_information::get_shape(hpcshape sh) {
return res;
}
hyperpoint normalize_flat(hyperpoint h) {
if(prod) return product_decompose(h).second;
return normalize(h);
}
hyperpoint get_center(const vector<hyperpoint>& vh) {
hyperpoint h = Hypc;
for(auto h1: vh) h = h + h1;
return normalize(h);
return normalize_flat(h);
}
ld zc(ld z) {
@ -125,7 +130,7 @@ void geometry_information::add_texture(hpcshape& sh) {
vector<hyperpoint> scaleshape(const vector<hyperpoint>& vh, ld s) {
vector<hyperpoint> res;
for(hyperpoint h: vh) res.push_back(normalize(h * s + shcenter * (1-s)));
for(hyperpoint h: vh) res.push_back(normalize_flat(h * s + shcenter * (1-s)));
return res;
}
@ -326,8 +331,8 @@ void geometry_information::make_armor_3d(hpcshape& sh, int kind) {
for(hyperpoint h: body) {
array<ld, 2> p;
p[0] = h[0] / h[3];
p[1] = h[1] / h[3];
p[0] = h[0] / h[LDIM];
p[1] = h[1] / h[LDIM];
pts[0].emplace_back(p);
}
@ -394,8 +399,8 @@ void geometry_information::make_head_3d(hpcshape& sh) {
for(hyperpoint h: head) {
array<ld, 2> p;
p[0] = h[0] / h[3];
p[1] = h[1] / h[3];
p[0] = h[0] / h[LDIM];
p[1] = h[1] / h[LDIM];
pts[0].emplace_back(p);
}
@ -476,6 +481,11 @@ void geometry_information::make_skeletal(hpcshape& sh, ld push) {
shift_last(-push);
}
hyperpoint yzspin(ld alpha, hyperpoint h) {
if(prod) return product::direct_exp(cspin(1, 2, alpha) * product::inverse_exp(h));
else return cspin(1, 2, alpha) * h;
}
void geometry_information::make_revolution(hpcshape& sh, int mx, ld push) {
auto body = get_shape(sh);
bshape(sh, PPR::MONSTER_BODY);
@ -484,12 +494,12 @@ void geometry_information::make_revolution(hpcshape& sh, int mx, ld push) {
hyperpoint h0 = body[i];
hyperpoint h1 = body[(i+1) % isize(body)];
for(int s=0; s<mx; s+=step) {
hpcpush(cspin(1, 2, s * degree) * h0);
hpcpush(cspin(1, 2, s * degree) * h1);
hpcpush(cspin(1, 2, (s+step) * degree) * h0);
hpcpush(cspin(1, 2, s * degree) * h1);
hpcpush(cspin(1, 2, (s+step) * degree) * h0);
hpcpush(cspin(1, 2, (s+step) * degree) * h1);
hpcpush(yzspin(s * degree, h0));
hpcpush(yzspin(s * degree, h1));
hpcpush(yzspin((s+step) * degree, h0));
hpcpush(yzspin(s * degree, h1));
hpcpush(yzspin((s+step) * degree, h0));
hpcpush(yzspin((s+step) * degree, h1));
}
}
last->flags |= POLY_TRIANGLES;
@ -537,7 +547,7 @@ void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push,
for(int i=0; i<n; i++) if(!stillin[i] && !stillin[lastid[i]]) lastid[i] = lastid[lastid[i]];
for(int i=0; i<n; i++) {
if(!stillin[i]) gbody[i] = normalize(gbody[lastid[i]] * (i - lastid[i]) + gbody[nextid[i]] * (nextid[i] - i));
if(!stillin[i]) gbody[i] = normalize_flat(gbody[lastid[i]] * (i - lastid[i]) + gbody[nextid[i]] * (nextid[i] - i));
}
bshape(sh, PPR::MONSTER_BODY);
@ -551,12 +561,12 @@ void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push,
hyperpoint h1 = tbody[i1];
hyperpoint hs0 = nbody[i];
hyperpoint hs1 = nbody[i1];
hpcpush(cspin(1, 2, s * degree) * h0);
hpcpush(cspin(1, 2, s * degree) * h1);
hpcpush(cspin(1, 2, (s+step) * degree) * hs0);
hpcpush(cspin(1, 2, s * degree) * h1);
hpcpush(cspin(1, 2, (s+step) * degree) * hs0);
hpcpush(cspin(1, 2, (s+step) * degree) * hs1);
hpcpush(yzspin(s * degree, h0));
hpcpush(yzspin(s * degree, h1));
hpcpush(yzspin((s+step) * degree, hs0));
hpcpush(yzspin(s * degree, h1));
hpcpush(yzspin((s+step) * degree, hs0));
hpcpush(yzspin((s+step) * degree, hs1));
}
}
last->flags |= POLY_TRIANGLES;
@ -600,26 +610,40 @@ void geometry_information::animate_bird(hpcshape& orig, hpcshape_animated& anima
// shift_shape(orig, BIRD);
}
EX hyperpoint forward_dir(ld x) { return prod ? point3(x, 0, 0) : xpush0(x); }
EX hyperpoint dir_to_point(hyperpoint h) { return prod ? product::direct_exp(h) : h; }
EX hyperpoint dir_setlength(hyperpoint dir, ld length) {
if(dir[0] == 0 && dir[1] == 0 && dir[2] == 0) return dir;
if(prod) return dir * (length / hypot_d(3, dir));
return rspintox(dir) * xpush0(length);
}
void geometry_information::slimetriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev) {
dynamicval<int> d(vid.texture_step, 8);
texture_order([&] (ld x, ld y) {
ld z = 1-x-y;
ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8);
hyperpoint h = rspintox(a*x+b*y+c*z) * xpush0(r);
ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8) * (prod ? .5 : 1);
hyperpoint h = dir_to_point(dir_setlength(a*x+b*y+c*z, r));
hpcpush(h);
});
}
void geometry_information::balltriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev) {
if(lev == 0) {
hpcpush(a);
hpcpush(b);
hpcpush(c);
hpcpush(dir_to_point(a));
hpcpush(dir_to_point(b));
hpcpush(dir_to_point(c));
}
else {
hyperpoint cx = rspintox(mid(a,b)) * xpush0(rad);
hyperpoint ax = rspintox(mid(b,c)) * xpush0(rad);
hyperpoint bx = rspintox(mid(c,a)) * xpush0(rad);
auto midpoint = [&] (hyperpoint h1, hyperpoint h2) {
if(prod) return dir_setlength(h1+h2, rad);
else return rspintox(mid(h1,h2)) * xpush0(rad);
};
hyperpoint cx = midpoint(a, b);
hyperpoint ax = midpoint(b, c);
hyperpoint bx = midpoint(c, a);
balltriangle(ax, bx, cx, rad, lev-1);
balltriangle(ax, bx, c , rad, lev-1);
balltriangle(ax, b , cx, rad, lev-1);
@ -630,8 +654,8 @@ void geometry_information::balltriangle(hyperpoint a, hyperpoint b, hyperpoint c
void geometry_information::make_ball(hpcshape& sh, ld rad, int lev) {
bshape(sh, sh.prio);
sh.flags |= POLY_TRIANGLES;
hyperpoint tip = xpush0(rad);
hyperpoint atip = xpush0(-rad);
hyperpoint tip = forward_dir(rad);
hyperpoint atip = forward_dir(-rad);
ld z = 63.43 * degree;
for(int i=0; i<5; i++) {
hyperpoint a = cspin(1, 2, (72 * i ) * degree) * spin(z) * tip;
@ -691,7 +715,13 @@ void geometry_information::make_euclidean_sky() {
);
}
/** res[0] and res[1] place H on the plane, while res[2] is the altitude */
hyperpoint psmin(hyperpoint H) {
if(prod) {
auto d = product_decompose(H);
d.second[2] = d.first;
return d.second;
}
hyperpoint res;
res[2] = asin_auto(H[2]);
ld cs = pow(cos_auto(res[2]), 2);
@ -704,7 +734,7 @@ hyperpoint psmin(hyperpoint H) {
void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye, ld shift_head, int q, ld zoom) {
hyperpoint center = Hypc;
for(int i=eye.s; i<eye.e; i++) if(q == 1 || hpc[i][1] > 0) center += hpc[i];
center = normalize(center);
center = normalize_flat(center);
// center /= (eye.e - eye.s);
ld rad = 0;
for(int i=eye.s; i<eye.e; i++) if(q == 1 || hpc[i][1] > 0) rad += hdist(center, hpc[i]);
@ -724,7 +754,7 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye
zmid /= isize(pss);
ld mindist = 1e9;
for(int i=0; i<isize(pss); i+=3) if(pss[i][2] < zmid || WDIM == 3) {
for(int i=0; i<isize(pss); i+=3) if(prod ? pss[i][2] > zmid : (pss[i][2] < zmid || (WDIM == 3 && !prod))) {
ld d = sqhypot_d(2, pss[i]-pscenter) + sqhypot_d(2, pss[i+1]-pscenter) + sqhypot_d(2, pss[i+2]-pscenter);
if(d < mindist) mindist = d, pos = min(min(pss[i][2], pss[i+1][2]), pss[i+2][2]), qty++;
qtyall++;
@ -1086,10 +1116,10 @@ void geometry_information::make_3d_models() {
hyperpoint atip = xpush0(-1);
ld z = 63.43 * degree;
for(int i=0; i<5; i++) {
auto a = cspin(1, 2, (72 * i ) * degree) * spin(z) * xpush0(1);
auto b = cspin(1, 2, (72 * i-72) * degree) * spin(z) * xpush0(1);
auto c = cspin(1, 2, (72 * i+36) * degree) * spin(M_PI-z) * xpush0(1);
auto d = cspin(1, 2, (72 * i-36) * degree) * spin(M_PI-z) * xpush0(1);
auto a = cspin(1, 2, (72 * i ) * degree) * spin(z) * forward_dir(1);
auto b = cspin(1, 2, (72 * i-72) * degree) * spin(z) * forward_dir(1);
auto c = cspin(1, 2, (72 * i+36) * degree) * spin(M_PI-z) * forward_dir(1);
auto d = cspin(1, 2, (72 * i-36) * degree) * spin(M_PI-z) * forward_dir(1);
slimetriangle(tip, a, b, 1, 0);
slimetriangle(a, b, c, 1, 0);
slimetriangle(b, c, d, 1, 0);

View File

@ -113,7 +113,7 @@ EX void remission() {
}
EX hyperpoint move_destination_vec(int d) {
hyperpoint Forward = prod ? hpxy3(1,0,0) : tC0(pushone());
hyperpoint Forward = prod ? forward_dir(1) : tC0(pushone());
if(WDIM == 2) return spin(-d * M_PI/4) * tC0(pushone());
// else if(WDIM == 2 && pmodel == mdPerspective) return cspin(0, 2, d * M_PI/4) * tC0(pushone());
// else if(WDIM == 2) return spin(-d * M_PI/4) * tC0(pushone());

View File

@ -437,6 +437,20 @@ void geometry_information::prepare_basics() {
goto finish;
}
if(prod) {
auto t = this;
product::in_underlying_geometry([&] {
t->rhexf = cgi.rhexf;
t->hexf = cgi.hexf;
t->crossf = cgi.crossf;
t->hcrossf = cgi.crossf;
t->tessf = cgi.tessf;
t->hexhexdist = cgi.hexhexdist;
t->base_distlimit = cgi.base_distlimit-1;
});
goto prod_finish;
}
if((sphere || hyperbolic) && WDIM == 3 && !binarytiling) {
rhexf = hexf = 0.378077;
crossf = hcrossf = 0.620672;
@ -512,6 +526,8 @@ void geometry_information::prepare_basics() {
if(binarytiling) binary::build_tmatrix();
#endif
prod_finish:
scalefactor = crossf / hcrossf7;
orbsize = crossf;

View File

@ -1345,7 +1345,7 @@ EX bool drawMonsterType(eMonster m, cell *where, const transmatrix& V1, color_t
char xch = minf[m].glyph;
transmatrix V = V1;
if(WDIM == 3 && (classflag(m) & CF_FACE_UP) && where) V = V1 * cspin(0, 2, M_PI/2);
if(WDIM == 3 && (classflag(m) & CF_FACE_UP) && where && !prod) V = V1 * cspin(0, 2, M_PI/2);
// if(GDIM == 3) V = V * cspin(0, 2, M_PI/2);
@ -2749,7 +2749,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, color_t col, bool m
else {
// other monsters face the player
if(!nospins) {
if(!nospins && !prod) {
if(WDIM == 2) {
hyperpoint V0 = inverse(cwtV) * tC0(Vs);
hyperpoint V1 = spintox(V0) * V0;

View File

@ -132,8 +132,8 @@ const static transmatrix pispin = diag(-1,-1,1,1);
// central symmetry
const static transmatrix centralsym = diag(-1,-1,-1,-1);
inline hyperpoint hpxyz(ld x, ld y, ld z) { return GDIM == 2 ? hyperpoint(x,y,z,0) : hyperpoint(x,y,0,z); }
inline hyperpoint hpxyz3(ld x, ld y, ld z, ld w) { return GDIM == 2 ? hyperpoint(x,y,w,0) : hyperpoint(x,y,z,w); }
inline hyperpoint hpxyz(ld x, ld y, ld z) { return MDIM == 3 ? hyperpoint(x,y,z,0) : hyperpoint(x,y,0,z); }
inline hyperpoint hpxyz3(ld x, ld y, ld z, ld w) { return MDIM == 3 ? hyperpoint(x,y,w,0) : hyperpoint(x,y,z,w); }
inline hyperpoint point3(ld x, ld y, ld z) { return hyperpoint(x,y,z,0); }
inline hyperpoint point31(ld x, ld y, ld z) { return hyperpoint(x,y,z,1); }
inline hyperpoint point2(ld x, ld y) { return hyperpoint(x,y,0,0); }
@ -450,7 +450,7 @@ EX transmatrix euaffine(hyperpoint h) {
EX transmatrix cpush(int cid, ld alpha) {
transmatrix T = Id;
if(prod && cid == 2)
return mscale(Id, exp(alpha));
return mscale(Id, alpha);
if(nonisotropic)
return eupush3(cid == 0 ? alpha : 0, cid == 1 ? alpha : 0, cid == 2 ? alpha : 0);
T[LDIM][LDIM] = T[cid][cid] = cos_auto(alpha);
@ -473,6 +473,7 @@ EX bool eqmatrix(transmatrix A, transmatrix B, ld eps IS(.01)) {
#if MAXMDIM >= 4
// in the 3D space, move the point h orthogonally to the (x,y) plane by z units
EX hyperpoint orthogonal_move(const hyperpoint& h, ld z) {
if(prod) return zshift(h, z);
if(!hyperbolic) return rgpushxto0(h) * cpush(2, z) * C0;
if(nil) return nisot::translate(h) * cpush0(2, z);
if(translatable) return hpxy3(h[0], h[1], h[2] + z);
@ -622,7 +623,7 @@ EX transmatrix ggpushxto0(const hyperpoint& H, ld co) {
}
if(prod) {
auto d = product_decompose(H);
return mscale(PIU(ggpushxto0(d.second, co)), exp(d.first * co));
return mscale(PIU(ggpushxto0(d.second, co)), d.first * co);
}
transmatrix res = Id;
if(sqhypot_d(GDIM, H) < 1e-12) return res;
@ -764,7 +765,7 @@ EX transmatrix inverse(const transmatrix& T) {
EX pair<ld, hyperpoint> product_decompose(hyperpoint h) {
ld z = zlevel(h);
return make_pair(z, mscale(h, exp(-z)));
return make_pair(z, mscale(h, -z));
}
// distance between mh and 0
@ -829,6 +830,7 @@ EX ld hdist(const hyperpoint& h1, const hyperpoint& h2) {
EX hyperpoint mscale(const hyperpoint& t, double fac) {
if(GDIM == 3 && !prod) return cpush(2, fac) * t;
if(prod) fac = exp(fac);
hyperpoint res;
for(int i=0; i<MDIM; i++)
res[i] = t[i] * fac;
@ -840,6 +842,7 @@ EX transmatrix mscale(const transmatrix& t, double fac) {
// if(pmodel == mdFlatten) { transmatrix u = t; u[2][LDIM] -= fac; return u; }
return t * cpush(2, fac);
}
if(prod) fac = exp(fac);
transmatrix res;
for(int i=0; i<MDIM; i++) for(int j=0; j<MDIM; j++)
res[i][j] = t[i][j] * fac;
@ -912,7 +915,7 @@ EX hyperpoint orthogonal_of_C0(hyperpoint h0, hyperpoint h1, hyperpoint h2) {
EX hyperpoint zshift(hyperpoint x, ld z) {
if(GDIM == 3 && WDIM == 2) return rgpushxto0(x) * cpush0(2, z);
else if(prod) return mscale(x, exp(z));
else if(prod) return mscale(x, z);
else return mscale(x, z);
}

View File

@ -1353,7 +1353,7 @@ EX void centerpc(ld aspd) {
auto d = product_decompose(H);
ld dist = -d.first / R * aspd;
if(abs(dist) > abs(d.first)) dist = -d.first;
View = mscale(View, exp(dist));
View = mscale(View, dist);
aspd *= sqrt(R*R - d.first * d.first) / R;
}
@ -1377,9 +1377,11 @@ EX void optimizeview() {
if(prod) {
ld z = zlevel(tC0(View));
View = mscale(View, exp(-z));
View = mscale(View, -z);
product::in_underlying_geometry(optimizeview);
View = mscale(View, exp(z));
if(z > product::plevel / 2) { product::current_view_level--; z -= product::plevel; }
if(z < -product::plevel / 2) { product::current_view_level++; z += product::plevel; }
View = mscale(View, z);
return;
}
@ -1473,6 +1475,7 @@ EX void resetview() {
else centerover = cwt;
cwtV = View;
nisot::local_perspective = Id;
if(prod) product::current_view_level = product::get_where(cwt.at).second;
// SDL_LockSurface(s);
// SDL_UnlockSurface(s);
}

View File

@ -553,7 +553,6 @@ EX namespace product {
underlying_cgip = cgip;
geometry = gProduct;
ginf[gProduct] = ginf[underlying];
ginf[gProduct].sides += 2;
ginf[gProduct].cclass = gcProduct;
ginf[gProduct].flags |= qEXPERIMENTAL;
pmodel = mdPerspective;
@ -561,6 +560,8 @@ EX namespace product {
EX ld plevel = 1;
EX int current_view_level;
hrmap *pmap;
geometry_information *pcgip;
@ -599,7 +600,7 @@ EX namespace product {
cell* gamestart() override { return getCell(underlying_map->gamestart(), 0); }
transmatrix relative_matrix(cell *c2, cell *c1, const hyperpoint& point_hint) override {
return in_underlying([&] { return calc_relative_matrix(where[c2].first, where[c1].first, point_hint); }) * mscale(Id, exp(plevel * (where[c2].second - where[c1].second)));
return in_underlying([&] { return calc_relative_matrix(where[c2].first, where[c1].first, point_hint); }) * mscale(Id, plevel * (where[c2].second - where[c1].second));
}
hrmap_product() {
@ -611,12 +612,14 @@ EX namespace product {
}
};
cell *get_at(cell *base, int level) {
EX cell *get_at(cell *base, int level) {
return ((hrmap_product*)currentmap)->getCell(base, level);
}
EX pair<cell*, int> get_where(cell *c) { return ((hrmap_product*)currentmap)->where[c]; }
void drawcell_stack(cell *c, transmatrix V, int spinv, bool mirrored) {
in_actual([&] { for(int z=-5; z<=5; z++) drawcell(get_at(c, z), V * mscale(Id, exp(plevel * z)), spinv, mirrored); });
in_actual([&] { for(int z=-5; z<=5; z++) drawcell(get_at(c, current_view_level+z), V * mscale(Id, plevel * z), spinv, mirrored); });
}
void find_cell_connection(cell *c, int d) {

View File

@ -755,7 +755,7 @@ vector<hyperpoint> make5(hyperpoint a, hyperpoint b, hyperpoint c) {
void geometry_information::create_wall3d() {
if(WDIM == 2) return;
int howmany = penrose ? 22 : S7;
int howmany = penrose ? 22 : prod ? S7+2 : S7;
shWall3D.resize(howmany);
shPlainWall3D.resize(howmany);
shWireframe3D.resize(howmany);
@ -857,15 +857,15 @@ void geometry_information::create_wall3d() {
if(prod) {
cell model;
model.type = S7-2;
for(int i=0; i<S7-2; i++)
model.type = S7;
for(int i=0; i<S7; i++)
make_wall(i, {product::get_corner(&model, i, -1), product::get_corner(&model, i, +1), product::get_corner(&model, i+1, +1), product::get_corner(&model, i+1, -1)});
for(int a: {0,1}) {
vector<hyperpoint> l;
int z = a ? 1 : -1;
for(int i=0; i<S7-2; i++)
for(int i=0; i<S7; i++)
l.push_back(product::get_corner(&model, i, z));
make_wall(S7-2+a, l);
make_wall(S7+a, l);
}
}