diff --git a/basegraph.cpp b/basegraph.cpp index 5e9f7465..91192d63 100644 --- a/basegraph.cpp +++ b/basegraph.cpp @@ -263,6 +263,10 @@ void stereo::set_viewport(int ed) { glViewport(vid.xres/2, 0, vid.xres/2, vid.yres); } +bool model_needs_depth() { + return pmodel == mdBall || pmodel == mdHyperboloid || pmodel == mdHemisphere; + } + void setGLProjection(int col) { DEBB(DF_GRAPH, (debugfile,"setGLProjection\n")); GLERR("pre_setGLProjection"); @@ -299,17 +303,17 @@ void setGLProjection(int col) { //glLineWidth(1.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if(pmodel == mdBall || pmodel == mdHyperboloid || pmodel == mdHemisphere) { + if(model_needs_depth()) { #ifdef GL_ES glClearDepthf(1.0f); #else glClearDepth(1.0f); #endif - glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); + glhr::set_depthtest(true); } else - glDisable(GL_DEPTH_TEST); + glhr::set_depthtest(false); GLERR("setGLProjection"); @@ -523,6 +527,8 @@ bool gl_print(int x, int y, int shift, int size, const char *s, int color, int a int ysiz = f.heights[32] * size / gsiz; bool clicked = (mousex >= x && mousey <= y && mousex <= x+tsize && mousey >= y-ysiz); + + glhr::set_depthtest(false); for(int i=0; s[i];) { @@ -917,6 +923,7 @@ void drawCircle(int x, int y, int size, int color) { glcoords.push_back(make_array(x + size * sin(rr), y + size * cos(rr), stereo::scrdist)); } glhr::vertices(glcoords); + glhr::set_depthtest(false); glDrawArrays(GL_LINE_LOOP, 0, pts); return; } diff --git a/config.cpp b/config.cpp index 508ec2a0..397e5e77 100644 --- a/config.cpp +++ b/config.cpp @@ -337,6 +337,7 @@ void initConfig() { addsaver(stereo::anaglyph_eyewidth, "eyewidth-anaglyph", 0.1); addsaver(stereo::fov, "field-of-vision", 90); addsaverenum(stereo::mode, "stereo-mode"); + addsaver(vid.euclid_to_sphere, "euclid to sphere projection", 1.5); #if CAP_SHMUP shmup::initConfig(); @@ -1130,6 +1131,17 @@ void showStereo() { }; } +void config_camera_rotation() { + dialog::editNumber(vid.ballangle, 0, 90, 5, 0, XLAT("camera rotation in 3D models"), + "Rotate the camera in 3D models (ball model, hyperboloid, and hemisphere). " + "Note that hyperboloid and hemisphere models are also available in the " + "Hypersian Rug surfaces menu, but they are rendered differently there -- " + "they are rendered by making a flat picture first, then mapping it to a surface. " + "This makes the output better in some ways, but 3D effects are lost. " + "Hypersian Rug model also allows more camera freedom." + ); + } + void show3D() { cmode = sm::SIDE | sm::A3 | sm::MAYDARK; gamescreen(0); @@ -1158,7 +1170,7 @@ void show3D() { dialog::addBreak(50); dialog::addBoolItem(XLAT("ball model"), pmodel == mdBall, 'B'); dialog::addBoolItem(XLAT("hyperboloid model"), pmodel == mdHyperboloid, 'M'); - dialog::addSelItem(XLAT("camera rotation in ball model"), fts3(vid.ballangle), 'b'); + dialog::addSelItem(XLAT("camera rotation in 3D models"), fts3(vid.ballangle), 'b'); dialog::addSelItem(XLAT("projection in ball model"), fts3(vid.ballproj), 'x'); if(sphere) @@ -1181,10 +1193,8 @@ void show3D() { dialog::handleNavigation(sym, uni); if(uni == 'n') - cmode &= sm::A3, dialog::editNumber(geom3::highdetail, 0, 5, .5, 7, XLAT("High detail range"), ""); else if(uni == 'm') - cmode &= sm::A3, dialog::editNumber(geom3::middetail, 0, 5, .5, 7, XLAT("Mid detail range"), ""); else if(uni == 'c') tc_camera = ticks, @@ -1209,22 +1219,17 @@ void show3D() { pushScreen(showStereo); else if(uni == 'y') - cmode &= sm::A3, dialog::editNumber(vid.yshift, 0, 1, .1, 0, XLAT("Y shift"), "Don't center on the player character." ); else if(uni == 's') - cmode &= sm::A3, dialog::editNumber(vid.camera_angle, -180, 180, 5, 0, XLAT("camera rotation"), "Rotate the camera. Can be used to obtain a first person perspective, " "or third person perspective when combined with Y shift." ); else if(uni == 'b') - cmode &= sm::A3, - dialog::editNumber(vid.ballangle, 0, 90, 5, 0, XLAT("camera rotation in ball model"), - "Rotate the camera in ball/hyperboloid model."); + config_camera_rotation(); else if(uni == 'x') - cmode &= sm::A3, dialog::editNumber(vid.ballproj, 0, 100, .1, 0, XLAT("projection in ball model"), "This parameter affects the ball model the same way as the projection parameter affects the disk model."); else if(uni == 'i') diff --git a/conformal.cpp b/conformal.cpp index 4064aa02..3872e616 100644 --- a/conformal.cpp +++ b/conformal.cpp @@ -537,6 +537,7 @@ namespace conformal { { "right", "up", "left", "down" }, { "right", "up", "left", "down" }, { "right", "up", "left", "down" }, + { "right", "up", "left", "down" }, { "right", "up", "left", "down" } }; @@ -577,7 +578,7 @@ namespace conformal { dialog::addBoolItem("Switch", false, '6'); } - if(pmodel == 4) { + if(pmodel == mdPolynomial) { dialog::addSelItem(XLAT("coefficient"), fts4(polygonal::coefr[polygonal::coefid]), 'x'); dialog::addSelItem(XLAT("coefficient (imaginary)"), @@ -585,12 +586,20 @@ namespace conformal { dialog::addSelItem(XLAT("which coefficient"), its(polygonal::coefid), 'n'); } - if(pmodel == 3) { + if(pmodel == mdPolygonal) { dialog::addSelItem(XLAT("polygon sides"), its(polygonal::SI), 'x'); dialog::addSelItem(XLAT("star factor"), fts(polygonal::STAR), 'y'); dialog::addSelItem(XLAT("degree of the approximation"), its(polygonal::deg), 'n'); } + if(pmodel == mdBall || pmodel == mdHyperboloid || pmodel == mdHemisphere) { + dialog::addSelItem(XLAT("camera rotation in 3D models"), fts3(vid.ballangle), 'b'); + } + + if(pmodel == mdHemisphere) { + dialog::addSelItem(XLAT("euclid to sphere projection"), fts3(vid.euclid_to_sphere), 'l'); + } + if(!bounded && !euclid) dialog::addBoolItem(XLAT("prepare the line animation"), (on), 'e'); if(on) dialog::addSelItem(XLAT("animation speed"), fts(lvspeed), 'a'); @@ -633,6 +642,14 @@ namespace conformal { create(); } } + else if(uni == 'b') + config_camera_rotation(); + else if(uni == 'l') { + dialog::editNumber(vid.euclid_to_sphere, 0, 10, .1, 1, XLAT("euclid to sphere projection"), + "Stereographic projection to a sphere. Choose the radius of the sphere." + ); + dialog::scaleLog(); + } else if(uni == 'o') autoband = !autoband; else if(uni == 'm' || uni == 'M') { diff --git a/dialogs.cpp b/dialogs.cpp index edc164c9..2fc8f605 100644 --- a/dialogs.cpp +++ b/dialogs.cpp @@ -829,7 +829,7 @@ namespace dialog { ne.intval = NULL; ne.positive = false; dialogflags = (cmode & sm::A3); - if(cmode & sm::SIDE) dialogflags |= sm::MAYDARK; + if(cmode & sm::SIDE) dialogflags |= sm::MAYDARK | sm::SIDE; cmode |= sm::NUMBER; pushScreen(drawNumberDialog); reaction = reaction_t(); diff --git a/graph.cpp b/graph.cpp index b9c20d30..45f0deac 100644 --- a/graph.cpp +++ b/graph.cpp @@ -2309,7 +2309,8 @@ void drawaura() { glhr::switch_mode(glhr::gmVarColored); glhr::id_modelview(); glhr::prepare(auravertices); - glDrawArrays(GL_TRIANGLES, 0, size(auravertices)); + glhr::set_depthtest(false); + glDrawArrays(GL_TRIANGLES, 0, size(auravertices)); setcameraangle(false); diff --git a/hyper.h b/hyper.h index 0c337ee2..69121689 100644 --- a/hyper.h +++ b/hyper.h @@ -647,7 +647,7 @@ extern reaction_t help_delegate; struct videopar { ld scale, alpha, sspeed, mspeed, yshift, camera_angle; - ld ballangle, ballproj; + ld ballangle, ballproj, euclid_to_sphere; int mobilecompasssize; int aurastr, aurasmoothen; diff --git a/hypgraph.cpp b/hypgraph.cpp index 8b91ad62..dd0d2f50 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -129,20 +129,23 @@ void applymodel(hyperpoint H, hyperpoint& ret) { switch(cgclass) { case gcHyperbolic: { + ld zl = zlevel(H); ret = H / H[2]; ret[2] = sqrt(1 - sqhypot2(ret)); + ret = ret * (1 + (zl - 1) * ret[2]); break; } case gcEuclid: { // stereographic projection to a sphere - auto hd = hdist0(H) / H[2]; - if(hd == 0) H[2] = -1; + auto hd = hdist0(H) / vid.euclid_to_sphere; + if(hd == 0) ret = hpxyz(0, 0, -1); else { ld x = 2 * hd / (1 + hd * hd); ld y = x / hd; - H = H * x / (hd * H[2]); - H[2] = 1 - y; + ret = H * x / hd / vid.euclid_to_sphere; + ret[2] = (1 - y); + ret = ret * (1 + (H[2]-1) * y / vid.euclid_to_sphere); } break; } @@ -153,7 +156,7 @@ void applymodel(hyperpoint H, hyperpoint& ret) { } } - ret = rotmatrix(0, 2, ball) * ret; + ret = rotmatrix(M_PI/2 + ball, 1, 2) * ret; ghcheck(ret, H); return; diff --git a/polygons.cpp b/polygons.cpp index f2252128..55aecd5a 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -250,7 +250,7 @@ void setmatrix(int useV, const transmatrix& V) { GLfloat mat[16] = { 1, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, + 0, 0, -1, 0, 0, 0, stereo::scrdist, 1 }; glhr::set_modelview(glhr::as_glmatrix(mat)); @@ -299,14 +299,17 @@ void gldraw(int useV, const transmatrix& V, const vector& v, int ps, i glEnable(GL_STENCIL_TEST); glColorMask( GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE ); + glhr::set_depthtest(false); glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT); glStencilFunc( GL_ALWAYS, 0x1, 0x1 ); glhr::color2(0xFFFFFFFF); glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); + stereo::set_mask(ed); + glhr::color2(col); + glhr::set_depthtest(model_needs_depth()); + if(flags & POLY_INVERSE) { - stereo::set_mask(ed); - glhr::color2(col); glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO); glStencilFunc( GL_NOTEQUAL, 1, 1); GLfloat xx = vid.xres; @@ -324,8 +327,6 @@ void gldraw(int useV, const transmatrix& V, const vector& v, int ps, i setmatrix(useV, V); } else { - stereo::set_mask(ed); - glhr::color2(col); glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO); glStencilFunc( GL_EQUAL, 1, 1); glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); @@ -337,6 +338,7 @@ void gldraw(int useV, const transmatrix& V, const vector& v, int ps, i if(outline) { glhr::color2(outline); + glhr::set_depthtest(model_needs_depth()); glDrawArrays(GL_LINE_STRIP, ps, pq); } } diff --git a/shaders.cpp b/shaders.cpp index b981b624..798a34a2 100644 --- a/shaders.cpp +++ b/shaders.cpp @@ -670,4 +670,13 @@ void store_in_buffer(vector& v) { #endif } +bool current_depthtest; + +void set_depthtest(bool b) { + if(b != current_depthtest) { + current_depthtest = b; + if(b) glEnable(GL_DEPTH_TEST); + else glDisable(GL_DEPTH_TEST); + } + } } diff --git a/textures.cpp b/textures.cpp index 91891039..285359ec 100644 --- a/textures.cpp +++ b/textures.cpp @@ -483,6 +483,7 @@ void texture_config::drawRawTexture() { } glhr::set_modelview(glhr::translate(0, 0, stereo::scrdist)); glhr::prepare(rtver); + glhr::set_depthtest(false); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); }