device orientation-based scrolling on mobiles

This commit is contained in:
Zeno Rogue 2018-07-23 05:14:19 +02:00
parent bd77680518
commit 6c0a052470
8 changed files with 181 additions and 5 deletions

View File

@ -629,7 +629,7 @@ void achievement_final(bool really_final) {
specific_improved = 0;
specific_what = 0;
if(specials == 0) improveItemScores();
if(specialcode == 0) improveItemScores();
int tg = gold();
if(tg && haveLeaderboard(sid)) {

View File

@ -661,7 +661,7 @@ void showGraphConfig() {
char xuni = uni | 96;
if(uni >= 32 && uni < 64) xuni = uni;
if(xuni == 'u') vid.particles = !vid.particles;
if(xuni == 'd') vid.graphglyph = (1+vid.graphglyph)%3;
@ -829,6 +829,8 @@ void showBasicConfig() {
dialog::addBoolItem(XLAT("forget faraway cells"), memory_saving_mode, 'y');
dialog::addSelItem(XLAT("scrolling by device rotation"), ors::choices[ors::mode], '1');
if(CAP_SHMUP && !ISMOBILE)
dialog::addSelItem(XLAT("configure keys/joysticks"), "", 'p');
@ -846,6 +848,8 @@ void showBasicConfig() {
if(uni >= 32 && uni < 64) xuni = uni;
if(xuni == '1') pushScreen(ors::show);
if(uni == 'M') vid.quickmouse = !vid.quickmouse;
else if(xuni == 'm') vid.skipstart = !vid.skipstart;
@ -1467,5 +1471,5 @@ int read_gamemode_args() {
auto ah_config = addHook(hooks_args, 0, read_config_args) + addHook(hooks_args, 0, read_gamemode_args);
#endif
}

View File

@ -517,6 +517,7 @@ void mainloopiter() {
if(timetowait > 0)
SDL_Delay(timetowait);
else {
ors::check_orientation();
if(cmode & sm::CENTER) {
if(playermoved && vid.sspeed > -4.99 && !outoffocus)
centerpc((ticks - lastt) / 1000.0 * exp(vid.sspeed));
@ -908,4 +909,144 @@ bool handleCompass() {
return false;
}
// orientation sensitivity
namespace ors {
int mode;
double sensitivity = 1;
int when_enabled;
transmatrix last_orientation;
transmatrix relative_matrix = Id;
string choices[3] = {"OFF", "relative", "absolute"};
#if CAP_ORIENTATION
transmatrix getOrientation() {
return MirrorX * MirrorZ * hr::getOrientation() * MirrorX * MirrorZ;
}
#endif
void reset() {
#if CAP_ORIENTATION
if(mode) last_orientation = getOrientation();
relative_matrix = Id;
#endif
}
void delayed_reset() {
#if CAP_ORIENTATION
relative_matrix = Id; when_enabled = ticks;
#endif
}
void show() {
#if CAP_ORIENTATION
cmode = sm::SIDE;
gamescreen(0);
dialog::init(XLAT("scrolling by device rotation"));
dialog::addHelp(XLAT(
"This lets you scroll the map by rotating your device. It can be e.g. used to "
"play the spherical mode of HyperRogue in mobile VR goggles -- the \"spherical VR\" "
"button configures this; this VR mode can be disabled by touching the screen for 1 second."));
dialog::addSelItem(XLAT("mode"), choices[mode], 'm');
dialog::add_action([] () { int m = (mode + 1) % 3; mode = 0; fullcenter(); mode = m; delayed_reset(); });
dialog::addSelItem(XLAT("sensitivity"), fts(sensitivity), 's');
dialog::add_action([] () {
dialog::editNumber(sensitivity, -10, 10, 1, 1, XLAT("sensitivity"),
XLAT("1 means that rotating the device by 1 radian corresponds to scrolling by 1 unit. In spherical geometry, 1 unit = 1 radian."));
});
dialog::addBreak(100);
dialog::addItem(XLAT("stereo vision config"), 'e');
dialog::add_action([] () { pushScreen(showStereo); });
dialog::addItem(XLAT("experiment with geometry"), 'g');
dialog::add_action([] () { runGeometryExperiments(); });
dialog::addSelItem(XLAT("projection"), fts(vid.alpha), 'p');
dialog::add_action([] () { projectionDialog(); });
dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z');
dialog::add_action([] () { editScale(); });
dialog::addItem(XLAT("spherical VR"), 'v');
dialog::add_action([] () {
if(!sphere) { targetgeometry = gSphere; restart_game(rg::geometry); }
mode = 0; fullcenter();
mode = 2; sensitivity = 1;
stereo::mode = sLR; stereo::ipd = 0.2;
vid.alpha = 0; vid.scale = 1;
});
dialog::addBreak(100);
dialog::addBack();
dialog::display();
#endif
}
void relative_apply() {
if(ors::mode == 1) View = relative_matrix * View;
}
void relative_unapply() {
if(ors::mode == 1) View = inverse(relative_matrix) * View;
}
transmatrix change_geometry(const transmatrix& T) {
if(sphere && sensitivity == 1) return T;
ld alpha, beta, push;
{
dynamicval<eGeometry> g(geometry, gSphere);
hyperpoint h = T * C0;
push = hdist0(h);
alpha = atan2(h[1], h[0]);
if(push == 0) alpha = 0;
hyperpoint spinpoint = gpushxto0(h) * T * xpush(1) * C0;
beta = atan2(spinpoint[1], spinpoint[0]);
}
// gpushxto0(h) * T * xpush(1) * C0 == spin(beta) * xpush(1) * C0
// gpushxto0(h) * T == spin(beta)
// T = rgpushxto0(h) * spin(beta)
transmatrix U = spin(-alpha) * xpush(push * sensitivity) * spin(-beta+alpha);
return U;
}
void unrotate(transmatrix& T) {
if(mode == 1) T = inverse(relative_matrix) * T;
}
void rerotate(transmatrix& T) {
if(mode == 1) T = (relative_matrix) * T;
}
void check_orientation() {
#if CAP_ORIENTATION
if(!mode) return;
if(ticks < when_enabled + 500) {
last_orientation = getOrientation();
return;
}
transmatrix next_orientation = MirrorX * getOrientation();
transmatrix T = inverse(next_orientation) * last_orientation;
if(mode == 1) unrotate(View), unrotate(cwtV);
relative_matrix = change_geometry(T);
if(mode == 1) rerotate(View), rerotate(cwtV);
if(mode == 2) View = relative_matrix * View, last_orientation = next_orientation;
#endif
}
}
}

12
hyper.h
View File

@ -3727,4 +3727,16 @@ extern void switchHardcore();
extern bool using_perspective;
void generateAlts(heptagon *h, int levs = irr::on ? 1 : S3-3, bool link_cdata = true);
namespace ors {
extern int mode;
extern string choices[];
void show();
void apply();
void check_orientation();
void unrotate(transmatrix& T);
void rerotate(transmatrix& T);
void reset();
}
}

View File

@ -242,6 +242,9 @@ const transmatrix Mirror = {{{1,0,0}, {0,-1,0}, {0,0,1}}};
// mirror image
const transmatrix MirrorX = {{{-1,0,0}, {0,1,0}, {0,0,1}}};
// mirror image
const transmatrix MirrorZ = {{{1,0,0}, {0,1,0}, {0,0,-1}}};
// rotate by PI
const transmatrix pispin = {{{-1,0,0}, {0,-1,0}, {0,0,1}}};

View File

@ -730,8 +730,12 @@ void spinEdge(ld aspd) {
}
void centerpc(ld aspd) {
if(ors::mode == 2 && vid.sspeed < 5) return;
if(vid.sspeed >= 4.99) aspd = 1000;
DEBB(DF_GRAPH, (debugfile,"center pc\n"));
ors::unrotate(cwtV); ors::unrotate(View);
hyperpoint H = ypush(-vid.yshift) * sphereflip * tC0(cwtV);
ld R = H[0] == 0 && H[1] == 0 ? 0 : hdist0(H); // = sqrt(H[0] * H[0] + H[1] * H[1]);
if(R < 1e-9) {
@ -741,6 +745,7 @@ void centerpc(ld aspd) {
} */
spinEdge(aspd);
fixmatrix(View);
ors::rerotate(cwtV); ors::rerotate(View);
return;
}
@ -766,6 +771,8 @@ void centerpc(ld aspd) {
fixmatrix(View);
spinEdge(aspd);
}
ors::rerotate(cwtV); ors::rerotate(View);
}
void optimizeview() {

View File

@ -168,6 +168,7 @@ void handleclick(MOBPAR_FORMAL) {
if(andmode == 0 && shmup::on) ; // just fire, do not change modes
else {
if(andmode == 1) {
ors::reset();
centerpc(INF);
View = Id;
viewctr.h = cwt.c->master;
@ -235,6 +236,8 @@ void mobile_draw(MOBPAR_FORMAL) {
if(lastt > ticks) lastt = ticks;
int tdiff = ticks - lastt;
ors::check_orientation();
if(playermoved && vid.sspeed > -4.99)
centerpc(tdiff / 1000.0 * exp(vid.sspeed));
@ -287,6 +290,11 @@ void mobile_draw(MOBPAR_FORMAL) {
#endif
mouseh = gethyper(mousex, mousey);
inmenu = isize(screens) > 1;
if(!inmenu && stereo::mode == stereo::sLR && ors::mode)
mousex = vid.xres/2, mousey = vid.yres/2, mouseh = sphereflip * C0;
// if(debfile) fprintf(debfile, "d1\n"), fflush(debfile);
frames++;
if(conformal::on) conformal::apply();
@ -303,8 +311,6 @@ void mobile_draw(MOBPAR_FORMAL) {
shiftmul = getcshift;
calcMousedest();
inmenu = isize(screens) > 1;
if(lclicked && !clicked && !inmenu) handleclick(MOBPAR_ACTUAL);
if(inmenu && !clicked && !lclicked) inmenu = false;
@ -336,6 +342,8 @@ void mobile_draw(MOBPAR_FORMAL) {
if(lclicked && !clicked) {
if(rug::rugged)
rug::select();
else if(ors::mode && !longclick)
normal_reaction = true;
else
pushScreen(showStereo);
}

View File

@ -1176,6 +1176,7 @@ void switch_game_mode(char switchWhat) {
break;
case rg::geometry:
ors::reset();
if(geometry == targetgeometry) geometry = gNormal;
else geometry = targetgeometry;
if(chaosmode && (euclid || sphere || quotient)) chaosmode = false;