mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-04-14 14:53:20 +00:00
initial implementation of VR
This commit is contained in:
parent
4444fa6bf1
commit
0de8ce9a10
@ -293,6 +293,10 @@ EX void setGLProjection(color_t col IS(backcolor)) {
|
||||
|
||||
glClearColor(part(col, 2) / 255.0, part(col, 1) / 255.0, part(col, 0) / 255.0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
#if CAP_VR
|
||||
vrhr::clear();
|
||||
#endif
|
||||
|
||||
GLERR("setGLProjection #1");
|
||||
|
||||
|
@ -1911,6 +1911,12 @@ EX void show3D() {
|
||||
dialog::addInfo(XLAT("parameters set correctly"));
|
||||
dialog::addBreak(50);
|
||||
dialog::addItem(XLAT("stereo vision config"), 'e');
|
||||
|
||||
#if CAP_VR
|
||||
dialog::addBoolItem(XLAT("VR settings"), vrhr::state > 0, 'v');
|
||||
dialog::add_action_push(vrhr::show_vr_settings);
|
||||
#endif
|
||||
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
|
||||
|
44
control.cpp
44
control.cpp
@ -26,6 +26,7 @@ EX bool holdmouse;
|
||||
EX int getcstat, lgetcstat;
|
||||
EX ld getcshift;
|
||||
EX bool inslider;
|
||||
EX int slider_x;
|
||||
|
||||
EX function <void(int sym, int uni)> keyhandler = [] (int sym, int uni) {};
|
||||
EX function <bool(SDL_Event &ev)> joyhandler = [] (SDL_Event &ev) {return false;};
|
||||
@ -134,6 +135,11 @@ EX void movepckeydir(int d) {
|
||||
if(!canmove) movepcto(md), remission(); else movepcto(md);
|
||||
}
|
||||
|
||||
EX void movevrdir(hyperpoint vec) {
|
||||
movedir md = vectodir(vec);
|
||||
if(!canmove) movepcto(md), remission(); else movepcto(md);
|
||||
}
|
||||
|
||||
EX void calcMousedest() {
|
||||
if(mouseout()) return;
|
||||
if(vid.revcontrol == true) { mouseh[0] = -mouseh[0]; mouseh[1] = -mouseh[1]; }
|
||||
@ -278,6 +284,7 @@ EX bool quitmainloop = false;
|
||||
EX bool doexiton(int sym, int uni) {
|
||||
if(sym == SDLK_ESCAPE) return true;
|
||||
if(sym == SDLK_F10) return true;
|
||||
if(sym == PSEUDOKEY_EXIT) return true;
|
||||
if(sym == PSEUDOKEY_RELEASE) return false;
|
||||
#ifndef FAKE_SDL
|
||||
if(sym == SDLK_LSHIFT) return false;
|
||||
@ -329,6 +336,14 @@ EX void full_forward_camera(ld t) {
|
||||
}
|
||||
}
|
||||
|
||||
EX void full_strafe_camera(ld t) {
|
||||
if(GDIM == 3) {
|
||||
shift_view(ctangent(0, t * camera_speed));
|
||||
didsomething = true;
|
||||
playermoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
EX void full_rotate_camera(int dir, ld val) {
|
||||
if(rug::rug_control() && lshiftclick) {
|
||||
val *= camera_rot_speed;
|
||||
@ -548,6 +563,9 @@ EX void handleKeyNormal(int sym, int uni) {
|
||||
|
||||
if(sym == 'v' && DEFAULTNOR(sym))
|
||||
pushScreen(showMainMenu);
|
||||
|
||||
if(sym == PSEUDOKEY_MENU)
|
||||
pushScreen(showMainMenu);
|
||||
|
||||
if(sym == '-' || sym == PSEUDOKEY_WHEELDOWN) {
|
||||
actonrelease = false;
|
||||
@ -643,6 +661,10 @@ EX void mainloopiter() {
|
||||
vid.monmode = 0;
|
||||
#endif
|
||||
|
||||
#if CAP_VR
|
||||
vrhr::vr_shift();
|
||||
#endif
|
||||
|
||||
optimizeview();
|
||||
|
||||
models::configure();
|
||||
@ -759,6 +781,18 @@ EX void mainloopiter() {
|
||||
SDL_Event ev;
|
||||
DEBB(DF_GRAPH, ("polling for events\n"));
|
||||
|
||||
#if CAP_VR
|
||||
if(vrhr::state) {
|
||||
rug::using_rugview urv;
|
||||
dynamicval<bool> ds(didsomething, didsomething);
|
||||
using namespace vrhr;
|
||||
if(vraim_x) full_rotate_camera(0, -vraim_x / 20);
|
||||
if(vraim_y) full_rotate_camera(1, vraim_y / 20);
|
||||
if(vrgo_y) full_forward_camera(-vrgo_y / 20);
|
||||
if(vrgo_x) full_strafe_camera(-vrgo_x / 20);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(mouseaiming(shmup::on)) {
|
||||
#if CAP_MOUSEGRAB
|
||||
rug::using_rugview urv;
|
||||
@ -787,7 +821,17 @@ EX void mainloopiter() {
|
||||
}
|
||||
else sc_ticks = ticks;
|
||||
|
||||
#if CAP_VR
|
||||
vrhr::vr_control();
|
||||
#endif
|
||||
achievement_pump();
|
||||
|
||||
for(auto d: dialog::key_queue) {
|
||||
println(hlog, "handling key ", d);
|
||||
handlekey(d, d);
|
||||
}
|
||||
dialog::key_queue.clear();
|
||||
|
||||
while(SDL_PollEvent(&ev)) handle_event(ev);
|
||||
fix_mouseh();
|
||||
#if CAP_SDLJOY
|
||||
|
58
dialogs.cpp
58
dialogs.cpp
@ -379,7 +379,17 @@ EX namespace dialog {
|
||||
|
||||
EX purehookset hooks_display_dialog;
|
||||
|
||||
EX vector<int> key_queue;
|
||||
|
||||
EX void queue_key(int key) { key_queue.push_back(key); }
|
||||
|
||||
EX void display() {
|
||||
|
||||
#if CAP_VR
|
||||
for(auto h: vrhr::get_hits())
|
||||
displaystr(h.x, h.y, 2, vid.fsize * 2, "X", 0xFFD500, 8);
|
||||
#endif
|
||||
|
||||
callhooks(hooks_display_dialog);
|
||||
int N = items.size();
|
||||
dfsize = vid.fsize;
|
||||
@ -432,6 +442,16 @@ EX namespace dialog {
|
||||
xthis = xthis && (mousex >= dcenter - dialogwidth/2 && mousex <= dcenter + dialogwidth/2);
|
||||
displayfr(dcenter, mid, 2, dfsize * I.scale/100, I.body, I.color, 8);
|
||||
if(xthis) getcstat = I.key;
|
||||
|
||||
#if CAP_VR
|
||||
for(auto h: vrhr::get_hits()) {
|
||||
bool vrthis = (h.y >= top && h.y < tothei);
|
||||
if(cmode & sm::DIALOG_STRICT_X)
|
||||
vrthis = vrthis && (mousex >= dcenter - dialogwidth/2 && mousex <= dcenter + dialogwidth/2);
|
||||
if(vrthis) I.color = I.colors;
|
||||
if(vrthis && h.clicked) queue_key(I.key);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(I.type == diItem || I.type == diBigItem) {
|
||||
bool xthis = (mousey >= top && mousey < tothei);
|
||||
@ -449,6 +469,19 @@ EX namespace dialog {
|
||||
I.color = (xthis&&mousepressed&&actonrelease) ? I.colorc : I.colors;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CAP_VR
|
||||
for(auto h: vrhr::get_hits()) {
|
||||
bool vrthis = (h.y >= top && h.y < tothei);
|
||||
if(cmode & sm::DIALOG_STRICT_X)
|
||||
vrthis = vrthis && (mousex >= dcenter - dialogwidth/2 && mousex <= dcenter + dialogwidth/2);
|
||||
if(vrthis) I.color = I.colors;
|
||||
if(vrthis && h.clicked) {
|
||||
queue_key(I.key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(I.type == diBigItem) {
|
||||
displayfr(dcenter, mid, 2, dfsize * I.scale/100, I.body, I.color, 8);
|
||||
}
|
||||
@ -482,7 +515,17 @@ EX namespace dialog {
|
||||
displayfr(sl + double(sw * I.p1 / I.p2), mid, 2, dfsize * I.scale/100, "#", I.color, 8);
|
||||
displayfr(sr, mid, 2, dfsize * I.scale/100, "}", I.color, 0);
|
||||
}
|
||||
if(xthis) getcstat = I.key, inslider = true;
|
||||
if(xthis) getcstat = I.key, inslider = true, slider_x = mousex;
|
||||
|
||||
#if CAP_VR
|
||||
for(auto h: vrhr::get_hits()) {
|
||||
bool vrthis = (h.y >= top && h.y < tothei);
|
||||
if(cmode & sm::DIALOG_STRICT_X)
|
||||
vrthis = vrthis && (mousex >= dcenter - dialogwidth/2 && mousex <= dcenter + dialogwidth/2);
|
||||
if(vrthis) I.color = I.colors;
|
||||
if(vrthis && h.clicked) queue_key(I.key), inslider = true, slider_x = h.x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(I.type == diKeyboard) {
|
||||
int len = 0;
|
||||
@ -612,7 +655,7 @@ EX namespace dialog {
|
||||
int shift = colorAlpha ? 0 : 8;
|
||||
|
||||
if(uni >= 'A' && uni <= 'D') {
|
||||
int x = (mousex - (dcenter-dwidth/4)) * 510 / dwidth;
|
||||
int x = (slider_x - (dcenter-dwidth/4)) * 510 / dwidth;
|
||||
if(x < 0) x = 0;
|
||||
if(x > 255) x = 255;
|
||||
part(color, uni - 'A') = x;
|
||||
@ -705,7 +748,14 @@ EX namespace dialog {
|
||||
displayColorButton(dcenter - dwidth/4 + dwidth * part(color, i) / 510, y, "#", 0, 8, 0, col);
|
||||
|
||||
if(mousey >= y - vid.fsize && mousey < y + vid.fsize)
|
||||
getcstat = 'A' + i, inslider = true;
|
||||
getcstat = 'A' + i, inslider = true, slider_x = mousex;
|
||||
|
||||
#if CAP_VR
|
||||
for(auto h: vrhr::get_hits()) {
|
||||
bool vrthis = (h.y >= y - vid.fsize && h.y < y + vid.fsize);
|
||||
if(vrthis && h.clicked) queue_key('A' + i), inslider = true, slider_x = h.x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
displayColorButton(dcenter, vid.yres/2+vid.fsize * 6, XLAT("select this color") + " : " + format(colorAlpha ? "%08X" : "%06X", color), ' ', 8, 0, color >> (colorAlpha ? ash : 0));
|
||||
@ -884,7 +934,7 @@ EX namespace dialog {
|
||||
sl = vid.yres + vid.fsize*2, sr = vid.xres - vid.fsize*2;
|
||||
else
|
||||
sl = vid.xres/4, sr = vid.xres*3/4;
|
||||
ld d = (mousex - sl + .0) / (sr-sl);
|
||||
ld d = (slider_x - sl + .0) / (sr-sl);
|
||||
ld val = ne.sc.inverse(d * (ne.sc.direct(ne.vmax) - ne.sc.direct(ne.vmin)) + ne.sc.direct(ne.vmin));
|
||||
ld nextval = ne.sc.inverse((mousex + 1. - sl) / (sr - sl) * (ne.sc.direct(ne.vmax) - ne.sc.direct(ne.vmin)) + ne.sc.direct(ne.vmin));
|
||||
ld dif = abs(val - nextval);
|
||||
|
36
drawing.cpp
36
drawing.cpp
@ -208,22 +208,31 @@ EX void glflush() {
|
||||
}
|
||||
shapes_merged = 0;
|
||||
#endif
|
||||
|
||||
|
||||
if(isize(text_vertices)) {
|
||||
// printf("%08X | %d texts, %d vertices\n", text_color, texts_merged, isize(text_vertices));
|
||||
current_display->next_shader_flags = GF_TEXTURE;
|
||||
dynamicval<eModel> m(pmodel, mdPixel);
|
||||
if(!svg::in) current_display->set_all(0,0);
|
||||
glBindTexture(GL_TEXTURE_2D, text_texture);
|
||||
glhr::color2(text_color);
|
||||
glhr::set_depthtest(false);
|
||||
for(int ed = (current_display->stereo_active() && text_shift)?-1:0; ed<2; ed+=2) {
|
||||
glhr::set_modelview(glhr::translate(-ed*text_shift-current_display->xcenter,-current_display->ycenter, 0));
|
||||
current_display->set_mask(ed);
|
||||
|
||||
|
||||
auto drawer = [] {
|
||||
glhr::color2(text_color);
|
||||
glBindTexture(GL_TEXTURE_2D, text_texture);
|
||||
glhr::set_depthtest(false);
|
||||
glhr::current_vertices = NULL;
|
||||
glhr::prepare(text_vertices);
|
||||
glDrawArrays(GL_TRIANGLES, 0, isize(text_vertices));
|
||||
};
|
||||
|
||||
#if CAP_VR
|
||||
if(vrhr::state == 1 && !(cmode & sm::NORMAL))
|
||||
vrhr::in_vr_ui(drawer);
|
||||
|
||||
else
|
||||
#endif
|
||||
for(int ed = (current_display->stereo_active() && text_shift)?-1:0; ed<2; ed+=2) {
|
||||
glhr::set_modelview(glhr::translate(-ed*text_shift-current_display->xcenter,-current_display->ycenter, 0));
|
||||
current_display->set_mask(ed);
|
||||
drawer();
|
||||
|
||||
GLERR("print");
|
||||
}
|
||||
@ -2294,11 +2303,18 @@ EX void draw_main() {
|
||||
EX void drawqueue() {
|
||||
|
||||
DEBBI(DF_GRAPH, ("drawqueue"));
|
||||
|
||||
|
||||
#if CAP_WRL
|
||||
if(wrl::in) { wrl::render(); return; }
|
||||
#endif
|
||||
|
||||
#if CAP_VR
|
||||
if(vrhr::state == 1) {
|
||||
vrhr::render();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
callhooks(hooks_drawqueue);
|
||||
current_display->next_shader_flags = 0;
|
||||
reset_projection();
|
||||
|
@ -1235,6 +1235,9 @@ void geometry_information::make_floor_textures_here() {
|
||||
cd->radius = cd->scrsize * pconf.scale;
|
||||
|
||||
floor_textures->enable();
|
||||
#if CAP_VR
|
||||
dynamicval<int> i(vrhr::state, 0);
|
||||
#endif
|
||||
floor_textures->clear(0); // 0xE8E8E8 = 1
|
||||
|
||||
// gradient vertices
|
||||
|
52
graph.cpp
52
graph.cpp
@ -3724,6 +3724,10 @@ void make_clipping_planes() {
|
||||
#if MAXMDIM >= 4
|
||||
clipping_planes.clear();
|
||||
if(!frustum_culling || PIU(sphere) || experimental || vid.stereo_mode == sODS || panini_alpha) return;
|
||||
#if CAP_VR
|
||||
if(vrhr::state) return;
|
||||
#endif
|
||||
|
||||
auto add_clipping_plane = [] (ld x1, ld y1, ld x2, ld y2) {
|
||||
ld z1 = 1, z2 = 1;
|
||||
hyperpoint sx = point3(y1 * z2 - y2 * z1, z1 * x2 - z2 * x1, x1 * y2 - x2 * y1);
|
||||
@ -4151,6 +4155,11 @@ EX void queuecircleat(cell *c, double rad, color_t col) {
|
||||
#endif
|
||||
|
||||
EX cell *forwardcell() {
|
||||
#if CAP_VR
|
||||
if(vrhr::state) {
|
||||
return vrhr::forward_cell;
|
||||
}
|
||||
#endif
|
||||
movedir md = vectodir(move_destination_vec(6));
|
||||
cellwalker xc = cwt + md.d + wstep;
|
||||
return xc.at;
|
||||
@ -4279,7 +4288,7 @@ EX void drawMarkers() {
|
||||
|
||||
if(GDIM == 3 && !inHighQual && !shmup::on && vid.axes3 && playermoved) {
|
||||
cell *c = forwardcell();
|
||||
queuecircleat(c, .8, getcs().uicolor);
|
||||
if(c) queuecircleat(c, .8, getcs().uicolor);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -4868,10 +4877,14 @@ EX void calcparam() {
|
||||
cd->ycenter = lerp(vid.fsize + cd->scrsize, vid.yres - cd->scrsize - vid.fsize, .8);
|
||||
}
|
||||
else {
|
||||
if(vid.xres > vid.yres * 4/3+16 && (cmode & sm::SIDE))
|
||||
bool ok = true;
|
||||
#if CAP_VR
|
||||
ok = ok && !vrhr::state;
|
||||
#endif
|
||||
if(vid.xres > vid.yres * 4/3+16 && (cmode & sm::SIDE) && ok)
|
||||
current_display->sidescreen = true;
|
||||
#if CAP_TOUR
|
||||
if(tour::on && (tour::slides[tour::currentslide].flags & tour::SIDESCREEN))
|
||||
if(tour::on && (tour::slides[tour::currentslide].flags & tour::SIDESCREEN) && ok)
|
||||
current_display->sidescreen = true;
|
||||
#endif
|
||||
|
||||
@ -5017,6 +5030,9 @@ EX void gamescreen(int _darken) {
|
||||
}
|
||||
|
||||
darken = _darken;
|
||||
#if CAP_VR
|
||||
if(vrhr::state) darken = 0;
|
||||
#endif
|
||||
|
||||
if(history::includeHistory) history::restore();
|
||||
|
||||
@ -5062,6 +5078,31 @@ EX void gamescreen(int _darken) {
|
||||
if(texture::config.tstate == texture::tsAdjusting)
|
||||
texture::config.drawRawTexture();
|
||||
#endif
|
||||
|
||||
#if CAP_VR
|
||||
if(vrhr::state && _darken) {
|
||||
int xsi = current_display->xsize;
|
||||
int ysi = current_display->ysize;
|
||||
color_t col = 0x000000C0;
|
||||
current_display->next_shader_flags = 0;
|
||||
dynamicval<eModel> m(pmodel, mdPixel);
|
||||
|
||||
vrhr::in_vr_ui([&] {
|
||||
glhr::color2(col);
|
||||
glhr::set_depthtest(false);
|
||||
vector<glvertex> vs;
|
||||
vs.emplace_back(glhr::makevertex(0, 0, 0));
|
||||
vs.emplace_back(glhr::makevertex(xsi, 0, 0));
|
||||
vs.emplace_back(glhr::makevertex(xsi, ysi, 0));
|
||||
vs.emplace_back(glhr::makevertex(0, 0, 0));
|
||||
vs.emplace_back(glhr::makevertex(0, ysi, 0));
|
||||
vs.emplace_back(glhr::makevertex(xsi, ysi, 0));
|
||||
glhr::current_vertices = NULL;
|
||||
glhr::vertices(vs);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EX bool nohelp;
|
||||
@ -5232,6 +5273,11 @@ EX void drawscreen() {
|
||||
|
||||
glflush();
|
||||
DEBB(DF_GRAPH, ("swapbuffers"));
|
||||
|
||||
#if CAP_VR
|
||||
vrhr::submit();
|
||||
#endif
|
||||
|
||||
#if CAP_SDL
|
||||
#if CAP_GL
|
||||
if(vid.usingGL) SDL_GL_SwapBuffers(); else
|
||||
|
@ -120,6 +120,7 @@
|
||||
#include "multigame.cpp"
|
||||
#include "inforder.cpp"
|
||||
#include "dpgen.cpp"
|
||||
#include "vr.cpp"
|
||||
|
||||
#if CAP_ROGUEVIZ
|
||||
#include "rogueviz/rogueviz-all.cpp"
|
||||
|
32
hypgraph.cpp
32
hypgraph.cpp
@ -1592,6 +1592,38 @@ EX hyperpoint vertical_vector() {
|
||||
}
|
||||
|
||||
EX void spinEdge(ld aspd) {
|
||||
|
||||
#if CAP_VR
|
||||
if(vrhr::state && keep_vertical()) {
|
||||
transmatrix T = vrhr::hmd_ref_at;
|
||||
T = vrhr::sm * inverse(T);
|
||||
vrhr::be_33(T);
|
||||
|
||||
transmatrix V = T * get_view_orientation();
|
||||
|
||||
hyperpoint h = inverse(V) * C0;
|
||||
V = V * rgpushxto0(h);
|
||||
|
||||
V = cspin(2, 1, 90 * degree) * V;
|
||||
|
||||
if(1) {
|
||||
dynamicval<eGeometry> g(geometry, gSphere);
|
||||
bool b = vid.always3;
|
||||
vid.always3 = false;
|
||||
geom3::apply_always3();
|
||||
V = gpushxto0(V*C0) * V;
|
||||
if(b) {
|
||||
vid.always3 = b;
|
||||
geom3::apply_always3();
|
||||
}
|
||||
}
|
||||
|
||||
V = cspin(1, 2, 90 * degree) * V;
|
||||
get_view_orientation() = inverse(T) * V * gpushxto0(h);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ld downspin = 0;
|
||||
auto& ds = downseek;
|
||||
if(dual::state == 2 && (dual::one_euclidean ? !euclid : dual::currently_loaded != dual::main_side)) {
|
||||
|
@ -598,7 +598,7 @@ EX namespace sn {
|
||||
"if(iz < 0.05 && ix > .85 && iy > .45 && iy < .75) ok = false;"
|
||||
"if(iz < 0.025 && ix > .65 && iy > .65 && ix < .8 && iy < .8) ok = false;"
|
||||
|
||||
"if(!ok) res = vec4(0,0,0,1);"
|
||||
"if(!ok) res = vec4(0./0.,0./0.,0./0.,1);"
|
||||
"else "
|
||||
|
||||
"\n#endif\n"
|
||||
|
@ -76,6 +76,9 @@ bool need_many_cell_types() {
|
||||
|
||||
/** is the raycaster available? */
|
||||
EX bool available() {
|
||||
#if CAP_VR
|
||||
if(vrhr::state) return false; /* not implemented */
|
||||
#endif
|
||||
if(noGUI) return false;
|
||||
if(!vid.usingGL) return false;
|
||||
if(GDIM == 2) return false;
|
||||
|
6
rug.cpp
6
rug.cpp
@ -1021,6 +1021,9 @@ EX void prepareTexture() {
|
||||
|
||||
dynamicval<eStereo> d(vid.stereo_mode, sOFF);
|
||||
dynamicval<ld> dl(levellines, 0);
|
||||
#if CAP_VR
|
||||
dynamicval<int> i(vrhr::state, 0);
|
||||
#endif
|
||||
calcparam_rug();
|
||||
models::configure();
|
||||
|
||||
@ -1084,6 +1087,9 @@ EX void drawRugScene() {
|
||||
|
||||
auto& rug = queuecurve(shiftless(Id), 0, 0xFFFFFFFF, PPR::LINE);
|
||||
|
||||
dynamicval<transmatrix> tV(View, View);
|
||||
View = Id; /* needed for vr */
|
||||
|
||||
if(nonisotropic) {
|
||||
transmatrix T2 = eupush( tC0(view_inverse(rugView)) );
|
||||
NLP = rugView * T2;
|
||||
|
107
shaders.cpp
107
shaders.cpp
@ -202,7 +202,13 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
|
||||
"mediump float d = dot(t.xyz, t.xyz);\n"
|
||||
"mediump float hz = (1.+d) / (1.-d);\n"
|
||||
"mediump float ad = acosh(hz);\n"
|
||||
"mediump float m = d == 0. ? 0. : d >= 1. ? 1.e4 : (hz+1.) * ad / sinh(ad);\n"
|
||||
"mediump float m = d == 0. ? 0. : d >= 1. ? 1.e4 : (hz+1.) * ad / sinh(ad);\n";
|
||||
#if CAP_VR
|
||||
if(vrhr::state == 2)
|
||||
coordinator += "t.xyz *= ad/d;\n";
|
||||
else
|
||||
#endif
|
||||
coordinator +=
|
||||
"t.xyz *= m;\n";
|
||||
distfun = "ad";
|
||||
}
|
||||
@ -295,7 +301,11 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
|
||||
if(!skip_t) {
|
||||
vmain += "mediump vec4 t = uMV * aPosition;\n";
|
||||
vmain += coordinator;
|
||||
if(GDIM == 3 && WDIM == 2 && hyperbolic && context_fog && pmodel == mdPerspective) {
|
||||
bool ok = true;
|
||||
#if CAP_VR
|
||||
if(vrhr::state) ok = false;
|
||||
#endif
|
||||
if(GDIM == 3 && WDIM == 2 && hyperbolic && context_fog && ok && pmodel == mdPerspective) {
|
||||
vsh +=
|
||||
"uniform mediump mat4 uRadarTransform;\n"
|
||||
"uniform mediump sampler2D tAirMap;\n"
|
||||
@ -407,6 +417,9 @@ void display_data::set_projection(int ed, ld shift) {
|
||||
id <<= 6; id |= shader_flags;
|
||||
id <<= 6; id |= spherephase;
|
||||
id <<= 1; if(vid.consider_shader_projection) id |= 1;
|
||||
#if CAP_VR
|
||||
id <<= 3; id |= vrhr::state;
|
||||
#endif
|
||||
id <<= 2; id |= (spherespecial & 3);
|
||||
if(sol && solv_all) id |= 1;
|
||||
if(in_h2xe()) id |= 1;
|
||||
@ -459,22 +472,28 @@ void display_data::set_projection(int ed, ld shift) {
|
||||
}
|
||||
|
||||
glhr::new_projection();
|
||||
|
||||
if(ed && vid.stereo_mode == sLR) {
|
||||
glhr::projection_multiply(glhr::translate(ed, 0, 0));
|
||||
glhr::projection_multiply(glhr::scale(2, 1, 1));
|
||||
}
|
||||
|
||||
ld tx = (cd->xcenter-cd->xtop)*2./cd->xsize - 1;
|
||||
ld ty = (cd->ycenter-cd->ytop)*2./cd->ysize - 1;
|
||||
glhr::projection_multiply(glhr::translate(tx, -ty, 0));
|
||||
|
||||
if(pmodel == mdManual) return;
|
||||
|
||||
if(pconf.stretch != 1 && (shader_flags & SF_DIRECT) && pmodel != mdPixel) glhr::projection_multiply(glhr::scale(1, pconf.stretch, 1));
|
||||
#if CAP_VR
|
||||
if(vrhr::state != 2) {
|
||||
#else
|
||||
if(true) {
|
||||
#endif
|
||||
if(ed && vid.stereo_mode == sLR) {
|
||||
glhr::projection_multiply(glhr::translate(ed, 0, 0));
|
||||
glhr::projection_multiply(glhr::scale(2, 1, 1));
|
||||
}
|
||||
|
||||
ld tx = (cd->xcenter-cd->xtop)*2./cd->xsize - 1;
|
||||
ld ty = (cd->ycenter-cd->ytop)*2./cd->ysize - 1;
|
||||
glhr::projection_multiply(glhr::translate(tx, -ty, 0));
|
||||
|
||||
if(vid.stereo_mode != sODS)
|
||||
eyewidth_translate(ed);
|
||||
if(pmodel == mdManual) return;
|
||||
|
||||
if(pconf.stretch != 1 && (shader_flags & SF_DIRECT) && pmodel != mdPixel) glhr::projection_multiply(glhr::scale(1, pconf.stretch, 1));
|
||||
|
||||
if(vid.stereo_mode != sODS)
|
||||
eyewidth_translate(ed);
|
||||
}
|
||||
|
||||
auto ortho = [&] (ld x, ld y) {
|
||||
glhr::glmatrix M = glhr::ortho(x, y, 1);
|
||||
@ -498,26 +517,44 @@ void display_data::set_projection(int ed, ld shift) {
|
||||
|
||||
bool u_alpha = false;
|
||||
|
||||
if(shader_flags & SF_PIXELS) ortho(cd->xsize/2, -cd->ysize/2);
|
||||
if(shader_flags & SF_PIXELS) {
|
||||
#if CAP_VR
|
||||
if(vrhr::state == 2) {
|
||||
glhr::projection_multiply(glhr::tmtogl_transpose(vrhr::hmd_mvp));
|
||||
glhr::id_modelview();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
ortho(cd->xsize/2, -cd->ysize/2);
|
||||
}
|
||||
else if(shader_flags & SF_BOX) ortho(cd->xsize/current_display->radius/2, -cd->ysize/current_display->radius/2);
|
||||
else if(shader_flags & SF_ODSBOX) {
|
||||
ortho(M_PI, M_PI);
|
||||
glhr::fog_max(1/sightranges[geometry], darkena(backcolor, 0, 0xFF));
|
||||
}
|
||||
else if(shader_flags & SF_PERS3) {
|
||||
glhr::projection_multiply(glhr::frustum(current_display->tanfov, current_display->tanfov * cd->ysize / cd->xsize));
|
||||
glhr::projection_multiply(glhr::scale(1, -1, -1));
|
||||
if(nisot::local_perspective_used()) {
|
||||
if(prod) {
|
||||
for(int i=0; i<3; i++) NLP[3][i] = NLP[i][3] = 0;
|
||||
NLP[3][3] = 1;
|
||||
}
|
||||
if(!(shader_flags & SF_ORIENT))
|
||||
glhr::projection_multiply(glhr::tmtogl_transpose(NLP));
|
||||
#if CAP_VR
|
||||
if(vrhr::state == 2) {
|
||||
glhr::projection_multiply(glhr::tmtogl_transpose(vrhr::hmd_mvp));
|
||||
}
|
||||
if(ed) {
|
||||
glhr::using_eyeshift = true;
|
||||
glhr::eyeshift = glhr::tmtogl(xpush(vid.ipd * ed/2));
|
||||
#else
|
||||
if(1) {}
|
||||
#endif
|
||||
else {
|
||||
glhr::projection_multiply(glhr::frustum(current_display->tanfov, current_display->tanfov * cd->ysize / cd->xsize));
|
||||
glhr::projection_multiply(glhr::scale(1, -1, -1));
|
||||
if(nisot::local_perspective_used()) {
|
||||
if(prod) {
|
||||
for(int i=0; i<3; i++) NLP[3][i] = NLP[i][3] = 0;
|
||||
NLP[3][3] = 1;
|
||||
}
|
||||
if(!(shader_flags & SF_ORIENT))
|
||||
glhr::projection_multiply(glhr::tmtogl_transpose(NLP));
|
||||
}
|
||||
if(ed) {
|
||||
glhr::using_eyeshift = true;
|
||||
glhr::eyeshift = glhr::tmtogl(xpush(vid.ipd * ed/2));
|
||||
}
|
||||
}
|
||||
glhr::fog_max(1/sightranges[geometry], darkena(backcolor, 0, 0xFF));
|
||||
}
|
||||
@ -644,12 +681,20 @@ EX flagtype get_shader_flags() {
|
||||
}
|
||||
|
||||
EX void glapplymatrix(const transmatrix& V) {
|
||||
#if CAP_VR
|
||||
transmatrix V3;
|
||||
bool use_vr = vrhr::state;
|
||||
if(use_vr) V3 = vrhr::hmd_pre * V;
|
||||
const transmatrix& V2 = use_vr ? V3 : V;
|
||||
#else
|
||||
const transmatrix& V2 = V;
|
||||
#endif
|
||||
GLfloat mat[16];
|
||||
int id = 0;
|
||||
|
||||
if(MXDIM == 3) {
|
||||
for(int y=0; y<3; y++) {
|
||||
for(int x=0; x<3; x++) mat[id++] = V[x][y];
|
||||
for(int x=0; x<3; x++) mat[id++] = V2[x][y];
|
||||
mat[id++] = 0;
|
||||
}
|
||||
mat[12] = 0;
|
||||
@ -659,7 +704,7 @@ EX void glapplymatrix(const transmatrix& V) {
|
||||
}
|
||||
else {
|
||||
for(int y=0; y<4; y++)
|
||||
for(int x=0; x<4; x++) mat[id++] = V[x][y];
|
||||
for(int x=0; x<4; x++) mat[id++] = V2[x][y];
|
||||
}
|
||||
glhr::set_modelview(glhr::as_glmatrix(mat));
|
||||
}
|
||||
|
3
sky.cpp
3
sky.cpp
@ -374,6 +374,9 @@ EX struct renderbuffer *airbuf;
|
||||
|
||||
EX void make_air() {
|
||||
if(!sky) return;
|
||||
#if CAP_VR
|
||||
if(vrhr::state) return;
|
||||
#endif
|
||||
const int AIR_TEXTURE = 512;
|
||||
if(!airbuf) {
|
||||
airbuf = new renderbuffer(AIR_TEXTURE, AIR_TEXTURE, true);
|
||||
|
10
sysconfig.h
10
sysconfig.h
@ -224,6 +224,8 @@
|
||||
#define PSEUDOKEY_WHEELDOWN 2501
|
||||
#define PSEUDOKEY_WHEELUP 2502
|
||||
#define PSEUDOKEY_RELEASE 2503
|
||||
#define PSEUDOKEY_EXIT 2504
|
||||
#define PSEUDOKEY_MENU 2505
|
||||
|
||||
#ifndef CAP_PNG
|
||||
#define CAP_PNG (!ISMOBWEB)
|
||||
@ -312,6 +314,10 @@
|
||||
#define CAP_RACING (!ISMOBWEB && !ISMINI)
|
||||
#endif
|
||||
|
||||
#ifndef CAP_VR
|
||||
#define CAP_VR ISSTEAM
|
||||
#endif
|
||||
|
||||
#ifndef CAP_LEGACY
|
||||
#define CAP_LEGACY 0
|
||||
#endif
|
||||
@ -462,6 +468,10 @@ typedef unsigned GLuint;
|
||||
#include <new>
|
||||
#include <limits.h>
|
||||
|
||||
#if CAP_VR
|
||||
#include "openvr.h"
|
||||
#endif
|
||||
|
||||
#if CAP_VIDEO
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
997
vr.cpp
Normal file
997
vr.cpp
Normal file
@ -0,0 +1,997 @@
|
||||
// Hyperbolic Rogue -- VR support
|
||||
// Copyright (C) 2020-2020 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
/** \file vr.cpp
|
||||
* \brief VR support
|
||||
*/
|
||||
|
||||
#include "hyper.h"
|
||||
namespace hr {
|
||||
|
||||
EX namespace vrhr {
|
||||
|
||||
#if CAP_VR
|
||||
|
||||
#if HDR
|
||||
enum class eHeadset { none, rotation_only, reference, holonomy };
|
||||
enum class eEyes { none, equidistant, truesim };
|
||||
enum class eCompScreen { none, reference, single, eyes };
|
||||
#endif
|
||||
|
||||
EX eHeadset hsm = eHeadset::reference;
|
||||
EX eEyes eyes = eEyes::equidistant;
|
||||
EX eCompScreen cscr = eCompScreen::single;
|
||||
|
||||
EX cell *forward_cell;
|
||||
|
||||
EX ld vraim_x, vraim_y, vrgo_x, vrgo_y;
|
||||
|
||||
vector<pair<string, string> > headset_desc = {
|
||||
{"none", "Ignore the headset movement and rotation."},
|
||||
{"rotation only", "Ignore the headset movement but do not ignore its rotation."},
|
||||
{"reference", "The reference point in the real world corresponds to the reference point in VR. When you move your head in a loop, you return to where you started."},
|
||||
{"holonomy", "Headsets movements in the real world are translated to the same movements in VR. Since the geometry is different, when you move your head in a loop, you usually don't return "
|
||||
"to where you started."}
|
||||
};
|
||||
|
||||
vector<pair<string, string> > eyes_desc = {
|
||||
{"none", "Both eyes see the same image."},
|
||||
{"equidistant", "Render the image so that the perceived direction and distance is correct."},
|
||||
{"true vision", "Simulate the actual binocular vision in the non-Euclidean space. Hyperbolic spaces look smaller than they are (stretched Klein model), spherical spaces look weird, "
|
||||
"nonisotropic spaces are incomprehensible."}, /* not implemented */
|
||||
};
|
||||
|
||||
/* not implemented */
|
||||
vector<pair<string, string> > comp_desc = {
|
||||
{"none", "Do not display anything on the computer screen."},
|
||||
{"reference", "Display the view from the reference point."},
|
||||
{"single", "(not implemented)"}, // "Display a single monocular image."},
|
||||
{"eyes", "Display a copy of the VR display."},
|
||||
};
|
||||
|
||||
struct vr_rendermodel {
|
||||
string name;
|
||||
GLuint texture_id;
|
||||
vector<glhr::textured_vertex> vertices;
|
||||
};
|
||||
|
||||
struct vr_framebuffer {
|
||||
bool ok;
|
||||
GLuint m_nDepthBufferId;
|
||||
GLuint m_nRenderTextureId;
|
||||
GLuint m_nRenderFramebufferId;
|
||||
GLuint m_nResolveTextureId;
|
||||
GLuint m_nResolveFramebufferId;
|
||||
vr_framebuffer(int x, int y);
|
||||
~vr_framebuffer();
|
||||
};
|
||||
|
||||
vr_framebuffer::vr_framebuffer(int xsize, int ysize) {
|
||||
resetbuffer rb;
|
||||
glGenFramebuffers(1, &m_nRenderFramebufferId );
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_nRenderFramebufferId);
|
||||
|
||||
glGenRenderbuffers(1, &m_nDepthBufferId);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_nDepthBufferId);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, xsize, ysize );
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_nDepthBufferId );
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_nDepthBufferId );
|
||||
|
||||
glGenTextures(1, &m_nRenderTextureId );
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_nRenderTextureId );
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, xsize, ysize, true);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_nRenderTextureId, 0);
|
||||
|
||||
glGenFramebuffers(1, &m_nResolveFramebufferId );
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_nResolveFramebufferId);
|
||||
|
||||
glGenTextures(1, &m_nResolveTextureId );
|
||||
glBindTexture(GL_TEXTURE_2D, m_nResolveTextureId );
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, xsize, ysize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_nResolveTextureId, 0);
|
||||
|
||||
// check FBO status
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
||||
ok = status == GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
rb.reset();
|
||||
}
|
||||
|
||||
vr_framebuffer::~vr_framebuffer() {
|
||||
glDeleteRenderbuffers( 1, &m_nDepthBufferId );
|
||||
glDeleteTextures( 1, &m_nRenderTextureId );
|
||||
glDeleteFramebuffers( 1, &m_nRenderFramebufferId );
|
||||
glDeleteTextures( 1, &m_nResolveTextureId );
|
||||
glDeleteFramebuffers( 1, &m_nResolveFramebufferId );
|
||||
}
|
||||
|
||||
struct controller_data {
|
||||
int x, y, clicked;
|
||||
};
|
||||
|
||||
struct vrdata_t {
|
||||
vr::IVRSystem *vr;
|
||||
uint32_t xsize, ysize;
|
||||
vr_framebuffer *eyes[2];
|
||||
transmatrix proj[2];
|
||||
transmatrix eyepos[2];
|
||||
vr::TrackedDevicePose_t poses[ vr::k_unMaxTrackedDeviceCount ];
|
||||
transmatrix pose_matrix[vr::k_unMaxTrackedDeviceCount ];
|
||||
vector<vr_rendermodel*> models;
|
||||
vr_rendermodel* device_models[ vr::k_unMaxTrackedDeviceCount ];
|
||||
controller_data cdata [ vr::k_unMaxTrackedDeviceCount ];
|
||||
};
|
||||
|
||||
vrdata_t vrdata;
|
||||
|
||||
/** should we try to access VR */
|
||||
EX bool enabled = true;
|
||||
|
||||
/** we tried to access VR but failed */
|
||||
EX bool failed;
|
||||
|
||||
/** VR error message */
|
||||
EX string error_msg;
|
||||
|
||||
/** 0 = not loaded, 1 = loaded but not currently rendering, 2 = currently rendering the VR screen, 3 = currently rendering the computer screen */
|
||||
EX int state = 0;
|
||||
|
||||
// use E4 when working with real-world matrices to ensure that inverses, multiplications, etc. are computed correctly
|
||||
#define E4 dynamicval<eGeometry> g(geometry, gCubeTiling)
|
||||
|
||||
#define IN_E4(x) [&]{ E4; return x; }()
|
||||
|
||||
std::string GetTrackedDeviceString( vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL ) {
|
||||
uint32_t unRequiredBufferLen = vr::VRSystem()->GetStringTrackedDeviceProperty( unDevice, prop, NULL, 0, peError );
|
||||
if( unRequiredBufferLen == 0 ) return "";
|
||||
|
||||
char *pchBuffer = new char[ unRequiredBufferLen ];
|
||||
unRequiredBufferLen = vr::VRSystem()->GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
|
||||
std::string sResult = pchBuffer;
|
||||
delete [] pchBuffer;
|
||||
return sResult;
|
||||
}
|
||||
|
||||
transmatrix vr_to_hr(vr::HmdMatrix44_t mat) {
|
||||
transmatrix T;
|
||||
for(int i=0; i<4; i++)
|
||||
for(int j=0; j<4; j++)
|
||||
T[i][j] = mat.m[i][j];
|
||||
return T;
|
||||
}
|
||||
|
||||
transmatrix vr_to_hr(vr::HmdMatrix34_t mat) {
|
||||
transmatrix T;
|
||||
for(int i=0; i<3; i++)
|
||||
for(int j=0; j<4; j++)
|
||||
T[i][j] = mat.m[i][j];
|
||||
T[3][0] = 0;
|
||||
T[3][1] = 0;
|
||||
T[3][2] = 0;
|
||||
T[3][3] = 1;
|
||||
return T;
|
||||
}
|
||||
|
||||
string device_class_name(vr::ETrackedDeviceClass v) {
|
||||
if(v == vr::TrackedDeviceClass_Controller)
|
||||
return "controller";
|
||||
if(v == vr::TrackedDeviceClass_HMD)
|
||||
return "HMD";
|
||||
if(v == vr::TrackedDeviceClass_Invalid)
|
||||
return "invalid";
|
||||
if(v == vr::TrackedDeviceClass_GenericTracker)
|
||||
return "tracker";
|
||||
if(v == vr::TrackedDeviceClass_TrackingReference)
|
||||
return "reference";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
|
||||
EX transmatrix hmd_at = Id;
|
||||
EX transmatrix hmd_ref_at = Id;
|
||||
|
||||
EX transmatrix hmd_mvp, hmd_pre;
|
||||
|
||||
EX transmatrix sm;
|
||||
|
||||
vr_rendermodel *get_render_model(string name) {
|
||||
for(auto& m: vrdata.models)
|
||||
if(m->name == name)
|
||||
return m;
|
||||
|
||||
println(hlog, "trying to load model ", name);
|
||||
|
||||
vr::RenderModel_t *pModel;
|
||||
vr::EVRRenderModelError error;
|
||||
while(1) {
|
||||
error = vr::VRRenderModels()->LoadRenderModel_Async(name.c_str(), &pModel );
|
||||
if(error != vr::VRRenderModelError_Loading) break;
|
||||
usleep(1000);
|
||||
}
|
||||
if(error != vr::VRRenderModelError_None) {
|
||||
println(hlog, "Unable to load render model %s - %s\n", name, vr::VRRenderModels()->GetRenderModelErrorNameFromEnum( error ) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vr::RenderModel_TextureMap_t *pTexture;
|
||||
while (1) {
|
||||
error = vr::VRRenderModels()->LoadTexture_Async( pModel->diffuseTextureId, &pTexture );
|
||||
if(error != vr::VRRenderModelError_Loading) break;
|
||||
usleep(1000);
|
||||
}
|
||||
if(error != vr::VRRenderModelError_None) {
|
||||
println(hlog, "Unable to load render texture id:%d for render model %s\n", pModel->diffuseTextureId, name);
|
||||
vr::VRRenderModels()->FreeRenderModel( pModel );
|
||||
return NULL; // move on to the next tracked device
|
||||
}
|
||||
|
||||
auto md = new vr_rendermodel;
|
||||
vrdata.models.emplace_back(md);
|
||||
md->name = name;
|
||||
|
||||
int cnt = pModel->unTriangleCount * 3;
|
||||
for(int i=0; i<cnt; i++) {
|
||||
glhr::textured_vertex tv;
|
||||
int id = pModel->rIndexData[i];
|
||||
for(int j=0; j<3; j++)
|
||||
tv.coords[j] = pModel->rVertexData[id].vPosition.v[j];
|
||||
tv.coords[3] = 1;
|
||||
for(int j=0; j<2; j++)
|
||||
tv.texture[j] = pModel->rVertexData[id].rfTextureCoord[j];
|
||||
md->vertices.push_back(tv);
|
||||
}
|
||||
|
||||
glGenTextures(1, &md->texture_id);
|
||||
glBindTexture( GL_TEXTURE_2D, md->texture_id);
|
||||
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, pTexture->unWidth, pTexture->unHeight,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, pTexture->rubTextureMapData );
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||||
|
||||
GLfloat fLargest;
|
||||
glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest );
|
||||
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest );
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, 0 );
|
||||
|
||||
println(hlog, "model loaded successfully");
|
||||
return md;
|
||||
}
|
||||
|
||||
#if HDR
|
||||
struct click {
|
||||
int x, y, clicked;
|
||||
};
|
||||
#endif
|
||||
|
||||
EX vector<click> get_hits() {
|
||||
vector<click> res;
|
||||
for(auto h: vrhr::vrdata.cdata)
|
||||
if(h.x || h.y)
|
||||
res.emplace_back(click{h.x, h.y, h.clicked});
|
||||
return res;
|
||||
}
|
||||
|
||||
void track_all() {
|
||||
track_actions();
|
||||
|
||||
E4;
|
||||
sm = Id; sm[1][1] = sm[2][2] = -1;
|
||||
// println(hlog, "tracking");
|
||||
vr::VRCompositor()->WaitGetPoses(vrdata.poses, vr::k_unMaxTrackedDeviceCount, NULL, 0 );
|
||||
// println(hlog, "poses received");
|
||||
|
||||
for(int i=0; i<(int)vr::k_unMaxTrackedDeviceCount; i++) {
|
||||
auto& p = vrdata.poses[i];
|
||||
vrdata.device_models[i] = nullptr;
|
||||
if(!p.bPoseIsValid)
|
||||
continue;
|
||||
transmatrix T = vr_to_hr(p.mDeviceToAbsoluteTracking) * sm;
|
||||
|
||||
// println(hlog, "found ", device_class_name(vrdata.vr->GetTrackedDeviceClass(i)), " at ", T);
|
||||
|
||||
vrdata.pose_matrix[i] = T;
|
||||
|
||||
if(i == vr::k_unTrackedDeviceIndex_Hmd) {
|
||||
hmd_at = inverse(T);
|
||||
if(first) hmd_ref_at = hmd_at, first = false;
|
||||
}
|
||||
|
||||
auto& cd = vrdata.cdata[i];
|
||||
cd.x = cd.y = 0;
|
||||
|
||||
if(vrdata.vr->GetTrackedDeviceClass(i) == vr::TrackedDeviceClass_Controller) {
|
||||
string mname = GetTrackedDeviceString(i, vr::Prop_RenderModelName_String );
|
||||
vrdata.device_models[i] = get_render_model(mname);
|
||||
|
||||
/*
|
||||
cd.last = cd.cur;
|
||||
bool ok = vrdata.vr->GetControllerState(i, &cd.cur, sizeof(state));
|
||||
if(ok) {
|
||||
println(hlog, "pressed = ", color_t(cd.cur.ulButtonPressed), " touched = ", color_t(cd.cur.ulButtonTouched), " on ", i);
|
||||
for(int i=0; i<5; i++)
|
||||
if(cd.cur.rAxis[i].x || cd.cur.rAxis[i].y)
|
||||
println(hlog, "axis ", i, " = ", tie(cd.cur.rAxis[i].x, cd.cur.rAxis[i].y));
|
||||
}
|
||||
*/
|
||||
|
||||
hyperpoint h1 = sm * hmd_at * vrdata.pose_matrix[i] * sm * C0;
|
||||
hyperpoint h2 = sm * hmd_at * vrdata.pose_matrix[i] * sm * point31(0, 0, -0.01);
|
||||
ld p = ilerp(h1[2], h2[2], -ui_depth);
|
||||
hyperpoint px = lerp(h1, h2, p);
|
||||
px[0] /= ui_size;
|
||||
px[1] /= -ui_size;
|
||||
px[0] += current_display->xsize/2;
|
||||
px[1] += current_display->ysize/2;
|
||||
cd.x = px[0];
|
||||
cd.y = px[1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EX void vr_control() {
|
||||
if(!enabled || !vid.usingGL) {
|
||||
if(state) shutdown_vr();
|
||||
return;
|
||||
}
|
||||
if(enabled && vid.usingGL && !state && !failed) {
|
||||
start_vr();
|
||||
}
|
||||
if(state == 1) {
|
||||
track_all();
|
||||
}
|
||||
}
|
||||
|
||||
EX void be_33(transmatrix& T) {
|
||||
for(int i=0; i<3; i++) T[i][3] = T[3][i] = 0;
|
||||
T[3][3] = 1;
|
||||
}
|
||||
|
||||
EX void apply_movement(const transmatrix& rel) {
|
||||
hyperpoint h0 = IN_E4(inverse(rel) * C0);
|
||||
hyperpoint h = h0;
|
||||
for(int i=0; i<3; i++) h[i] /= -absolute_unit_in_meters;
|
||||
|
||||
shift_view(h);
|
||||
transmatrix Rot = rel;
|
||||
be_33(Rot);
|
||||
rotate_view(Rot);
|
||||
}
|
||||
|
||||
EX void vr_shift() {
|
||||
if(first) return;
|
||||
rug::using_rugview urv;
|
||||
if(GDIM == 2) return;
|
||||
|
||||
if(hsm == eHeadset::holonomy) {
|
||||
apply_movement(IN_E4(hmd_at * inverse(hmd_ref_at)));
|
||||
hmd_ref_at = hmd_at;
|
||||
playermoved = false;
|
||||
if(!rug::rugged) optimizeview();
|
||||
}
|
||||
}
|
||||
|
||||
EX ld absolute_unit_in_meters = 1;
|
||||
|
||||
void move_according_to(vr::ETrackedControllerRole role, bool last, bool cur) {
|
||||
if(!last && !cur) return;
|
||||
int id = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(role);
|
||||
if(id >= 0 && id < int(vr::k_unMaxTrackedDeviceCount)) {
|
||||
hyperpoint h;
|
||||
if(true) {
|
||||
E4;
|
||||
transmatrix T = (hsm == eHeadset::none ? hmd_at : hmd_ref_at) * vrdata.pose_matrix[id] * sm;
|
||||
vrhr::be_33(T);
|
||||
h = T * point31(0, 0, -0.01);
|
||||
}
|
||||
if(last && !cur)
|
||||
movevrdir(h);
|
||||
else {
|
||||
movedir md = vectodir(h);
|
||||
cellwalker xc = cwt + md.d + wstep;
|
||||
forward_cell = xc.at;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct digital_action_data {
|
||||
string action_name;
|
||||
vr::VRActionHandle_t handle;
|
||||
bool last, curr;
|
||||
function<void(bool, bool)> act;
|
||||
bool_reaction_t when;
|
||||
digital_action_data(string s, bool_reaction_t when, function<void(bool, bool)> f) : when(when) { action_name = s; act = f; handle = vr::k_ulInvalidActionHandle; }
|
||||
};
|
||||
|
||||
struct analog_action_data {
|
||||
string action_name;
|
||||
vr::VRActionHandle_t handle;
|
||||
ld x, y;
|
||||
function<void(ld, ld)> act;
|
||||
analog_action_data(string s, function<void(ld, ld)> f) { action_name = s; act = f; handle = vr::k_ulInvalidActionHandle; }
|
||||
};
|
||||
|
||||
struct set_data {
|
||||
string set_name;
|
||||
int prio;
|
||||
vr::VRActionHandle_t handle;
|
||||
bool_reaction_t when;
|
||||
set_data(string s, int p, bool_reaction_t w) { set_name = s; prio = p; when = w; handle = vr::k_ulInvalidActionHandle; }
|
||||
};
|
||||
|
||||
vector<digital_action_data> dads = {
|
||||
digital_action_data("/actions/menu/in/SelectLeft", [] { return !(cmode && sm::NORMAL); }, [] (bool last, bool curr) {
|
||||
if(curr && !last) {
|
||||
int id = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( vr::TrackedControllerRole_LeftHand);
|
||||
if(id >= 0 && id < int(vr::k_unMaxTrackedDeviceCount))
|
||||
vrdata.cdata[id].clicked = true;
|
||||
}
|
||||
}),
|
||||
digital_action_data("/actions/menu/in/SelectRight", [] { return !(cmode && sm::NORMAL); }, [] (bool last, bool curr) {
|
||||
if(curr && !last) {
|
||||
int id = vr::VRSystem()->GetTrackedDeviceIndexForControllerRole( vr::TrackedControllerRole_RightHand);
|
||||
if(id >= 0 && id < int(vr::k_unMaxTrackedDeviceCount))
|
||||
vrdata.cdata[id].clicked = true;
|
||||
}
|
||||
}),
|
||||
digital_action_data("/actions/menu/in/Exit", [] { return !(cmode && sm::NORMAL); }, [] (bool last, bool curr) {
|
||||
if(curr && !last) dialog::queue_key(PSEUDOKEY_EXIT);
|
||||
}),
|
||||
digital_action_data("/actions/game/in/MoveLeft", [] { return (cmode && sm::NORMAL); }, [] (bool last, bool curr) {
|
||||
move_according_to(vr::TrackedControllerRole_LeftHand, last, curr);
|
||||
}),
|
||||
digital_action_data("/actions/game/in/MoveRight", [] { return (cmode && sm::NORMAL); }, [] (bool last, bool curr) {
|
||||
move_according_to(vr::TrackedControllerRole_RightHand, last, curr);
|
||||
}),
|
||||
digital_action_data("/actions/game/in/EnterMenu", [] { return (cmode && sm::NORMAL); }, [] (bool last, bool curr) {
|
||||
if(curr && !last) dialog::queue_key(PSEUDOKEY_MENU);
|
||||
}),
|
||||
digital_action_data("/actions/general/in/SetReference", [] { return true; }, [] (bool last, bool curr) {
|
||||
if(curr && !last) hmd_ref_at = hmd_at;
|
||||
})
|
||||
};
|
||||
|
||||
vector<analog_action_data> aads = {
|
||||
analog_action_data("/actions/general/in/MoveCamera", [] (ld x, ld y) {
|
||||
vrgo_x = x;
|
||||
vrgo_y = y;
|
||||
}),
|
||||
analog_action_data("/actions/general/in/RotateCamera", [] (ld x, ld y) {
|
||||
vraim_x = x;
|
||||
vraim_y = y;
|
||||
}),
|
||||
};
|
||||
|
||||
vector<set_data> sads = {
|
||||
set_data("/actions/menu", 20, [] { return !(cmode & sm::NORMAL); }),
|
||||
set_data("/actions/game", 20, [] { return cmode & sm::NORMAL; }),
|
||||
set_data("/actions/general", 10, [] { return true; })
|
||||
};
|
||||
|
||||
void init_input() {
|
||||
const auto& vi = vr::VRInput();
|
||||
|
||||
string cwd;
|
||||
|
||||
char cwdbuf[PATH_MAX];
|
||||
if (getcwd(cwdbuf, sizeof(cwdbuf)) != NULL) {
|
||||
cwd = cwdbuf;
|
||||
println(hlog, "Found cwd: ", cwd);
|
||||
if(cwd.back() == '/' || cwd.back() == '\\') ;
|
||||
else cwd += (ISWINDOWS ? '\\' : '/');
|
||||
cwd += "hypervr_actions.json";
|
||||
}
|
||||
|
||||
vi->SetActionManifestPath(cwd.c_str());
|
||||
|
||||
for(auto& sad: sads)
|
||||
vi->GetActionSetHandle(sad.set_name.c_str(), &sad.handle);
|
||||
|
||||
for(auto& dad: dads)
|
||||
vi->GetActionHandle(dad.action_name.c_str(), &dad.handle);
|
||||
|
||||
for(auto& aad: aads)
|
||||
vi->GetActionHandle(aad.action_name.c_str(), &aad.handle);
|
||||
}
|
||||
|
||||
EX void track_actions() {
|
||||
|
||||
for(auto& cd: vrdata.cdata)
|
||||
cd.clicked = false;
|
||||
|
||||
forward_cell = nullptr;
|
||||
|
||||
vector<vr::VRActiveActionSet_t> sets;
|
||||
|
||||
for(auto& sad: sads) if(sad.when()) {
|
||||
sets.emplace_back();
|
||||
auto& s = sets.back();
|
||||
s.ulActionSet = sad.handle;
|
||||
s.ulRestrictedToDevice = vr::k_ulInvalidInputValueHandle;
|
||||
s.ulSecondaryActionSet = vr::k_ulInvalidInputValueHandle;
|
||||
s.nPriority = sad.prio;
|
||||
}
|
||||
|
||||
if(isize(sets))
|
||||
vr::VRInput()->UpdateActionState( &sets[0], sizeof(vr::VRActiveActionSet_t), isize(sets));
|
||||
|
||||
for(auto& dad: dads) {
|
||||
if(!dad.when()) continue;
|
||||
vr::InputDigitalActionData_t actionData;
|
||||
vr::VRInput()->GetDigitalActionData(dad.handle, &actionData, sizeof(actionData), vr::k_ulInvalidInputValueHandle );
|
||||
dad.last = dad.curr;
|
||||
dad.curr = actionData.bState;
|
||||
dad.act(dad.last, dad.curr);
|
||||
}
|
||||
|
||||
for(auto& aad: aads) {
|
||||
vr::InputAnalogActionData_t actionData;
|
||||
vr::VRInput()->GetAnalogActionData(aad.handle, &actionData, sizeof(actionData), vr::k_ulInvalidInputValueHandle );
|
||||
aad.x = actionData.x;
|
||||
aad.y = actionData.y;
|
||||
aad.act(aad.x, aad.y);
|
||||
}
|
||||
}
|
||||
|
||||
EX void start_vr() {
|
||||
|
||||
vr::EVRInitError eError = vr::VRInitError_None;
|
||||
vrdata.vr = vr::VR_Init( &eError, vr::VRApplication_Scene );
|
||||
|
||||
if(eError != vr::VRInitError_None) {
|
||||
error_msg = vr::VR_GetVRInitErrorAsEnglishDescription( eError );
|
||||
println(hlog, "Unable to init VR: ", error_msg);
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
else println(hlog, "VR initialized successfully");
|
||||
|
||||
string driver = GetTrackedDeviceString( vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String );
|
||||
string display = GetTrackedDeviceString( vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String );
|
||||
|
||||
println(hlog, "HyperRogue VR: driver=", driver, " display=", display);
|
||||
|
||||
if(!vr::VRCompositor()) {
|
||||
println(hlog, "Compositor initialization failed. See log file for details\n" );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
init_input();
|
||||
|
||||
vrdata.vr->GetRecommendedRenderTargetSize( &vrdata.xsize, &vrdata.ysize);
|
||||
|
||||
println(hlog, "recommended size: ", int(vrdata.xsize), " x ", int(vrdata.ysize));
|
||||
|
||||
for(int a=0; a<2; a++) {
|
||||
auto eye = vr::EVREye(a);
|
||||
vrdata.eyes[a] = new vr_framebuffer(vrdata.xsize, vrdata.ysize);
|
||||
println(hlog, "eye ", a, " : ", vrdata.eyes[a]->ok ? "OK" : "Error");
|
||||
|
||||
vrdata.proj[a] =
|
||||
vr_to_hr(vrdata.vr->GetProjectionMatrix(eye, 0.01, 300));
|
||||
|
||||
println(hlog, "projection = ", vrdata.proj[a]);
|
||||
|
||||
vrdata.eyepos[a] =
|
||||
vr_to_hr(vrdata.vr->GetEyeToHeadTransform(eye));
|
||||
|
||||
println(hlog, "eye-to-head = ", vrdata.eyepos[a]);
|
||||
}
|
||||
|
||||
//CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, leftEyeDesc );
|
||||
//CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, rightEyeDesc );
|
||||
|
||||
state = 1;
|
||||
}
|
||||
|
||||
EX void shutdown_vr() {
|
||||
vr::VR_Shutdown();
|
||||
vrdata.vr = nullptr;
|
||||
for(auto& e: vrdata.eyes) {
|
||||
delete e;
|
||||
e = nullptr;
|
||||
}
|
||||
state = 0;
|
||||
}
|
||||
|
||||
EX void clear() {
|
||||
if(!state) return;
|
||||
resetbuffer rb;
|
||||
for(int i=0; i<2; i++) {
|
||||
auto& ey = vrdata.eyes[i];
|
||||
glBindFramebuffer( GL_FRAMEBUFFER, ey->m_nRenderFramebufferId );
|
||||
glViewport(0, 0, vrdata.xsize, vrdata.ysize );
|
||||
glhr::set_depthtest(false);
|
||||
glhr::set_depthtest(true);
|
||||
glhr::set_depthwrite(false);
|
||||
glhr::set_depthwrite(true);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
rb.reset();
|
||||
current_display->set_viewport(0);
|
||||
}
|
||||
|
||||
EX ld ui_depth = 1.5;
|
||||
EX ld ui_size = 0.004;
|
||||
|
||||
EX void in_vr_ui(reaction_t what) {
|
||||
|
||||
resetbuffer rb;
|
||||
if(!state) return;
|
||||
|
||||
int xsi = current_display->xsize;
|
||||
int ysi = current_display->ysize;
|
||||
state = 2;
|
||||
|
||||
for(int i=0; i<2; i++) {
|
||||
dynamicval<int> vx(vid.xres, vrdata.xsize);
|
||||
dynamicval<int> vy(vid.yres, vrdata.ysize);
|
||||
E4;
|
||||
auto& ey = vrdata.eyes[i];
|
||||
glBindFramebuffer( GL_FRAMEBUFFER, ey->m_nRenderFramebufferId );
|
||||
glViewport(0, 0, vrdata.xsize, vrdata.ysize );
|
||||
calcparam();
|
||||
glhr::set_depthtest(false);
|
||||
hmd_mvp = Id;
|
||||
hmd_mvp = xpush(-xsi/2) * ypush(-ysi/2) * hmd_mvp;
|
||||
transmatrix Sca = Id;
|
||||
Sca[0][0] *= ui_size;
|
||||
Sca[1][1] *= -ui_size;
|
||||
Sca[2][2] *= 0;
|
||||
hmd_mvp = Sca * hmd_mvp;
|
||||
hmd_mvp = zpush(-ui_depth) * hmd_mvp;
|
||||
hmd_mvp = vrdata.proj[i] * inverse(vrdata.eyepos[i]) * hmd_mvp;
|
||||
reset_projection();
|
||||
current_display->set_all(0, 0);
|
||||
what();
|
||||
}
|
||||
state = 1;
|
||||
|
||||
rb.reset();
|
||||
calcparam();
|
||||
current_display->set_viewport(0);
|
||||
calcparam();
|
||||
reset_projection();
|
||||
current_display->set_all(0, 0);
|
||||
glhr::set_modelview(glhr::translate(-current_display->xcenter,-current_display->ycenter, 0));
|
||||
what();
|
||||
}
|
||||
|
||||
EX void draw_eyes() {
|
||||
state = 1;
|
||||
for(int i=0; i<2; i++) {
|
||||
resetbuffer rb;
|
||||
auto& ey = vrdata.eyes[i];
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, ey->m_nRenderFramebufferId);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ey->m_nResolveFramebufferId );
|
||||
glBlitFramebuffer( 0, 0, vrdata.xsize, vrdata.ysize, 0, 0, vrdata.xsize, vrdata.ysize, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
rb.reset();
|
||||
|
||||
current_display->next_shader_flags = GF_TEXTURE;
|
||||
dynamicval<eModel> m(pmodel, mdPixel);
|
||||
current_display->set_all(0, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, ey->m_nResolveTextureId );
|
||||
glhr::id_modelview();
|
||||
glhr::set_depthtest(false);
|
||||
glhr::color2(0xFFFFFFFF);
|
||||
vector<glhr::textured_vertex> tvx;
|
||||
for(int a=0; a<6; a++) {
|
||||
int dx[6] = {0, 1, 1, 0, 0, 1};
|
||||
int dy[6] = {0, 0, 1, 0, 1, 1};
|
||||
glhr::textured_vertex tx;
|
||||
tx.coords[2] = 0;
|
||||
tx.coords[3] = 1;
|
||||
tx.coords[0] = (dx[a]+i) * current_display->xsize / 2 - current_display->xcenter;
|
||||
tx.coords[1] = (1-dy[a]) * current_display->ysize - current_display->ycenter;
|
||||
tx.texture[0] = dx[a];
|
||||
tx.texture[1] = dy[a];
|
||||
tvx.push_back(tx);
|
||||
}
|
||||
glhr::prepare(tvx);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}
|
||||
}
|
||||
|
||||
EX void render() {
|
||||
|
||||
resetbuffer rb;
|
||||
state = 2;
|
||||
|
||||
if(GDIM == 2) {
|
||||
state = 3;
|
||||
drawqueue();
|
||||
return;
|
||||
}
|
||||
|
||||
// eyes = lshiftclick ? eEyes::truesim : eEyes::equidistant;
|
||||
|
||||
// cscr = lshiftclick ? eCompScreen::eyes : eCompScreen::single;
|
||||
|
||||
for(int i=0; i<2; i++) {
|
||||
|
||||
dynamicval<int> vx(vid.xres, vrdata.xsize);
|
||||
dynamicval<int> vy(vid.yres, vrdata.ysize);
|
||||
|
||||
auto& ey = vrdata.eyes[i];
|
||||
|
||||
glBindFramebuffer( GL_FRAMEBUFFER, ey->m_nRenderFramebufferId );
|
||||
glViewport(0, 0, vrdata.xsize, vrdata.ysize );
|
||||
glhr::set_depthtest(false);
|
||||
glhr::set_depthtest(true);
|
||||
glhr::set_depthwrite(false);
|
||||
glhr::set_depthwrite(true);
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
calcparam();
|
||||
|
||||
transmatrix mu;
|
||||
for(int i=0; i<4; i++)
|
||||
for(int j=0; j<4; j++)
|
||||
mu[i][j] = i!=j ? 0 : i==3 ? 1 : absolute_unit_in_meters;
|
||||
|
||||
if(1) {
|
||||
dynamicval<transmatrix> tN(NLP, NLP);
|
||||
dynamicval<transmatrix> tV(View, View);
|
||||
dynamicval<transmatrix> tC(current_display->which_copy, current_display->which_copy);
|
||||
shiftmatrix Tv = cview();
|
||||
|
||||
if(hsm == eHeadset::rotation_only) {
|
||||
transmatrix T = hmd_at;
|
||||
be_33(T);
|
||||
apply_movement(T);
|
||||
}
|
||||
|
||||
else if(hsm == eHeadset::reference) {
|
||||
apply_movement(IN_E4(hmd_at * inverse(hmd_ref_at)));
|
||||
}
|
||||
|
||||
if(eyes == eEyes::truesim) {
|
||||
apply_movement(IN_E4(inverse(vrdata.eyepos[i])));
|
||||
}
|
||||
|
||||
make_actual_view();
|
||||
hmd_pre = cview().T * inverse(Tv.T);
|
||||
// inverse_shift(Tv, cview());
|
||||
// View * inverse(Tv.T);
|
||||
// inverse(inverse_shift(cview(), Tv));
|
||||
|
||||
hmd_mvp = Id;
|
||||
bool nlpu = nisot::local_perspective_used();
|
||||
if(1) {
|
||||
E4;
|
||||
if(nlpu) {
|
||||
be_33(NLP);
|
||||
hmd_mvp = NLP * hmd_mvp;
|
||||
}
|
||||
hmd_mvp = mu * sm * hmd_mvp;
|
||||
if(eyes == eEyes::equidistant) {
|
||||
hmd_mvp = inverse(vrdata.eyepos[i]) * hmd_mvp;
|
||||
}
|
||||
hmd_mvp = vrdata.proj[i] * hmd_mvp;
|
||||
}
|
||||
}
|
||||
|
||||
drawqueue();
|
||||
}
|
||||
|
||||
rb.reset();
|
||||
|
||||
calcparam();
|
||||
current_display->set_viewport(0);
|
||||
calcparam();
|
||||
current_display->next_shader_flags = 0;
|
||||
current_display->set_all(0, 0);
|
||||
|
||||
if(cscr == eCompScreen::eyes) draw_eyes();
|
||||
|
||||
if(cscr == eCompScreen::single) {
|
||||
/* todo */
|
||||
state = 3;
|
||||
drawqueue();
|
||||
}
|
||||
|
||||
if(cscr == eCompScreen::reference) {
|
||||
state = 3;
|
||||
drawqueue();
|
||||
}
|
||||
|
||||
state = 1;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void show_choice(string name, T& value, char key, vector<pair<string, string>> options) {
|
||||
dialog::addSelItem(XLAT(name), XLAT(options[int(value)].first), key);
|
||||
dialog::add_action_push([&value, name, options] {
|
||||
dialog::init(XLAT(name));
|
||||
dialog::addBreak(100);
|
||||
int q = isize(options);
|
||||
for(int i=0; i<q; i++) {
|
||||
dialog::addBoolItem(XLAT(options[i].first), int(value) == i, 'a'+i);
|
||||
dialog::add_action([&value, i] { value = T(i); popScreen(); });
|
||||
dialog::addBreak(100);
|
||||
dialog::addHelp(XLAT(options[i].second));
|
||||
dialog::addBreak(100);
|
||||
}
|
||||
dialog::addBreak(100);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
});
|
||||
}
|
||||
|
||||
EX void show_vr_settings() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("VR settings"));
|
||||
|
||||
dialog::addBoolItem_action(XLAT("VR enabled"), enabled, 'o');
|
||||
if(!enabled)
|
||||
dialog::addBreak(100);
|
||||
else if(failed)
|
||||
dialog::addInfo(XLAT("error: ") + error_msg, 0xC00000);
|
||||
else
|
||||
dialog::addInfo(XLAT("VR initialized correctly"), 0x00C000);
|
||||
|
||||
dialog::addBreak(100);
|
||||
|
||||
show_choice("headset movement", hsm, 'h', headset_desc);
|
||||
show_choice("binocular vision", eyes, 'b', eyes_desc);
|
||||
show_choice("computer screen", cscr, 'c', comp_desc);
|
||||
|
||||
dialog::addSelItem(XLAT("absolute unit in meters"), fts(absolute_unit_in_meters), 'a');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(absolute_unit_in_meters, .01, 100, 0.1, 1, XLAT("absolute unit in meters"),
|
||||
XLAT(
|
||||
"The size of the absolute unit of the non-Euclidean geometry correspond in meters. "
|
||||
"This affects the headset movement and binocular vision.\n\n"
|
||||
"In spherical geometry, the absolute unit is the radius of the sphere. "
|
||||
"The smaller the absolute unit, the stronger the non-Euclidean effects.\n\n"
|
||||
"Elements of the HyperRogue world have fixed size in terms of absolute units, "
|
||||
"so reducing the absolute unit makes them smaller. "
|
||||
"If you are playing in the Euclidean mode, this feature just scales everything "
|
||||
"(e.g., in the cube tiling, the 'absolute unit' is just the edge of the cube)."
|
||||
));
|
||||
dialog::scaleLog();
|
||||
});
|
||||
|
||||
if(hsm == eHeadset::reference) {
|
||||
hyperpoint h = hmd_at * inverse(hmd_ref_at) * C0;
|
||||
|
||||
dialog::addSelItem(XLAT("reset the reference point"), state ? fts(hypot_d(3, h)) + "m" : "", 'r');
|
||||
dialog::add_action([] { hmd_ref_at = hmd_at; });
|
||||
}
|
||||
else dialog::addBreak(100);
|
||||
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
||||
if(0) ;
|
||||
else if(argis("-vr-enabled")) {
|
||||
PHASEFROM(2);
|
||||
shift(); enabled = argi();
|
||||
}
|
||||
else if(argis("-vr-absunit")) {
|
||||
PHASEFROM(2);
|
||||
shift_arg_formula(absolute_unit_in_meters);
|
||||
}
|
||||
else if(argis("-d:vr")) {
|
||||
PHASEFROM(2); launch_dialog(show_vr_settings);
|
||||
}
|
||||
else if(argis("-vr-mode")) {
|
||||
PHASEFROM(2);
|
||||
shift(); hsm = (eHeadset) argi();
|
||||
shift(); eyes = (eEyes) argi();
|
||||
shift(); cscr = (eCompScreen) argi();
|
||||
}
|
||||
else return 1;
|
||||
return 0;
|
||||
}
|
||||
auto hooka = addHook(hooks_args, 100, readArgs);
|
||||
#endif
|
||||
|
||||
#if CAP_CONFIG
|
||||
void addconfig() {
|
||||
addsaver(enabled, "vr-enabled");
|
||||
addparam(absolute_unit_in_meters, "vr-abs-unit");
|
||||
}
|
||||
auto hookc = addHook(hooks_configfile, 100, addconfig);
|
||||
#endif
|
||||
|
||||
EX void submit() {
|
||||
|
||||
if(!state) return;
|
||||
for(int i=0; i<(int)vr::k_unMaxTrackedDeviceCount; i++)
|
||||
if(vrdata.device_models[i]) {
|
||||
resetbuffer rb;
|
||||
if(!state) return;
|
||||
|
||||
state = 2;
|
||||
dynamicval<eModel> m(pmodel, mdPerspective);
|
||||
dynamicval<ld> ms(sightranges[geometry], 100);
|
||||
|
||||
for(int e=0; e<2; e++) {
|
||||
dynamicval<int> vx(vid.xres, vrdata.xsize);
|
||||
dynamicval<int> vy(vid.yres, vrdata.ysize);
|
||||
E4;
|
||||
auto& ey = vrdata.eyes[e];
|
||||
glBindFramebuffer( GL_FRAMEBUFFER, ey->m_nRenderFramebufferId );
|
||||
glViewport(0, 0, vrdata.xsize, vrdata.ysize );
|
||||
calcparam();
|
||||
|
||||
hmd_mvp = vrdata.proj[e] * inverse(vrdata.eyepos[e]) * sm * hmd_at * vrdata.pose_matrix[i] * sm * Id;
|
||||
hmd_pre = Id;
|
||||
|
||||
reset_projection();
|
||||
current_display->next_shader_flags = GF_TEXTURE;
|
||||
current_display->set_all(0, 0);
|
||||
glhr::set_depthtest(false);
|
||||
glhr::set_depthtest(true);
|
||||
glhr::set_depthwrite(false);
|
||||
glhr::set_depthwrite(true);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
glhr::id_modelview();
|
||||
glhr::color2(0xFFFFFFFF);
|
||||
prepare(vrdata.device_models[i]->vertices);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, vrdata.device_models[i]->texture_id);
|
||||
glDrawArrays(GL_TRIANGLES, 0, isize(vrdata.device_models[i]->vertices));
|
||||
|
||||
if(1) {
|
||||
current_display->next_shader_flags = 0;
|
||||
current_display->set_all(0, 0);
|
||||
vector<glvertex> vex;
|
||||
vex.push_back(glhr::makevertex(0.01, 0, 0));
|
||||
vex.push_back(glhr::makevertex(-0.01, 0, 0));
|
||||
vex.push_back(glhr::makevertex(0, 0, -10));
|
||||
glhr::current_vertices = nullptr;
|
||||
glhr::vertices(vex);
|
||||
glhr::color2(0xC0FFC0C0);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state = 1;
|
||||
|
||||
rb.reset();
|
||||
calcparam();
|
||||
current_display->set_viewport(0);
|
||||
calcparam();
|
||||
reset_projection();
|
||||
current_display->set_all(0, 0);
|
||||
}
|
||||
|
||||
for(int i=0; i<2; i++) {
|
||||
auto eye = vr::EVREye(i);
|
||||
auto& ey = vrdata.eyes[i];
|
||||
|
||||
resetbuffer rb;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, ey->m_nRenderFramebufferId);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ey->m_nResolveFramebufferId );
|
||||
glBlitFramebuffer( 0, 0, vrdata.xsize, vrdata.ysize, 0, 0, vrdata.xsize, vrdata.ysize, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
rb.reset();
|
||||
|
||||
vr::Texture_t texture = {(void*)(uintptr_t)ey->m_nResolveTextureId, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
|
||||
vr::VRCompositor()->Submit(eye, &texture );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EX }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user