ODS in hyperbolic

This commit is contained in:
Zeno Rogue 2019-10-21 22:42:27 +02:00
parent 30eda241a8
commit c527d4e613
4 changed files with 148 additions and 49 deletions

View File

@ -1390,6 +1390,11 @@ EX void add_edit_fov(char key IS('f')) {
});
}
bool supported_ods() {
if(!CAP_ODS) return false;
return rug::rugged || (hyperbolic && GDIM == 3);
}
EX void showStereo() {
cmode = sm::SIDE | sm::MAYDARK;
gamescreen(0);
@ -1437,8 +1442,10 @@ EX void showStereo() {
"Currently, red-cyan anaglyph glasses and mobile VR googles are supported."
) + "\n\n";
if(uni == 'm')
{ vid.stereo_mode = eStereo((1 + vid.stereo_mode) % (CAP_ODS ? 4 : 3)); return; }
if(uni == 'm') {
vid.stereo_mode = eStereo((1 + vid.stereo_mode) % 4);
if(vid.stereo_mode == sODS && !supported_ods()) vid.stereo_mode = sOFF;
}
else if(uni == 'e')
dialog::editNumber(vid.ipd, -10, 10, 0.01, 0, XLAT("pupillary distance"),

View File

@ -1176,8 +1176,144 @@ void draw_s2xe0(dqi_poly *p) {
}
EX }
EX namespace ods {
#if CAP_ODS
EX bool project(hyperpoint h, hyperpoint& h1, hyperpoint& h2, bool eye) {
ld tanalpha = tan_auto(vid.ipd/2);
if(eye) tanalpha = -tanalpha;
if(!sphere) tanalpha = -tanalpha;
ld& x = h[0];
ld z = -h[1];
ld y = -h[2];
ld& t = h[3];
ld y02 = (x*x + y*y - tanalpha*tanalpha*t*t);
if(y02 < 0) return false;
ld y0 = sqrt(y02);
ld theta = atan(z / y0);
for(int i=0; i<2; i++) {
hyperpoint& h = (i ? h1 : h2);
if(i == 1) theta = -theta, y0 = -y0;
ld x0 = t * tanalpha;
ld phi = atan2(y, x) - atan2(y0, x0) + M_PI;
// ld delta = euclid ? hypot(y0,z) : atan2_auto(z / sin(theta), t / cos_auto(vid.ipd/2));
ld p = z / sin(theta) / t * cos_auto(vid.ipd / 2);
ld delta = (p > 1) ? 13 : (p < -1) ? -13 : atanh(p);
if(euclid || hyperbolic) phi -= M_PI;
if(hyperbolic) delta = -delta;
h[0] = phi;
h[1] = theta;
h[2] = delta;
if(euclid || hyperbolic) h[1] = -theta;
}
return true;
}
void draw_ods(dqi_poly *p) {
auto& stinf = s2xe::stinf;
if(!p->cnt) return;
if(!(p->flags & POLY_TRIANGLES)) return;
dqi_poly npoly = *p;
npoly.offset = 0;
npoly.tab = &glcoords;
npoly.V = Id;
npoly.tinf = p->tinf ? &stinf : NULL;
if(npoly.tinf) {
npoly.offset_texture = 0;
stinf.texture_id = p->tinf->texture_id;
stinf.tvertices.clear();
}
npoly.V = Id;
glcoords.clear();
array<hyperpoint, 6> h;
if(0) for(int i=0; i<p->cnt; i+=3) {
for(int j=0; j<3; j++)
h[j] = p->V * glhr::gltopoint((*p->tab)[p->offset+i+j]);
for(int j=0; j<3; j++) {
glcoords.push_back(glhr::makevertex(h[j][0], h[j][1], h[j][2]));
if(npoly.tinf) stinf.tvertices.push_back(p->tinf->tvertices[i+j]);
}
}
if(1) for(int i=0; i<p->cnt; i+=3) {
for(int j=0; j<3; j++) {
hyperpoint o = p->V * glhr::gltopoint((*p->tab)[p->offset+i+j]);
if(!project(o, h[j], h[j+3], global_projection == -1))
goto next_i;
}
for(int j=0; j<6; j++) {
// let Delta be from 0 to 2PI
if(h[j][2]<0) h[j][2] += 2 * M_PI;
// Theta is from -PI/2 to PI/2. Let it be from 0 to PI
h[j][1] += global_projection * M_PI/2;
h[j][3] = 1;
}
/* natsph here */
if(h[0][2] < 0) swap(h[0], h[3]);
if(h[1][2] < 0) swap(h[1], h[4]);
if(h[2][2] < 0) swap(h[2], h[5]);
cyclefix(h[0][0], 0);
cyclefix(h[1][0], h[0][0]);
cyclefix(h[2][0], h[0][0]);
cyclefix(h[3][0], 0);
cyclefix(h[4][0], h[3][0]);
cyclefix(h[5][0], h[3][0]);
if(abs(h[1][1] - h[0][1]) > M_PI/2) goto next_i;
if(abs(h[2][1] - h[0][1]) > M_PI/2) goto next_i;
if(h[0][0] < -M_PI || h[0][0] > M_PI) println(hlog, h[0][0]);
if(1) {
int fst = 0, lst = 0;
if(h[1][0] < -M_PI || h[2][0] < -M_PI) lst++;
if(h[1][0] > +M_PI || h[2][0] > +M_PI) fst--;
for(int x=fst; x<=lst; x++) for(int j=0; j<3; j++) {
glcoords.push_back(glhr::makevertex(h[j][0] + 2 * M_PI * x, h[j][1], h[j][2]));
if(npoly.tinf) stinf.tvertices.push_back(p->tinf->tvertices[p->offset_texture+i+j]);
}
}
/* natsph here */
next_i: ;
}
npoly.cnt = isize(glcoords);
// npoly.color = 0xFFFFFFFF;
npoly.gldraw();
}
#endif
EX }
void dqi_poly::draw() {
if(flags & POLY_DEBUG) debug_this();
#if CAP_ODS
if(vid.stereo_mode == sODS) {
ods::draw_ods(this);
return;
}
#endif
if(in_s2xe() && vid.usingGL && pmodel == mdPerspective && (current_display->set_all(global_projection), (get_shader_flags() & SF_DIRECT))) {
s2xe::draw_s2xe(this);

View File

@ -4568,7 +4568,7 @@ EX int noclipped;
void make_clipping_planes() {
#if MAXMDIM >= 4
clipping_planes.clear();
if(PIU(sphere) || experimental) return;
if(PIU(sphere) || experimental || vid.stereo_mode == sODS) return;
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);

48
rug.cpp
View File

@ -1168,61 +1168,17 @@ extern int besti;
#if CAP_ODS
/* these functions are for the ODS projection, used in VR videos */
void cyclefix(ld& a, ld b) {
if(a > b + M_PI) a -= 2 * M_PI;
if(a < b - M_PI) a += 2 * M_PI;
}
ld raddif(ld a, ld b) {
ld d = a-b;
if(d < 0) d = -d;
if(d > 2*M_PI) d -= 2*M_PI;
if(d > M_PI) d = 2 * M_PI-d;
return d;
}
bool project_ods(hyperpoint azeq, hyperpoint& h1, hyperpoint& h2, bool eye) {
USING_NATIVE_GEOMETRY;
ld tanalpha = tan_auto(vid.ipd/2);
if(eye) tanalpha = -tanalpha;
if(!sphere) tanalpha = -tanalpha;
ld d = hypot_d(3, azeq);
ld sindbd = sin_auto(d)/d, cosd = cos_auto(d);
ld x = azeq[0] * sindbd;
ld y = azeq[2] * sindbd;
ld z = azeq[1] * sindbd;
ld t = cosd;
return ods::project(hyperpoint(azeq[0] * sindbd, azeq[1] * sindbd, azeq[2] * sindbd, cosd), h1, h2, eye);
// printf("%10.5lf %10.5lf %10.5lf ", azeq[0], azeq[1], azeq[2]);
// printf(" => %10.5lf %10.5lf %10.5lf %10.5lf", x, y, z, t);
ld y02 = (x*x + y*y - tanalpha*tanalpha*t*t);
if(y02 < 0) return false;
ld y0 = sqrt(y02);
ld theta = atan(z / y0);
for(int i=0; i<2; i++) {
hyperpoint& h = (i ? h1 : h2);
if(i == 1) theta = -theta, y0 = -y0;
ld x0 = t * tanalpha;
ld phi = atan2(y, x) - atan2(y0, x0) + M_PI;
ld delta = euclid ? hypot(y0,z) : atan2_auto(z / sin(theta), t / cos_auto(vid.ipd/2));
if(euclid || hyperbolic) phi -= M_PI;
if(hyperbolic) delta = -delta;
h[0] = phi;
h[1] = theta;
h[2] = delta;
if(euclid || hyperbolic) h[1] = -theta;
// printf(" => %10.5lf %10.5lf %10.5lf", phi, theta, delta);
}
// printf("\n");
return true;
@ -1242,7 +1198,7 @@ void drawTriangle(triangle& t) {
dt++;
#if CAP_ODS
if(vid.stereo_mode == current_display->sODS) {
if(vid.stereo_mode == sODS) {
hyperpoint pts[3];
// not implemented