diff --git a/config.cpp b/config.cpp index ee6c21ac..df8f3080 100644 --- a/config.cpp +++ b/config.cpp @@ -1345,11 +1345,13 @@ EX void initConfig() { addsaver(vid.desaturate, "desaturate", 0); param_enum(vid.stereo_mode, "stereo_mode", "stereo-mode", vid.stereo_mode) - ->editable({{"OFF", ""}, {"anaglyph", ""}, {"side-by-side", ""} - #if CAP_ODS - , {"ODS", ""} - #endif - }, "stereo mode", 'm'); + ->editable({ + {"OFF", "linear perspective"}, {"anaglyph", "for red-cyan glasses"}, {"side-by-side", "for mobile VR"}, + {"ODS", "for rendering 360° VR videos (implemented only in raycaster and some other parts)"}, + {"Panini", "Projection believed to be used by Italian painters. Allows very high FOV angles while rendering more straight lines as straight than the stereographic projection."}, + {"stereographic", "Stereographic projection allows very high FOV angles."}, + {"equirectangular", "for rendering 360° videos (implemented only in raycaster)"} + }, "stereo/high-FOV mode", 'm'); param_f(vid.plevel_factor, "plevel_factor", 0.7); @@ -1577,11 +1579,12 @@ EX void initConfig() { param_f(camera_rot_speed, "camrot", "camera-rot-speed", 1); param_f(third_person_rotation, "third_person_rotation", 0); - param_f(panini_alpha, "panini_alpha", 0) + param_f(vid.stereo_param, "stereo_param", 0.9) + ->editable(-1, 1, 0.9, "stereographic/Panini parameter", "1 for full stereographic/Panini projection. Lower values reduce the effect.\n\n" + "HyperRogue uses " + "a quick implementation, so parameter values too close to 1 may " + "be buggy (outside of raycasting); try e.g. 0.9 instead.", 'd') ->set_reaction(reset_all_shaders); - param_f(stereo_alpha, "stereo_alpha", 0) - ->set_reaction(reset_all_shaders); - param_b(equirectangular, "equirectangular"); callhooks(hooks_configfile); @@ -2473,7 +2476,7 @@ EX void explain_detail() { } EX ld max_fov_angle() { - auto& p = panini_alpha ? panini_alpha : stereo_alpha; + auto p = get_stereo_param(); if(p >= 1 || p <= -1) return 360; return acos(-p) * 2 / degree; } @@ -2481,7 +2484,7 @@ EX ld max_fov_angle() { EX void add_edit_fov(char key IS('f')) { string sfov = fts(vid.fov) + "°"; - if(panini_alpha || stereo_alpha) { + if(get_stereo_param()) { sfov += " / " + fts(max_fov_angle()) + "°"; } dialog::addSelItem(XLAT("field of view"), sfov, key); @@ -2498,37 +2501,11 @@ EX void add_edit_fov(char key IS('f')) { ); dialog::bound_low(1e-8); dialog::bound_up(max_fov_angle() - 0.01); - string quick = - XLAT( - "HyperRogue uses " - "a quick implementation, so parameter values too close to 1 may " - "be buggy (outside of raycasting); try e.g. 0.9 instead." - ); - dialog::get_di().extra_options = [quick] { - dialog::addSelItem(XLAT("Panini projection"), fts(panini_alpha), 'P'); - dialog::add_action([quick] { - dialog::editNumber(panini_alpha, 0, 1, 0.1, 0, "Panini parameter", - XLAT( - "The Panini projection is an alternative perspective projection " - "which allows very wide field-of-view values.\n\n") + quick - ); - #if CAP_GL - dialog::get_di().reaction = reset_all_shaders; - #endif - dialog::get_di().extra_options = [] { add_edit_fov('F'); }; - }); - dialog::addSelItem(XLAT("spherical perspective projection"), fts(stereo_alpha), 'S'); - dialog::add_action([quick] { - dialog::editNumber(stereo_alpha, 0, 1, 0.1, 0, "spherical perspective parameter", - XLAT( - "Set to 1 to get stereographic projection, " - "which allows very wide field-of-view values.\n\n") + quick - ); - #if CAP_GL - dialog::get_di().reaction = reset_all_shaders; - #endif - dialog::get_di().extra_options = [] { add_edit_fov('F'); }; - }); + dialog::get_di().extra_options = [] { + add_edit(vid.stereo_mode, 'M'); + if(among(vid.stereo_mode, sPanini, sStereographic)) { + add_edit(vid.stereo_param, 'P'); + } }; }); } @@ -2554,6 +2531,9 @@ EX void showStereo() { case sLR: dialog::addSelItem(XLAT("distance between images"), fts(vid.lr_eyewidth), 'd'); break; + case sPanini: case sStereographic: + add_edit(vid.stereo_param); + break; default: dialog::addBreak(100); break; diff --git a/graph.cpp b/graph.cpp index de79257d..2d7609e2 100644 --- a/graph.cpp +++ b/graph.cpp @@ -22,10 +22,6 @@ EX bool spatial_graphics; EX bool wmspatial, wmescher, wmplain, wmblack, wmascii, wmascii3; EX bool mmspatial, mmhigh, mmmon, mmitem; -EX ld panini_alpha = 0; -EX ld stereo_alpha = 0; -EX bool equirectangular; - EX int detaillevel = 0; EX bool first_cell_to_draw = true; @@ -4122,10 +4118,14 @@ EX ld threshold, xyz_threshold; EX bool clip_checked = false; +EX bool other_stereo_mode() { + return among(vid.stereo_mode, sODS, sPanini, sStereographic, sEquirectangular); + } + void make_clipping_planes() { #if MAXMDIM >= 4 clip_checked = false; - if(!frustum_culling || PIU(sphere) || experimental || vid.stereo_mode == sODS || panini_alpha || stereo_alpha || gproduct || embedded_plane) return; + if(!frustum_culling || PIU(sphere) || experimental || other_stereo_mode() || gproduct || embedded_plane) return; if(WDIM == 3 && pmodel == mdPerspective && !nonisotropic && !in_s2xe()) threshold = sin_auto(cgi.corner_bonus), xyz_threshold = 0, clip_checked = true; @@ -5496,6 +5496,11 @@ EX ld min_scale = 1e-6; EX int forced_center_down = ISANDROID ? 2 : ISIOS ? 40 : 40; +EX ld get_stereo_param() { + if(among(vid.stereo_mode, sPanini, sStereographic)) return vid.stereo_param; + return 0; + } + EX void calcparam() { DEBBI(DF_GRAPH, ("calc param")); @@ -5557,7 +5562,7 @@ EX void calcparam() { cd->ycenter += cd->scrsize * pconf.yposition; ld fov = vid.fov * degree / 2; - cd->tanfov = sin(fov) / (cos(fov) + (panini_alpha ? panini_alpha : stereo_alpha)); + cd->tanfov = sin(fov) / (cos(fov) + get_stereo_param()); callhooks(hooks_calcparam); reset_projection(); diff --git a/hyper.h b/hyper.h index 4d09d592..649ee386 100644 --- a/hyper.h +++ b/hyper.h @@ -250,7 +250,7 @@ struct charstyle { bool lefthanded; }; -enum eStereo { sOFF, sAnaglyph, sLR, sODS }; +enum eStereo { sOFF, sAnaglyph, sLR, sODS, sPanini, sStereographic, sEquirectangular }; enum eModel : int; @@ -395,6 +395,7 @@ struct videopar { int cells_generated_limit; // limit on cells generated per frame eStereo stereo_mode; + ld stereo_param; ld ipd; ld lr_eyewidth, anaglyph_eyewidth; ld fov; diff --git a/legacy.cpp b/legacy.cpp index fce6fcbe..93c38a36 100644 --- a/legacy.cpp +++ b/legacy.cpp @@ -457,6 +457,24 @@ int read_legacy_args_anim() { } */ /* skiprope:legacy.cpp pconf.skiprope += skiprope_rotation * t * TAU / period; */ } + else if(argis("-palpha")) { + PHASEFROM(2); + #if CAP_GL + shift_arg_formula(vid.stereo_param, reset_all_shaders); + #else + shift_arg_formula(vid.stereo_param); + #endif + vid.stereo_mode = sPanini; + } + else if(argis("-salpha")) { + PHASEFROM(2); + #if CAP_GL + shift_arg_formula(vid.stereo_param, reset_all_shaders); + #else + shift_arg_formula(vid.stereo_param); + #endif + vid.stereo_mode = sStereographic; + } else return 1; return 0; } diff --git a/models.cpp b/models.cpp index 90207e8e..fd6a728e 100644 --- a/models.cpp +++ b/models.cpp @@ -234,7 +234,7 @@ EX namespace models { } EX bool has_orientation(eModel m) { - if(is_perspective(m) && panini_alpha) return true; + if(is_perspective(m) && vid.stereo_mode == sPanini) return true; if(nonisotropic) return false; return (mdinf[m].flags & mf::orientation); } @@ -884,22 +884,6 @@ EX namespace models { PHASEFROM(2); shift_arg_formula(vpconf.skiprope); } - else if(argis("-palpha")) { - PHASEFROM(2); - #if CAP_GL - shift_arg_formula(panini_alpha, reset_all_shaders); - #else - shift_arg_formula(panini_alpha); - #endif - } - else if(argis("-salpha")) { - PHASEFROM(2); - #if CAP_GL - shift_arg_formula(stereo_alpha, reset_all_shaders); - #else - shift_arg_formula(stereo_alpha); - #endif - } else if(argis("-zoom")) { PHASEFROM(2); shift_arg_formula(vpconf.scale); } diff --git a/raycaster.cpp b/raycaster.cpp index 8be71192..103ea5ce 100644 --- a/raycaster.cpp +++ b/raycaster.cpp @@ -1434,10 +1434,10 @@ void raygen::emit_iterate(int gid1) { fsh += "uniform mediump float uLevelLines;\n"; } - if(panini_alpha) + if(vid.stereo_mode == sPanini) fmain += panini_shader(); - else if(stereo_alpha) + else if(vid.stereo_mode == sStereographic) fmain += stereo_shader(); #ifndef GLES_ONLY @@ -1965,8 +1965,9 @@ void raygen::create() { " mediump mat4 vw = uStart * xzspin(-lambda) * "+f_xpush()+"(eye) * yzspin(phi);\n" " mediump vec4 at0 = vec4(0., 0., 1., 0.);\n"; // todo: will not work in product! +*/ - else if(equirectangular) fmain += + else if(vid.stereo_mode == sEquirectangular) fmain += " mediump float lambda = at.x * PI;\n" // -PI to PI " mediump float phi = at.y * PI / 2.0;\n" " mediump mat4 vw = uStart;\n" @@ -1978,10 +1979,10 @@ void raygen::create() { " mediump vec4 at0 = at;\n" " at0.y = -at.y;\n" " at0.w = 0.;\n"; - - if(panini_alpha) fmain += + + if(vid.stereo_mode == sPanini) fmain += "mediump float hr = at0.x*at0.x;\n" - "mediump float alpha = " + to_glsl(panini_alpha) + ";\n" + "mediump float alpha = " + to_glsl(get_stereo_param()) + ";\n" "mediump float A = 1. + hr;\n" "mediump float B = -2.*hr*alpha;\n" "mediump float C = 1. - hr*alpha*alpha;\n" @@ -1995,9 +1996,9 @@ void raygen::create() { "\n" ; - else if(stereo_alpha) fmain += + else if(vid.stereo_mode == sStereographic) fmain += "mediump float hr = at0.x*at0.x+at0.y*at0.y;\n" - "mediump float alpha = " + to_glsl(stereo_alpha) + ";\n" + "mediump float alpha = " + to_glsl(get_stereo_param()) + ";\n" "mediump float A = 1. + hr;\n" "mediump float B = -2.*hr*alpha;\n" "mediump float C = 1. - hr*alpha*alpha;\n" @@ -2579,7 +2580,7 @@ EX void cast() { #else if(0) ; #endif - else if(equirectangular) { + else if(among(vid.stereo_mode, sODS, sEquirectangular)) { glUniformMatrix4fv(o->uProjection, 1, 0, glhr::tmtogl_transpose(Id).as_array()); } else { diff --git a/shaders.cpp b/shaders.cpp index ffd11630..31f73db7 100644 --- a/shaders.cpp +++ b/shaders.cpp @@ -77,7 +77,7 @@ EX string panini_shader() { "float s = t.z;\n" "float l = length(t.xyz);\n" "t /= max(length(t.xz), 1e-2);\n" - "t.z += " + glhr::to_glsl(panini_alpha) + ";\n" + "t.z += " + glhr::to_glsl(get_stereo_param()) + ";\n" "t *= l;\n" "t.w = 1.;\n"; } @@ -88,7 +88,7 @@ EX string stereo_shader() { "float s = t.z;\n" "float l = length(t.xyz);\n" "t /= max(l, 1e-2);\n" - "t.z += " + glhr::to_glsl(stereo_alpha) + ";\n" + "t.z += " + glhr::to_glsl(get_stereo_param()) + ";\n" "t *= l;\n" "t.w = 1.;\n"; } @@ -515,13 +515,13 @@ shared_ptr write_shader(flagtype shader_flags) { if(shader_flags & GF_LEVELS) vmain += "vPos = t;\n"; if(treset) vmain += "t[3] = 1.0;\n"; - if((shader_flags & SF_PERS3) && panini_alpha && !vrhr::rendering_eye()) { + if((shader_flags & SF_PERS3) && vid.stereo_mode == sPanini && !vrhr::rendering_eye()) { vmain += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;"; /* panini */ vmain += panini_shader(); shader_flags |= SF_ORIENT; } - else if((shader_flags & SF_PERS3) && stereo_alpha && !vrhr::rendering_eye()) { + else if((shader_flags & SF_PERS3) && vid.stereo_mode == sStereographic && !vrhr::rendering_eye()) { vmain += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;"; vmain += stereo_shader(); shader_flags |= SF_ORIENT; diff --git a/sysconfig.h b/sysconfig.h index 7a87f459..45ab04f9 100644 --- a/sysconfig.h +++ b/sysconfig.h @@ -190,7 +190,7 @@ #endif #ifndef CAP_ODS -#define CAP_ODS 0 +#define CAP_ODS 1 #endif #ifndef CAP_VIDEO