From b3f047ea6aaecf9e924692eed408910bb5e520f5 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Sat, 3 Feb 2018 13:41:49 +0100 Subject: [PATCH] reworked 3D vision --- basegraph.cpp | 122 +++++++++++++++++++++++++++++++++---------- commandline.cpp | 7 +++ config.cpp | 80 ++++++++++++++++++++++++---- conformal.cpp | 2 +- control.cpp | 3 ++ graph.cpp | 38 +++++++------- hud.cpp | 131 +++++++++++++++++++++++----------------------- hyper.h | 31 ++++++++--- hypgraph.cpp | 54 +++++++++++-------- polygons.cpp | 119 +++++++++++++++++++++++------------------- rug.cpp | 136 ++++++++++++++++++++++-------------------------- shmup.cpp | 2 +- textures.cpp | 2 +- 13 files changed, 451 insertions(+), 276 deletions(-) diff --git a/basegraph.cpp b/basegraph.cpp index 019ab1fe..74a3501c 100644 --- a/basegraph.cpp +++ b/basegraph.cpp @@ -10,6 +10,29 @@ int utfsize(char c) { return 4; } +namespace stereo { + eStereo mode; + ld ipd; + ld lr_eyewidth, anaglyph_eyewidth; + ld fov, tanfov; + + GLfloat scrdist, scrdist_text; + } + +bool stereo::in_anaglyph() { return stereo::mode == stereo::sAnaglyph; } +bool stereo::active() { return stereo::mode != sOFF; } + +ld stereo::eyewidth() { + switch(stereo::mode) { + case stereo::sAnaglyph: + return stereo::anaglyph_eyewidth; + case stereo::sLR: + return stereo::lr_eyewidth; + default: + return 0; + } + } + bool eqs(const char* x, const char* y) { return *y? *x==*y?eqs(x+1,y+1):false:true; } @@ -152,36 +175,70 @@ void setcameraangle(bool b) { } } -void selectEyeGL(int ed) { - DEBB(DF_GRAPH, (debugfile,"selectEyeGL\n")); - +void start_projection(int ed) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glTranslatef((vid.xcenter*2.)/vid.xres - 1, 1 - (vid.ycenter*2.)/vid.yres, 0); - if(pmodel) { - vid.scrdist = 4 * vid.radius; + if(ed) { + if(stereo::mode == stereo::sLR) { + glTranslatef(ed * (stereo::eyewidth() - .5) * 4, 0, 0); + glScalef(2, 1, 1); + } + else { + glTranslatef(-ed * stereo::eyewidth(), 0, 0); + } + } + } + +void stereo::set_projection(int ed) { + DEBB(DF_GRAPH, (debugfile,"stereo::set_projection\n")); + + start_projection(ed); + + if(pmodel && !stereo::active()) { // simulate glOrtho GLfloat ortho[16] = { GLfloat(2. / vid.xres), 0, 0, 0, 0, GLfloat(-2. / vid.yres), 0, 0, - 0, 0, GLfloat(.4 / vid.scrdist), 0, + 0, 0, GLfloat(.4 / stereo::scrdist), 0, 0, 0, 0, 1}; - vid.scrdist = -vid.scrdist; glMultMatrixf(ortho); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } - else { - float ve = ed*vid.eye; - ve *= 2; // vid.xres; ve /= vid.radius; - if(ve) - glTranslatef(-(ve * vid.radius) * (vid.alpha - (vid.radius*1./vid.xres) * vid.eye) / vid.xres, 0, 0); + else if(pmodel) { + float lowdepth = .1, hidepth = 1e9; + + ld right = vid.xres/2 * lowdepth / stereo::scrdist; + ld left = -right; + ld top = -vid.yres/2 * lowdepth / stereo::scrdist; + ld bottom = -top; + + GLfloat frustum[16] = { + GLfloat(2 * lowdepth / (right-left)), 0, 0, 0, + 0, GLfloat(2 * lowdepth / (top-bottom)), 0, 0, + 0, 0, -(hidepth+lowdepth)/(hidepth-lowdepth), -1, + 0, 0, -2*lowdepth*hidepth/(hidepth-lowdepth), 0}; + + glMultMatrixf(frustum); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if(ed) glTranslatef(stereo::ipd * vid.radius * ed/2, 0, 0); + + glScalef(1, 1, -1); + glTranslatef(0, 0, stereo::scrdist); + + stereo::scrdist_text = 0; + } + else { float lowdepth = .1; float hidepth = 1e9; @@ -196,20 +253,22 @@ void selectEyeGL(int ed) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - + GLfloat sc = vid.radius / (vid.yres/2.); GLfloat mat[16] = {sc,0,0,0, 0,-sc,0,0, 0,0,-1,0, 0,0, 0,1}; + glMultMatrixf(mat); - if(ve) glTranslatef(ve, 0, vid.eye); - vid.scrdist = vid.yres * sc / 2; + if(ed) glTranslatef(stereo::ipd*ed/2, 0, 0); + + stereo::scrdist_text = vid.yres * sc / 2; } cameraangle_on = false; } -void selectEyeMask(int ed) { - if(ed == 0) { +void stereo::set_mask(int ed) { + if(ed == 0 || stereo::mode != stereo::sAnaglyph) { glColorMask( GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE ); } else if(ed == 1) { @@ -220,6 +279,15 @@ void selectEyeMask(int ed) { } } +void stereo::set_viewport(int ed) { + if(ed == 0 || stereo::mode != stereo::sLR) + glViewport(0, 0, vid.xres, vid.yres); + else if(ed == 1) + glViewport(0, 0, vid.xres/2, vid.yres); + else if(ed == -1) + glViewport(vid.xres/2, 0, vid.xres/2, vid.yres); + } + void setGLProjection(int col) { DEBB(DF_GRAPH, (debugfile,"setGLProjection\n")); @@ -261,7 +329,7 @@ void setGLProjection(int col) { else glDisable(GL_DEPTH_TEST); - selectEyeGL(0); + stereo::set_projection(0); } #if CAP_GLFONT @@ -475,7 +543,7 @@ bool gl_print(int x, int y, int shift, int size, const char *s, int color, int a displaystr(x+w, y+h, 1, 10, "X", 0xFFFFFF, 8); markcorner = true; } */ - + for(int i=0; s[i];) { // glListBase(f.list_base); @@ -488,11 +556,11 @@ bool gl_print(int x, int y, int shift, int size, const char *s, int color, int a int hi = f.heights[tabid] * size/gsiz; GLERR("pre-print"); - - for(int ed = (vid.goteyes && shift)?-1:0; ed<2; ed+=2) { + + for(int ed = (stereo::active() && shift)?-1:0; ed<2; ed+=2) { glPushMatrix(); - glTranslatef(x-ed*shift-vid.xcenter,y-vid.ycenter, vid.scrdist); - selectEyeMask(ed); + glTranslatef(x-ed*shift-vid.xcenter,y-vid.ycenter, stereo::scrdist_text); + stereo::set_mask(ed); glBindTexture(GL_TEXTURE_2D, f.textures[tabid]); #if 1 @@ -516,7 +584,7 @@ bool gl_print(int x, int y, int shift, int size, const char *s, int color, int a glPopMatrix(); } - if(vid.goteyes) selectEyeMask(0); + if(stereo::active() && shift) stereo::set_mask(0); GLERR("print"); @@ -782,7 +850,7 @@ ld realradius() { ld vradius = vid.radius; if(sphere) { if(sphereflipped()) - vradius /= sqrt(vid.alphax*vid.alphax - 1); + vradius /= sqrt(vid.alpha*vid.alpha - 1); else vradius = 1e12; // use the following } @@ -885,7 +953,7 @@ void drawCircle(int x, int y, int size, int color) { float rr = (M_PI * 2 * r) / pts; glcoords[r][0] = x + size * sin(rr); glcoords[r][1] = y + size * cos(rr); - glcoords[r][2] = vid.scrdist; + glcoords[r][2] = stereo::scrdist; } qglcoords = pts; @@ -940,7 +1008,7 @@ void displayColorButton(int x, int y, const string& name, int key, int align, in } ld textscale() { - return vid.fsize / (vid.radius * crossf) * (1+vid.alphax) * 2; + return vid.fsize / (vid.radius * crossf) * (1+vid.alpha) * 2; } // bool notgl = false; diff --git a/commandline.cpp b/commandline.cpp index e30488eb..2c24502b 100644 --- a/commandline.cpp +++ b/commandline.cpp @@ -102,6 +102,9 @@ int arg::readCommon() { else if(argis("-nofps")) { nofps = true; } + else if(argis("-nohud")) { + nohud = true; + } else if(argis("-back")) { shift(); backcolor = strtol(args(), NULL, 16); } @@ -132,6 +135,10 @@ int arg::readCommon() { shift(); int q = argi(); placeItems(q, i); } + else if(argis("-SM")) { + PHASE(2); + shift(); stereo::mode = stereo::eStereo(argi()); + } else if(argis("-IU")) { PHASE(3) cheater++; timerghost = false; shift(); eItem i = readItem(args()); diff --git a/config.cpp b/config.cpp index 9be99ae0..b3fa2560 100644 --- a/config.cpp +++ b/config.cpp @@ -248,7 +248,6 @@ void initConfig() { // special graphics - addsaver(vid.eye, "eye distance", 0); addsaver(vid.ballangle, "ball angle", 20); addsaver(vid.yshift, "Y shift", 0); addsaver(vid.camera_angle, "camera angle", 0); @@ -332,6 +331,12 @@ void initConfig() { addsaver(viewdists, "expansion mode"); addsaver(backbrightness, "brightness behind sphere"); + + addsaver(stereo::ipd, "interpupilar-distance", 0.05); + addsaver(stereo::lr_eyewidth, "eyewidth-lr", 0.5); + addsaver(stereo::anaglyph_eyewidth, "eyewidth-anaglyph", 0.1); + addsaver(stereo::fov, "field-of-vision", 90); + addsaverenum(stereo::mode, "stereo-mode"); #if CAP_SHMUP shmup::initConfig(); @@ -437,7 +442,7 @@ void loadOldConfig(FILE *f) { float a, b, c, d; err=fscanf(f, "%f%f%f%f\n", &a, &b, &c, &d); if(err == 4) { - vid.scale = a; vid.eye = b; vid.alpha = c; vid.sspeed = d; + vid.scale = a; vid.alpha = c; vid.sspeed = d; } err=fscanf(f, "%d%d%d%d%d%d%d", &vid.wallmode, &vid.monmode, &vid.axes, &musicvolume, &vid.framelimit, &gl, &vid.antialias); vid.usingGL = gl; @@ -1047,6 +1052,66 @@ string explain3D(ld *param) { return ""; } +void showStereo() { + cmode = sm::SIDE | sm::A3 | sm::MAYDARK; + gamescreen(0); + using namespace geom3; + dialog::init(XLAT("stereo vision config")); + + string modenames[4] = { "OFF", "anaglyph", "stereo", "ODS" }; + + dialog::addSelItem(XLAT("stereo mode"), XLAT(modenames[stereo::mode]), 'm'); + dialog::addSelItem(XLAT("interpupilar distance"), fts3(stereo::ipd), 'e'); + + switch(stereo::mode) { + case stereo::sAnaglyph: + dialog::addSelItem(XLAT("distance between images"), fts(stereo::anaglyph_eyewidth), 'd'); + break; + case stereo::sLR: + dialog::addSelItem(XLAT("distance between images"), fts(stereo::lr_eyewidth), 'd'); + break; + default: + dialog::addBreak(100); + break; + } + + dialog::addSelItem(XLAT("field of view"), fts(stereo::fov) + "°", 'f'); + + dialog::addItem(XLAT("exit stereo configuration"), 'v'); + dialog::display(); + + keyhandler = [] (int sym, int uni) { + using namespace geom3; + dialog::handleNavigation(sym, uni); + + if(uni == 'm') + { stereo::mode = stereo::eStereo((1 + stereo::mode) % 3); return; } + + else if(uni == 'e') + dialog::editNumber(stereo::ipd, -10, 10, 0.01, 0, XLAT("interpupilar distance"), + XLAT("Watch the Minkowski hyperboloid or the hypersian rug mode with the " + "red/cyan 3D glasses.")); + + else if(uni == 'd' && stereo::mode == stereo::sAnaglyph) + dialog::editNumber(stereo::anaglyph_eyewidth, -1, 1, 0.01, 0, XLAT("distance between images"), + XLAT("Watch the Minkowski hyperboloid or the hypersian rug mode with the " + "red/cyan 3D glasses.")); + + else if(uni == 'd' && stereo::mode == stereo::sLR) + dialog::editNumber(stereo::lr_eyewidth, -1, 1, 0.01, 0, XLAT("distance between images"), + XLAT("Watch the Minkowski hyperboloid or the hypersian rug mode with the " + "red/cyan 3D glasses.")); + + else if(uni == 'f') + dialog::editNumber(stereo::fov, 1, 170, 1, 45, "field of view", + "Horizontal field of view, in the perspective projection. " + "In the orthogonal projection this just controls the scale." + ); + + else if(doexiton(sym, uni)) popScreen(); + }; + } + void show3D() { cmode = sm::SIDE | sm::A3 | sm::MAYDARK; gamescreen(0); @@ -1072,7 +1137,6 @@ void show3D() { dialog::addBreak(50); dialog::addSelItem(XLAT("Y shift"), fts3(vid.yshift), 'y'); dialog::addSelItem(XLAT("camera rotation"), fts3(vid.camera_angle), 's'); - dialog::addSelItem(XLAT("distance between eyes"), fts3(vid.eye), 'e'); dialog::addBreak(50); dialog::addBoolItem(XLAT("ball model"), pmodel == mdBall, 'B'); dialog::addBoolItem(XLAT("hyperboloid model"), pmodel == mdHyperboloid, 'M'); @@ -1090,6 +1154,7 @@ void show3D() { else dialog::addInfo(XLAT("parameters set correctly")); dialog::addBreak(50); + dialog::addItem(XLAT("stereo vision config"), 'e'); dialog::addItem(XLAT("exit 3D configuration"), 'v'); dialog::display(); @@ -1121,13 +1186,10 @@ void show3D() { dialog::editNumber(geom3::rock_wall_ratio, 0, 1, .1, .9, XLAT("Rock-III to wall ratio"), ""); else if(uni == 'h') dialog::editNumber(geom3::human_wall_ratio, 0, 1, .1, .7, XLAT("Human to wall ratio"), ""); - + else if(uni == 'e') - cmode &= sm::A3, - dialog::editNumber(vid.eye, -10, 10, 0.01, 0, XLAT("distance between eyes"), - XLAT("Watch the Minkowski hyperboloid or the hypersian rug mode with the " - "red/cyan 3D glasses.")); - + pushScreen(showStereo); + else if(uni == 'y') cmode &= sm::A3, dialog::editNumber(vid.yshift, 0, 1, .1, 0, XLAT("Y shift"), diff --git a/conformal.cpp b/conformal.cpp index 6ec59811..6e46492f 100644 --- a/conformal.cpp +++ b/conformal.cpp @@ -96,7 +96,7 @@ namespace polygonal { hyperpoint h; h[0] = z2.first * vid.radius; h[1] = z2.second * vid.radius; - h[2] = vid.scrdist; + h[2] = stereo::scrdist; curvepoint(h); } diff --git a/control.cpp b/control.cpp index 944104af..e5422884 100644 --- a/control.cpp +++ b/control.cpp @@ -430,6 +430,9 @@ void fix_mouseh() { void handlekey(int sym, int uni) { + if(uni == '=') { stereo::mode = stereo::eStereo((1 + stereo::mode) % 3); return; } + if(uni == '+') switchGL(); + if(callhandlers(false, hooks_handleKey, sym, uni)) return; keyhandler(sym, uni); diff --git a/graph.cpp b/graph.cpp index b7cf8d99..3932206a 100644 --- a/graph.cpp +++ b/graph.cpp @@ -2209,8 +2209,9 @@ void sumaura(int v) { void drawaura() { if(!haveaura()) return; + if(stereo::mode) return; double rad = vid.radius; - if(sphere && !mdEqui()) rad /= sqrt(vid.alphax*vid.alphax - 1); + if(sphere && !mdEqui()) rad /= sqrt(vid.alpha*vid.alpha - 1); for(int v=0; v<4; v++) sumaura(v); for(auto& p: auraspecials) { @@ -2297,7 +2298,7 @@ void drawaura() { cx[r][z][u+2] = bak[u] + (aurac[rm][u] / (aurac[rm][3]+.1) - bak[u]) * cmul[z]; } - for(int u=0; u<4; u++) glcoords[u][2] = vid.scrdist; + for(int u=0; u<4; u++) glcoords[u][2] = stereo::scrdist; for(int u=0; u<4; u++) coltab[u][3] = 1; for(int r=0; rwall == waPlatform) wcol = 0xF0F0A0; break; case laRlyeh: - fcol = (vid.goteyes2 ? 0x4080C0 : 0x004080); + fcol = (stereo::in_anaglyph() ? 0x4080C0 : 0x004080); break; case laHell: - fcol = (vid.goteyes2 ? 0xC03030 : 0xC00000); + fcol = (stereo::in_anaglyph() ? 0xC03030 : 0xC00000); break; case laCanvas: fcol = c->landparam; @@ -3166,7 +3167,7 @@ void placeSidewall(cell *c, int i, int sidepar, const transmatrix& V, bool warp, transmatrix V2 = V * ddspin(c, i); - // if(sphere && vid.alphax <= 1 && tC0(V2 * xpush(cellgfxdist(c, i)/2))[2] < -.5) return; + // if(sphere && vid.alpha <= 1 && tC0(V2 * xpush(cellgfxdist(c, i)/2))[2] < -.5) return; /* int aw = away(V2); prio += aw; if(!detaillevel && aw < 0) return; @@ -5342,12 +5343,13 @@ void calcparam() { vid.xcenter += vid.scrsize * vid.xposition; vid.ycenter += vid.scrsize * vid.yposition; - ld eye = vid.eye; if(pmodel || rug::rugged) eye = 0; - vid.beta = 1 + vid.alpha + eye; - vid.alphax = vid.alpha + eye; - vid.goteyes = vid.eye > 0.001 || vid.eye < -0.001; - vid.goteyes2 = vid.goteyes; - vid.scrdist = vid.radius; + stereo::tanfov = tan(stereo::fov * M_PI / 360); + + if(pmodel) + stereo::scrdist = vid.xres / 2 / stereo::tanfov; + else + stereo::scrdist = vid.radius; + stereo::scrdist_text = stereo::scrdist; } int ringcolor = darkena(0xFF, 0, 0xFF); @@ -5360,19 +5362,19 @@ void drawfullmap() { ptds.clear(); - if(!vid.goteyes && !euclid && (pmodel == mdDisk || pmodel == mdBall || (sphere && mdEqui()))) { + if(!stereo::active() && !euclid && (pmodel == mdDisk || pmodel == mdBall || (sphere && mdEqui()))) { double rad = vid.radius; if(sphere) { if(mdEqui()) ; else if(!vid.grid && !elliptic) rad = 0; - else if(vid.alphax <= 0) + else if(vid.alpha <= 0) ; - else if(vid.alphax <= 1 && (vid.grid || elliptic)) // mark the equator - rad = rad * 1 / vid.alphax; + else if(vid.alpha <= 1 && (vid.grid || elliptic)) // mark the equator + rad = rad * 1 / vid.alpha; else if(vid.grid) // mark the edge - rad /= sqrt(vid.alphax*vid.alphax - 1); + rad /= sqrt(vid.alpha*vid.alpha - 1); } if(!haveaura()) queuecircle(vid.xcenter, vid.ycenter, rad, ringcolor, vid.usingGL ? PPR_CIRCLE : PPR_OUTCIRCLE); diff --git a/hud.cpp b/hud.cpp index 383aaa05..7766c650 100644 --- a/hud.cpp +++ b/hud.cpp @@ -332,8 +332,9 @@ bool nofps = false; void drawStats() { callhandlers(false, hooks_prestats); #if CAP_ROGUEVIZ - if(rogueviz::on || nohud) return; + if(rogueviz::on) return; #endif + if(nohud || stereo::mode == stereo::sLR) return; if(viewdists && sidescreen) { distcolors[0] = forecolor; dialog::init(""); @@ -375,11 +376,11 @@ void drawStats() { { dynamicval pm(pmodel, mdDisk); dynamicval va(vid.alpha, 1); - dynamicval vax(vid.alphax, 1); + dynamicval vax(vid.alpha, 1); dynamicval v(vid, vid); calcparam(); #if CAP_GL - selectEyeGL(0); + stereo::set_projection(0); #endif if(haveMobileCompass()) { @@ -436,69 +437,77 @@ void drawStats() { } } } - return; } - instat = false; - bool portrait = vid.xres < vid.yres; - int colspace = portrait ? (vid.yres - vid.xres - vid.fsize*3) : (vid.xres - vid.yres - 16) / 2; - int rowspace = portrait ? vid.xres - 16 : vid.yres - vid.fsize * (vid.msgleft ? 9 : 4); - int colid[4], rowid[4]; - int maxbyclass[4]; - for(int z=0; z<4; z++) maxbyclass[z] = 0; - for(int i=0; i columns) { vid.killreduction++; continue; } - coltaken = 0; + else { + + instat = false; + bool portrait = vid.xres < vid.yres; + int colspace = portrait ? (vid.yres - vid.xres - vid.fsize*3) : (vid.xres - vid.yres - 16) / 2; + int rowspace = portrait ? vid.xres - 16 : vid.yres - vid.fsize * (vid.msgleft ? 9 : 4); + int colid[4], rowid[4]; + int maxbyclass[4]; + for(int z=0; z<4; z++) maxbyclass[z] = 0; + for(int i=0; i columns) { vid.killreduction++; continue; } + coltaken = 0; + } + colid[z] = coltaken, rowid[z] = 0, + coltaken += (maxbyclass[z] + rows-1) / rows; } - colid[z] = coltaken, rowid[z] = 0, - coltaken += (maxbyclass[z] + rows-1) / rows; + if(coltaken > columns) { vid.killreduction++; continue; } + break; } - if(coltaken > columns) { vid.killreduction++; continue; } - break; - } - - if(buttonsize <= vid.fsize*3/4) { - imponly = true; buttonsize = minsize; - rows = rowspace / buttonsize; if(!rows) return; - colid[0] = 0; colid[2] = portrait ? 1 : 0; - } - updatesort(); - stable_sort(glyphorder, glyphorder+glyphs, glyphsort); + if(buttonsize <= vid.fsize*3/4) { + imponly = true; buttonsize = minsize; + rows = rowspace / buttonsize; if(!rows) return; + colid[0] = 0; colid[2] = portrait ? 1 : 0; + } + + updatesort(); + stable_sort(glyphorder, glyphorder+glyphs, glyphsort); + + for(int i0=0; i0= rows) rowid[z] = 0, colid[z]++; - - displayglyph2(cx, cy, buttonsize, i); + int cx, cy; + if(portrait) + cx = 8 + buttonsize * rowid[z], cy = vid.fsize*2 + buttonsize * (colid[z]) + buttonsize/2; + else + cx = 8 + buttonsize * (colid[z]), cy = vid.fsize * 3 + buttonsize * rowid[z]; + + if(!portrait && z < 2) cx = vid.xres - cx - buttonsize; + + rowid[z]++; if(rowid[z] >= rows) rowid[z] = 0, colid[z]++; + + displayglyph2(cx, cy, buttonsize, i); + } } + } + calcparam(); +#if CAP_GL + stereo::set_projection(0); +#endif + string s0; if(!peace::on) { if(displayButtonS(vid.xres - 8, vid.fsize, XLAT("score: %1", its(gold())), forecolor, 16, vid.fsize)) { @@ -554,10 +563,4 @@ XLAT( callhooks(hooks_stats); } - - calcparam(); -#if CAP_GL - selectEyeGL(0); -#endif - } diff --git a/hyper.h b/hyper.h index f7c2303c..0edf0f1d 100644 --- a/hyper.h +++ b/hyper.h @@ -587,14 +587,13 @@ extern reaction_t help_delegate; #define HELPFUN(x) (help_delegate = x, "HELPFUN") struct videopar { - ld scale, eye, alpha, sspeed, mspeed, yshift, camera_angle; + ld scale, alpha, sspeed, mspeed, yshift, camera_angle; ld ballangle, ballproj; int mobilecompasssize; int aurastr, aurasmoothen; bool full; - bool goteyes; // for rendering - bool goteyes2; // for choosing colors + int graphglyph; // graphical glyphs bool darkhepta; int shifttarget; @@ -609,7 +608,6 @@ struct videopar { int xcenter, ycenter; int radius; int scrsize; - ld alphax, beta; bool grid; int particles; @@ -622,9 +620,6 @@ struct videopar { int msgleft, msglimit; - // for OpenGL - float scrdist; - bool usingGL; int antialias; #define AA_NOGL 1 @@ -2536,3 +2531,25 @@ struct renderbuffer { void use_as_texture(); void clear(int col); }; + +namespace stereo { + enum eStereo { sOFF, sAnaglyph, sLR, sODS }; + + extern eStereo mode; + extern ld ipd; + extern ld lr_eyewidth, anaglyph_eyewidth; + extern ld fov, tanfov; + + extern GLfloat scrdist, scrdist_text; + + ld eyewidth(); + bool active(); + bool in_anaglyph(); + + void set_viewport(int ed); + void set_projection(int ed); + void set_mask(int ed); + } + +double randd(); + diff --git a/hypgraph.cpp b/hypgraph.cpp index 7dabcd23..ccaf5fe5 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -26,7 +26,7 @@ hyperpoint gethyper(ld x, ld y) { } if(euclid) - return hpxy(hx * (EUCSCALE + vid.alphax), hy * (EUCSCALE + vid.alphax)); + return hpxy(hx * (EUCSCALE + vid.alpha), hy * (EUCSCALE + vid.alpha)); if(vid.camera_angle) camrotate(hx, hy); @@ -45,8 +45,8 @@ hyperpoint gethyper(ld x, ld y) { ld curv = sphere ? 1 : -1; A = 1+curv*hr; - B = 2*hr*vid.alphax*-curv; - C = 1 - curv*hr*vid.alphax*vid.alphax; + B = 2*hr*vid.alpha*-curv; + C = 1 - curv*hr*vid.alpha*vid.alpha; // Az^2 - Bz = C B /= A; C /= A; @@ -56,13 +56,13 @@ hyperpoint gethyper(ld x, ld y) { // z = (B/2) + sqrt(C + B^2/4) ld rootsign = 1; - if(sphere && vid.alphax > 1) rootsign = -1; + if(sphere && vid.alpha > 1) rootsign = -1; ld hz = B / 2 + rootsign * sqrt(C + B*B/4); hyperpoint H; - H[0] = hx * (hz+vid.alphax); - H[1] = hy * (hz+vid.alphax); + H[0] = hx * (hz+vid.alpha); + H[1] = hy * (hz+vid.alpha); H[2] = hz; return H; @@ -83,9 +83,21 @@ void ballmodel(hyperpoint& ret, double alpha, double d, double zl) { ret[2] = - ax * sa * cb - ay * sb; } +void apply_depth(hyperpoint &f, ld z) { + if(vid.usingGL) + f[2] = z; + else { + z = z * vid.radius; + ld mul = stereo::scrdist / (stereo::scrdist + z); + f[0] = f[0] * mul; + f[1] = f[1] * mul; + f[2] = vid.xres * stereo::eyewidth() / 2 / vid.radius + stereo::ipd * mul / 2; + } + } + void applymodel(hyperpoint H, hyperpoint& ret) { - ld tz = euclid ? (EUCSCALE+vid.alphax) : vid.alphax+H[2]; + ld tz = euclid ? (EUCSCALE+vid.alpha) : vid.alpha+H[2]; if(tz < BEHIND_LIMIT && tz > -BEHIND_LIMIT) tz = BEHIND_LIMIT; if(pmodel == mdUnchanged) { @@ -124,9 +136,9 @@ void applymodel(hyperpoint H, hyperpoint& ret) { if(pmodel == mdDisk) { if(!vid.camera_angle) { - ret[0] = H[0] / tz; + ret[0] = H[0] / tz; ret[1] = H[1] / tz; - ret[2] = (1 - vid.beta / tz); + ret[2] = vid.xres / vid.radius * stereo::eyewidth() / 2 - stereo::ipd / tz / 2; } else { ld tx = H[0]; @@ -137,7 +149,7 @@ void applymodel(hyperpoint H, hyperpoint& ret) { ld ux = tx, uy = ty * cc - ss * tz, uz = tz * cc + ss * ty; ret[0] = ux / uz; ret[1] = uy / uz; - ret[2] = 1 - vid.beta / uz; + ret[2] = vid.xres / vid.radius * stereo::eyewidth() / 2 - stereo::ipd / uz / 2; } return; } @@ -164,14 +176,14 @@ void applymodel(hyperpoint H, hyperpoint& ret) { ret[0] = d * H[0] / rad / M_PI; ret[1] = d * H[1] / rad / M_PI; ret[2] = 0; - if(zlev != 1 && vid.goteyes) - ret[2] = geom3::factor_to_lev(zlev); + if(zlev != 1 && stereo::active()) + apply_depth(ret, -geom3::factor_to_lev(zlev)); ghcheck(ret,H); return; } - tz = H[2]+vid.alphax; + tz = H[2]+vid.alpha; if(pmodel == mdPolygonal || pmodel == mdPolynomial) { pair p = polygonal::compute(H[0]/tz, H[1]/tz); @@ -198,8 +210,8 @@ void applymodel(hyperpoint H, hyperpoint& ret) { if(wmspatial || mmspatial) y0 *= zlev; ret[1] = 1 - y0; ret[2] = 0; - if(zlev != 1 && vid.goteyes) - ret[2] = y0 * geom3::factor_to_lev(zlev); + if(zlev != 1 && stereo::active()) + apply_depth(ret, -y0 * geom3::factor_to_lev(zlev)); ghcheck(ret,H); return; } @@ -229,8 +241,8 @@ void applymodel(hyperpoint H, hyperpoint& ret) { ret[1] = -y0/M_PI*2; ret[2] = 0; - if(zlev != 1 && vid.goteyes) - ret[2] = geom3::factor_to_lev(zlev) / (1 + yv * yv); + if(zlev != 1 && stereo::active()) + apply_depth(ret, -geom3::factor_to_lev(zlev) / (1 + yv * yv)); ghcheck(ret,H); } @@ -442,7 +454,7 @@ void drawEuclidean() { transmatrix View0 = View; - ld cellrad = vid.radius / (EUCSCALE + vid.alphax); + ld cellrad = vid.radius / (EUCSCALE + vid.alpha); ld centerd = matrixnorm(View0); @@ -613,8 +625,8 @@ void fullcenter() { transmatrix screenpos(ld x, ld y) { transmatrix V = Id; - V[0][2] += (x - vid.xcenter) / vid.radius * (1+vid.alphax); - V[1][2] += (y - vid.ycenter) / vid.radius * (1+vid.alphax); + V[0][2] += (x - vid.xcenter) / vid.radius * (1+vid.alpha); + V[1][2] += (y - vid.ycenter) / vid.radius * (1+vid.alpha); return V; } @@ -625,7 +637,7 @@ transmatrix atscreenpos(ld x, ld y, ld size) { V[1][2] += (y - vid.ycenter); V[0][0] = size * 2 * hcrossf / crossf; V[1][1] = size * 2 * hcrossf / crossf; - V[2][2] = vid.scrdist; + V[2][2] = stereo::scrdist; if(euclid) V[2][2] /= EUCSCALE; return V; diff --git a/polygons.cpp b/polygons.cpp index cffc6d29..e0b83aeb 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -184,13 +184,13 @@ void addpoint(const hyperpoint& H) { if(qglcoords >= POLYMAX) return; if(true) { - hyperpoint Hscr; + hyperpoint Hscr; applymodel(H, Hscr); - if(vid.alphax + H[2] <= BEHIND_LIMIT && pmodel == mdDisk) poly_flags |= POLY_BEHIND; + if(vid.alpha + H[2] <= BEHIND_LIMIT && pmodel == mdDisk) poly_flags |= POLY_BEHIND; if(spherespecial) { double curnorm = H[0]*H[0]+H[1]*H[1]+H[2]*H[2]; - double horizon = curnorm / vid.alphax; + double horizon = curnorm / vid.alpha; if((spherespecial>0) ^ (H[2] <= -horizon)) poly_flags |= POLY_INFRONT; else { @@ -198,7 +198,7 @@ void addpoint(const hyperpoint& H) { (sqrt(curnorm - horizon*horizon) / (vid.alpha - horizon)) / (sqrt(curnorm - H[2]*H[2]) / (vid.alpha+H[2])); -// double coef = (vid.alphax + horizon) / (vid.alphax + H[2]); -< that one has a funny effect, seriously +// double coef = (vid.alpha + horizon) / (vid.alpha + H[2]); -< that one has a funny effect, seriously Hscr[0] *= coef; Hscr[1] *= coef; } @@ -218,13 +218,11 @@ void addpoint(const hyperpoint& H) { void coords_to_poly() { polyi = qglcoords; for(int i=0; itexture_id); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(3, GL_FLOAT, 0, &tinf->tvertices[tinfshift]); - } - - for(int ed = vid.goteyes ? -1 : 0; ed<2; ed+=2) { - if(ed) selectEyeGL(ed); + if(tinf) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tinf->texture_id); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(3, GL_FLOAT, 0, &tinf->tvertices[tinfshift]); + } + + for(int ed = stereo::active() ? -1 : 0; ed<2; ed+=2) { + if(ed) stereo::set_projection(ed), stereo::set_viewport(ed); bool draw = col; again: @@ -338,7 +336,8 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline glPushMatrix(); glapplymatrix(V); } - + +/* if(useV == 2) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -348,7 +347,7 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline 0, 0, 1, 0, 0, 0, 0, 1 }; - mat[8] += ed * vid.eye; + // EYETODO mat[8] += ed * vid.eye; glMultMatrixf(mat); } @@ -359,11 +358,11 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, vid.scrdist, 1 + 0, 0, stereo::scrdist, 1 }; - mat[8] += ed * vid.eye; + // EYETODO mat[8] += ed * vid.eye; glMultMatrixf(mat); - } + } */ if(draw) { glEnable(GL_STENCIL_TEST); @@ -375,15 +374,15 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); if(flags & POLY_INVERSE) { - selectEyeMask(ed); + stereo::set_mask(ed); glcolor2(col); glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO); glStencilFunc( GL_NOTEQUAL, 1, 1); GLfloat xx = vid.xres; GLfloat yy = vid.yres; GLfloat scr[12] = { - -xx, -yy, vid.scrdist, +xx, -yy, vid.scrdist, - +xx, +yy, vid.scrdist, -xx, +yy, vid.scrdist + -xx, -yy, stereo::scrdist, +xx, -yy, stereo::scrdist, + +xx, +yy, stereo::scrdist, -xx, +yy, stereo::scrdist }; GLfloat *cur = currentvertices; activateVertexArray(scr, 4); @@ -393,7 +392,7 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline draw = false; goto again; } else { - selectEyeMask(ed); + stereo::set_mask(ed); glcolor2(col); glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO); glStencilFunc( GL_EQUAL, 1, 1); @@ -410,6 +409,8 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline if(useV) glPopMatrix(); } + + if(stereo::active()) stereo::set_projection(0), stereo::set_viewport(0), stereo::set_mask(0); if(tinf) { glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -422,7 +423,7 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline double linewidthat(const hyperpoint& h, double minwidth) { if(vid.antialias & AA_LINEWIDTH) { double dz = h[2]; - if(dz < 1 || abs(dz-vid.scrdist) < 1e-6) return vid.linewidth; + if(dz < 1 || abs(dz-stereo::scrdist) < 1e-6) return vid.linewidth; else { double dx = sqrt(dz * dz - 1); double dfc = dx/(dz+1); @@ -576,7 +577,7 @@ void drawpolyline(polytodraw& p) { /* pp.outline = 0x80808080; p.col = 0; */ - + addpoly(pp.V, pp.tab, pp.cnt); mercator_loop_min = mercator_loop_max = 0; @@ -587,7 +588,7 @@ void drawpolyline(polytodraw& p) { if(poly_flags & POLY_BEHIND) return; - for(int i=0; i poly_limit || abs(glcoords[i][1]) > poly_limit) return; // too large! } @@ -604,7 +605,7 @@ void drawpolyline(polytodraw& p) { poly_flags ^= POLY_INVERSE; if(poly_flags & POLY_INVERSE) { - if(curradius < vid.alphax - 1e-6) return; + if(curradius < vid.alpha - 1e-6) return; } } else poly_flags &=~ POLY_INVERSE; @@ -629,7 +630,7 @@ void drawpolyline(polytodraw& p) { ld a = i * M_PI / 180 + h; glcoords[qglcoords][0] = vid.radius * sin(a); glcoords[qglcoords][1] = vid.radius * cos(a); - glcoords[qglcoords][2] = vid.scrdist; + glcoords[qglcoords][2] = stereo::scrdist; qglcoords++; } poly_flags ^= POLY_INVERSE; @@ -637,7 +638,7 @@ void drawpolyline(polytodraw& p) { #if CAP_GL if(vid.usingGL) { - // if(pmodel == 0) for(int i=0; i= 2000 || fatborder) { int xmi = 3000, xma = -3000; @@ -808,20 +809,6 @@ void drawqueueitem(polytodraw& ptd) { #endif drawCircle(ptd.u.cir.x, ptd.u.cir.y, ptd.u.cir.size, ptd.col); } - -#if CAP_SDL - if(vid.goteyes && !vid.usingGL) { - int qty = s->w * s->h; - int *a = (int*) s->pixels; - int *b = (int*) aux->pixels; - SDL_LockSurface(aux); - while(qty) { - *a = ((*a) & 0xFF0000) | ((*b) & 0x00FFFF); - a++; b++; qty--; - } - SDL_UnlockSurface(aux); - } -#endif } void initquickqueue() { @@ -905,7 +892,7 @@ void drawqueue() { profile_stop(3); #if CAP_SDL - if(vid.goteyes && !vid.usingGL) { + if(stereo::active() && !vid.usingGL) { if(aux && (aux->w != s->w || aux->h != s->h)) SDL_FreeSurface(aux); @@ -965,7 +952,30 @@ void drawqueue() { } #if CAP_GL - if(vid.goteyes && vid.usingGL) selectEyeGL(0), selectEyeMask(0); + if(vid.usingGL) + stereo::set_projection(0), stereo::set_mask(0), stereo::set_viewport(0); +#endif + +#if CAP_SDL + if(stereo::mode == stereo::sAnaglyph && !vid.usingGL) { + int qty = s->w * s->h; + int *a = (int*) s->pixels; + int *b = (int*) aux->pixels; + SDL_LockSurface(aux); + while(qty) { + *a = ((*a) & 0xFF0000) | ((*b) & 0x00FFFF); + a++; b++; qty--; + } + SDL_UnlockSurface(aux); + } + + if(stereo::mode == stereo::sLR && !vid.usingGL) { + SDL_LockSurface(aux); + for(int y=0; y gw(geometry, gwhere == gElliptic ? gSphere : gwhere) @@ -55,6 +53,7 @@ struct rugpoint { double dist; hyperpoint h; // point in the represented space hyperpoint flat; // point in the native space, in azeq + hyperpoint precompute; vector edges; // Find-Union algorithm rugpoint *glue; @@ -202,7 +201,7 @@ rugpoint *addRugpoint(hyperpoint h, double dist) { m->h = h; /* - ld tz = vid.alphax+h[2]; + ld tz = vid.alpha+h[2]; m->x1 = (1 + h[0] / tz) / 2; m->y1 = (1 + h[1] / tz) / 2; */ @@ -345,7 +344,7 @@ void setVidParam() { vid.xres = vid.yres = TEXTURESIZE; vid.scrsize = HTEXTURESIZE; vid.radius = vid.scrsize * vid.scale; vid.xcenter = HTEXTURESIZE; vid.ycenter = HTEXTURESIZE; - vid.beta = 2; vid.alphax = 1; vid.eye = 0; vid.goteyes = false; + vid.alpha = 1; } void buildTorusRug() { @@ -899,11 +898,11 @@ void physics() { // drawing the Rug //----------------- -int eyemod; +bool use_precompute; void getco(rugpoint *m, hyperpoint& h, int &spherepoints) { using namespace hyperpoint_vec; - h = m->getglue()->flat; + h = use_precompute ? m->getglue()->precompute : m->getglue()->flat; if(rug_perspective && gwhere >= gSphere) { if(h[2] > 0) { ld rad = hypot3(h); @@ -916,7 +915,6 @@ void getco(rugpoint *m, hyperpoint& h, int &spherepoints) { spherepoints++; } } - if(eyemod) h[0] += eyemod * h[2] * vid.eye; } extern int besti; @@ -938,7 +936,6 @@ ld raddif(ld a, ld b) { } bool ods = false; -ld ipd = 0.05; bool project_ods(hyperpoint azeq, hyperpoint& h1, hyperpoint& h2, bool eye) { ld tanalpha = tan(ipd/2); @@ -1067,6 +1064,7 @@ void prepareTexture() { videopar svid = vid; setVidParam(); + dynamicval d(stereo::mode, stereo::sOFF); glbuf->enable(); @@ -1113,12 +1111,6 @@ void drawRugScene() { glbuf->use_as_texture(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if(backcolor == 0) glClearColor(0.05,0.05,0.05,1); else @@ -1131,60 +1123,59 @@ void drawRugScene() { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); - ld tanfov = tan(fov * M_PI / 360); + for(int ed=stereo::active() && stereo::mode != stereo::sODS ? -1 : 0; ed < 2; ed += 2) { + use_precompute = false; + stereo::set_mask(ed), stereo::set_viewport(ed); + if(ed == 1 && stereo::mode == stereo::sAnaglyph) + glClear(GL_DEPTH_BUFFER_BIT); + + start_projection(ed); + if(stereo::mode == stereo::sODS) + glOrtho(-M_PI, M_PI, -M_PI, M_PI, 0, -M_PI * 2); + else if(rug_perspective || stereo::active()) { + + ld vnear = .001; + ld vfar = 1000; + ld sca = vnear * stereo::tanfov / vid.xres; + xview = stereo::tanfov; + yview = stereo::tanfov * vid.yres / vid.xres; + glFrustum(-sca * vid.xres, sca * vid.xres, -sca * vid.yres, sca * vid.yres, vnear, vfar); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if(!rug_perspective) glTranslatef(0, 0, -model_distance); + if(ed) { + if(gwhere == gEuclid) + glTranslatef(stereo::ipd*ed/2, 0, 0); + else { + use_precompute = true; + for(auto p: points) { + p->precompute = p->flat; + push_point(p->precompute, 0, stereo::ipd*ed/2); + } + } + } + } + else { + xview = stereo::tanfov * model_distance; + yview = stereo::tanfov * model_distance * vid.yres / vid.xres; + glOrtho(-xview, xview, yview, -yview, -1000, 1000); + } + glColor4f(1.f, 1.f, 1.f, 1.f); -#if CAP_ODS - if(ods) { - glOrtho(-M_PI, M_PI, -M_PI, M_PI, 0, -M_PI * 2); - } - else -#endif - if(rug_perspective) { - ld vnear = .001; - ld vfar = 1000; - ld sca = vnear * tanfov / vid.xres; - xview = -tanfov; - yview = -tanfov * vid.yres / vid.xres; - glFrustum(-sca * vid.xres, sca * vid.xres, -sca * vid.yres, sca * vid.yres, vnear, vfar); - } - else { - xview = tanfov * model_distance; - yview = tanfov * model_distance * vid.yres / vid.xres; - - glOrtho(-xview, xview, -yview, yview, -1000, 1000); - } - - glColor4f(1.f, 1.f, 1.f, 1.f); - - if(rug_perspective && gwhere >= gSphere) { - glEnable(GL_FOG); - glFogi(GL_FOG_MODE, GL_LINEAR); - glFogf(GL_FOG_START, 0); - glFogf(GL_FOG_END, gwhere == gSphere ? 10 : 4); - } - - if(vid.eye > .001 || vid.eye < -.001) { - selectEyeMask(1); - glClear(GL_DEPTH_BUFFER_BIT); - glBegin(GL_TRIANGLES); - eyemod = 1; - for(int t=0; t= gSphere) { + glEnable(GL_FOG); + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogf(GL_FOG_START, 0); + glFogf(GL_FOG_END, gwhere == gSphere ? 10 : 4); + } + glBegin(GL_TRIANGLES); for(int t=0; tpat * C0; - if(sphere && vid.alphax > 1.001) for(int i=0; i<3; i++) ctr[i] = -ctr[i]; + if(sphere && vid.alpha > 1.001) for(int i=0; i<3; i++) ctr[i] = -ctr[i]; hyperpoint h = inverse(m->pat) * rgpushxto0(ctr) * jh; diff --git a/textures.cpp b/textures.cpp index 1b1c478a..be5561a0 100644 --- a/textures.cpp +++ b/textures.cpp @@ -467,7 +467,7 @@ void drawRawTexture() { glMatrixMode(GL_MODELVIEW); glcolor2(0xFFFFFF20); glPushMatrix(); - glTranslatef(0, 0, vid.scrdist); + glTranslatef(0, 0, stereo::scrdist); glBindTexture(GL_TEXTURE_2D, textureid); vector tver, sver; for(int i=0; i<4; i++) {