From 46ae64e945a264f61ca239300093e225ce5cb474 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Wed, 20 Mar 2019 02:10:53 +0100 Subject: [PATCH] 3d:: native perspective is now pmodel == mdPerspective, and other models work too --- basegraph.cpp | 14 +++++----- classes.cpp | 1 + classes.h | 2 +- conformal.cpp | 7 +++-- geom-exp.cpp | 8 +++--- graph.cpp | 7 ++--- hypgraph.cpp | 72 +++++++++++++++++++++++++++++++++++++-------------- polygons.cpp | 2 +- system.cpp | 3 +++ 9 files changed, 77 insertions(+), 39 deletions(-) diff --git a/basegraph.cpp b/basegraph.cpp index 3f01177d..d3768b92 100644 --- a/basegraph.cpp +++ b/basegraph.cpp @@ -220,29 +220,29 @@ void display_data::set_projection(int ed, bool apply_models) { if(vid.consider_shader_projection) { if(pmodel == mdDisk && !spherespecial && !(hyperbolic && vid.alpha <= -1) && DIM == 2) shaderside_projection = true; - if(pmodel == mdBand && hyperbolic && apply_models) + if(pmodel == mdBand && hyperbolic && apply_models && DIM == 2) shaderside_projection = true, glhr::new_shader_projection = glhr::shader_projection::band; - if(pmodel == mdHalfplane && hyperbolic && apply_models) + if(pmodel == mdHalfplane && hyperbolic && apply_models && DIM == 2) shaderside_projection = true, glhr::new_shader_projection = glhr::shader_projection::halfplane; - if(DIM == 3 && hyperbolic && apply_models) + if(DIM == 3 && hyperbolic && apply_models && pmodel == mdPerspective) shaderside_projection = true, glhr::new_shader_projection = glhr::shader_projection::standardH3; - if(DIM == 3 && euclid && apply_models) + if(DIM == 3 && euclid && apply_models && pmodel == mdPerspective) shaderside_projection = true, glhr::new_shader_projection = glhr::shader_projection::standardR3; - if(DIM == 3 && sphere && apply_models) { + if(DIM == 3 && sphere && apply_models && pmodel == mdPerspective) { shaderside_projection = true; if(spherephase == 0) glhr::new_shader_projection = glhr::shader_projection::standardS30; if(spherephase == 1) glhr::new_shader_projection = glhr::shader_projection::standardS31; if(spherephase == 2) glhr::new_shader_projection = glhr::shader_projection::standardS32; if(spherephase == 3) glhr::new_shader_projection = glhr::shader_projection::standardS33; } - if(DIM == 3 && apply_models) dim3 = true; + if(DIM == 3 && apply_models && shaderside_projection) dim3 = true; } start_projection(ed, shaderside_projection); auto cd = current_display; - if(!shaderside_projection && DIM != 3) { + if(!shaderside_projection) { glhr::projection_multiply(glhr::ortho(cd->xsize/2, -cd->ysize/2, abs(current_display->scrdist) + 30000)); if(ed) { glhr::glmatrix m = glhr::id; diff --git a/classes.cpp b/classes.cpp index 646c73e9..9b5d193d 100644 --- a/classes.cpp +++ b/classes.cpp @@ -1822,6 +1822,7 @@ const modelinfo models[int(mdPolynomial)+1] = { {X3("Joukowsky+inversion"), mf::hyper_only | mf::conformal}, {X3("rotated hyperboles"), mf::hyper_only}, {X3("spiral"), mf::hyper_or_torus | mf::quasiband}, + {X3("native perspective"), 0}, {X3(""), 0}, {X3(""), 0}, {X3(""), 0}, diff --git a/classes.h b/classes.h index 9a9cf283..2e641dbf 100644 --- a/classes.h +++ b/classes.h @@ -283,7 +283,7 @@ enum eModel { mdEquidistant, mdEquiarea, mdBall, mdHyperboloid, mdHemisphere, mdBandEquidistant, mdBandEquiarea, mdSinusoidal, mdTwoPoint, mdFisheye, mdJoukowsky, mdJoukowskyInverted, - mdRotatedHyperboles, mdSpiral, + mdRotatedHyperboles, mdSpiral, mdPerspective, mdGUARD, mdUnchanged, mdHyperboloidFlat, mdPolynomial }; diff --git a/conformal.cpp b/conformal.cpp index 63612a8c..9df916f0 100644 --- a/conformal.cpp +++ b/conformal.cpp @@ -584,6 +584,8 @@ namespace conformal { bool model_available(eModel pm) { if(sphere && (pm == mdHalfplane || pm == mdBall)) return false; + if(DIM == 2 && pm == mdPerspective) return false; + if(DIM == 3 && among(pm, mdBall, mdHyperboloid, mdFormula, mdPolygonal, mdRotatedHyperboles, mdSpiral, mdHemisphere)) return false; return true; } @@ -673,7 +675,7 @@ namespace conformal { eModel m = eModel(i); if(m == mdFormula && ISMOBILE) continue; if(model_available(m)) { - dialog::addBoolItem(get_model_name(m), pmodel == m, "0123456789!@#$%^&*()" [m]); + dialog::addBoolItem(get_model_name(m), pmodel == m, "0123456789!@#$%^&*()]" [m]); dialog::add_action([m] () { if(m == mdFormula) { edit_formula(); @@ -697,7 +699,8 @@ namespace conformal { dialog::lastItem().value += " " + its(rotation) + "°"; // if(pmodel == mdBand && sphere) - dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z'); + if(pmodel != mdPerspective) + dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z'); if(abs(vid.alpha-1) > 1e-3 && pmodel != mdBall && pmodel != mdHyperboloid && pmodel != mdHemisphere && pmodel != mdDisk) { dialog::addBreak(50); diff --git a/geom-exp.cpp b/geom-exp.cpp index f287066f..4d2134cd 100644 --- a/geom-exp.cpp +++ b/geom-exp.cpp @@ -677,13 +677,11 @@ void showEuclideanMenu() { dialog::add_action([] { pushScreen(patterns::showPrePattern); }); validity_info(); if(DIM == 3) { - dialog::addItem(XLAT("3D configuration"), '1'); + dialog::addItem(XLAT("3D configuration"), '9'); dialog::add_action([] { pushScreen(show3D); }); } - else { - dialog::addSelItem(XLAT("projection"), current_proj_name(), '1'); - dialog::add_action([] { pushScreen(conformal::model_menu); }); - } + dialog::addSelItem(XLAT("projection"), current_proj_name(), '1'); + dialog::add_action([] { pushScreen(conformal::model_menu); }); #if CAP_CRYSTAL && MAXMDIM >= 4 crystal::add_crystal_transform('x'); #endif diff --git a/graph.cpp b/graph.cpp index 94d4c706..8379b907 100644 --- a/graph.cpp +++ b/graph.cpp @@ -4808,8 +4808,8 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { for(int a=0; atype; a++) if(c->move(a) && !isWall3(c->move(a), dummy)) { - if(a < 4 && among(geometry, gHoroTris, gBinary3) && celldistAlt(c) >= celldistAlt(viewctr.at->c7)) continue; - if(a < 2 && among(geometry, gHoroRec) && celldistAlt(c) >= celldistAlt(viewctr.at->c7)) continue; + if(a < 4 && pmodel == mdPerspective && among(geometry, gHoroTris, gBinary3) && celldistAlt(c) >= celldistAlt(viewctr.at->c7)) continue; + if(a < 2 && pmodel == mdPerspective && among(geometry, gHoroRec) && celldistAlt(c) >= celldistAlt(viewctr.at->c7)) continue; if(qfi.fshape && wmescher) { auto& poly = queuepoly(V, shWall3D[a], darkena(wcol - d * get_darkval(a), 0, 0xFF)); poly.tinf = &qfi.fshape->tinf3; @@ -5923,6 +5923,7 @@ void drawthemap() { mmspatial = vid.monmode == 4 || vid.monmode == 5; spatial_graphics = wmspatial || mmspatial; + spatial_graphics = spatial_graphics && DIM == 2; #if CAP_RUG if(rug::rugged && !rug::spatial_rug) spatial_graphics = false; #endif @@ -6146,7 +6147,7 @@ void calcparam() { } cd->radius = vid.scale * cd->scrsize; - if(DIM == 3) cd->radius = cd->scrsize; + if(DIM == 3 && pmodel == mdPerspective) cd->radius = cd->scrsize; realradius = min(realradius, cd->radius); if(dronemode) { cd->ycenter -= cd->radius; cd->ycenter += vid.fsize/2; cd->ycenter += vid.fsize/2; cd->radius *= 2; } diff --git a/hypgraph.cpp b/hypgraph.cpp index 50d5a2b4..2dc9ceae 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -69,7 +69,12 @@ hyperpoint space_to_perspective(hyperpoint z, ld alpha) { ld s = 1 / (alpha + z[DIM]); z[0] *= s; z[1] *= s; - z[DIM] = 0; + if(DIM == 3) { + z[2] *= s; + z[3] = 0; + } + else + z[2] = 0; return z; } @@ -154,7 +159,7 @@ ld find_zlev(hyperpoint& H) { } ld get_tz(hyperpoint H) { - ld tz = euclid ? (1+vid.alpha) : vid.alpha+H[2]; + ld tz = euclid ? (1+vid.alpha) : vid.alpha+H[DIM]; if(tz < BEHIND_LIMIT && tz > -BEHIND_LIMIT) tz = BEHIND_LIMIT; return tz; } @@ -163,9 +168,26 @@ ld atan2(hyperpoint h) { return atan2(h[1], h[0]); } +pair move_z_to_y(hyperpoint& H) { + if(DIM == 2) return make_pair(0, 0); + ld R = hypot(H[1], H[2]); + pair res = { H[1] / R, H[2] / R }; + H[1] = R; H[2] = 0; + return res; + } + +void move_y_to_z(hyperpoint& H, pair coef) { + if(DIM == 3) { + H[2] = H[1] * coef.second; + H[1] = H[1] * coef.first; + H[3] = 1; + } + } + template void makeband(hyperpoint H, hyperpoint& ret, const T& f) { ld zlev = find_zlev(H); conformal::apply_orientation(H[0], H[1]); + auto r = move_z_to_y(H); ld x, y, yf, zf=0; y = asin_auto(H[1]); @@ -179,8 +201,9 @@ template void makeband(hyperpoint H, hyperpoint& ret, const T& f) { f(x, y); ld yzf = y * zf; y *= yf; - conformal::apply_orientation(y, x); ret = hpxyz(x / M_PI, y / M_PI, 0); + move_y_to_z(ret, r); + conformal::apply_orientation(ret[1], ret[0]); if(zlev != 1 && current_display->stereo_active()) apply_depth(ret, yzf / M_PI); return; @@ -233,19 +256,19 @@ hyperpoint mobius(hyperpoint h, ld angle, ld scale = 1) { void applymodel(hyperpoint H, hyperpoint& ret) { - if(DIM == 3) { - ld ratio = vid.xres / current_display->tanfov / current_display->radius / 2; - ret[0] = H[0]/H[2] * ratio; - ret[1] = H[1]/H[2] * ratio; - ret[2] = 1; - return; - } - using namespace hyperpoint_vec; hyperpoint H_orig = H; switch(pmodel) { + case mdPerspective: { + ld ratio = vid.xres / current_display->tanfov / current_display->radius / 2; + ret[0] = H[0]/H[2] * ratio; + ret[1] = H[1]/H[2] * ratio; + ret[2] = 1; + return; + } + case mdUnchanged: ret = H / current_display->radius; return; @@ -264,7 +287,9 @@ void applymodel(hyperpoint H, hyperpoint& ret) { if(!vid.camera_angle) { ret[0] = H[0] / tz; ret[1] = H[1] / tz; - ret[2] = vid.xres * current_display->eyewidth() / 2 / current_display->radius - vid.ipd / tz / 2; + if(DIM == 3) ret[2] = H[2] / tz; + else ret[2] = vid.xres * current_display->eyewidth() / 2 / current_display->radius - vid.ipd / tz / 2; + if(MAXMDIM == 4) ret[3] = 1; } else { ld tx = H[0]; @@ -289,7 +314,7 @@ void applymodel(hyperpoint H, hyperpoint& ret) { conformal::apply_orientation(H[0], H[1]); H[1] += 1; - double rad = sqhypot_d(2, H); + double rad = sqhypot_d(DIM, H); H /= -rad; H[1] += .5; @@ -307,7 +332,8 @@ void applymodel(hyperpoint H, hyperpoint& ret) { H[1] += H[0] * conformal::osin * log(zlev); } ret[1] = conformal::ocos + H[1]; - ret[2] = 0; + ret[2] = DIM == 3 ? H[2] : 0; + if(MAXMDIM == 4) ret[3] = 1; if(zlev != 1 && current_display->stereo_active()) apply_depth(ret, -H[1] * geom3::factor_to_lev(zlev)); break; @@ -378,8 +404,8 @@ void applymodel(hyperpoint H, hyperpoint& ret) { case mdFisheye: { ld zlev = find_zlev(H); H = space_to_perspective(H); - H[2] = zlev; - ret = H / sqrt(1 + sqhypot_d(3, H)); + H[DIM] = zlev; + ret = H / sqrt(1 + sqhypot_d(DIM+1, H)); break; } @@ -409,6 +435,7 @@ void applymodel(hyperpoint H, hyperpoint& ret) { } H = space_to_perspective(H); + auto yz = move_z_to_y(H); ld r = hypot_d(2, H); ld c = H[0] / r; ld s = H[1] / r; @@ -422,11 +449,12 @@ void applymodel(hyperpoint H, hyperpoint& ret) { if(vid.skiprope) ret = mobius(ret, vid.skiprope, 2); - + if(pmodel == mdJoukowskyInverted) { ld r2 = sqhypot_d(2, ret); ret[0] = ret[0] / r2; ret[1] = -ret[1] / r2; + move_y_to_z(ret, yz); conformal::apply_orientation(ret[1], ret[0]); /* @@ -439,7 +467,10 @@ void applymodel(hyperpoint H, hyperpoint& ret) { ret[0] = alpha; ret[1] = log(mod); */ } - else conformal::apply_orientation(ret[0], ret[1]); + else { + move_y_to_z(ret, yz); + conformal::apply_orientation(ret[0], ret[1]); + } break; } @@ -511,7 +542,7 @@ void applymodel(hyperpoint H, hyperpoint& ret) { case mdEquidistant: case mdEquiarea: { ld zlev = find_zlev(H); - ld rad = hypot_d(2, H); + ld rad = hypot_d(DIM, H); if(rad == 0) rad = 1; ld d = hdist0(H); ld df, zf; @@ -525,7 +556,8 @@ void applymodel(hyperpoint H, hyperpoint& ret) { d = sqrt(2*(cosh(d) - 1)) / 1.5; ret = H * (d * df / rad / M_PI); - ret[2] = 0; + if(DIM == 2) ret[2] = 0; + if(MAXMDIM == 4) ret[3] = 1; if(zlev != 1 && current_display->stereo_active()) apply_depth(ret, d * zf / M_PI); diff --git a/polygons.cpp b/polygons.cpp index 3c0ad1e6..e00c521b 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -496,7 +496,7 @@ vector line_vertices; void glapplymatrix(const transmatrix& V) { GLfloat mat[16]; int id = 0; - if(DIM == 3) { + if(pmodel == mdPerspective && DIM == 3) { if(elliptic && spherephase < 2) { for(int y=0; y<4; y++) { for(int x=0; x<4; x++) mat[id++] = -V[x][y]; diff --git a/system.cpp b/system.cpp index e0d2232c..22fe91d0 100644 --- a/system.cpp +++ b/system.cpp @@ -1170,6 +1170,7 @@ void push_game() { void set_geometry(eGeometry target) { if(geometry != target) { + int old_DIM = DIM; stop_game(); ors::reset(); geometry = target; @@ -1196,6 +1197,8 @@ void set_geometry(eGeometry target) { #if CAP_BT if(geometry == gBinaryTiling || DIM == 3) variation = eVariation::pure; #endif + if(DIM == 3 && old_DIM == 3 && pmodel == mdDisk) pmodel = mdPerspective; + if(DIM == 2 && pmodel == mdPerspective) pmodel = mdDisk; need_reset_geometry = true; }