diff --git a/modules/base/pymod/__init__.py b/modules/base/pymod/__init__.py index c6d7a8ec17b8085fb4412236f0bfbbf5f6cc648f..286bedced409ad9f66317d0ee7a71afde1c53082 100644 --- a/modules/base/pymod/__init__.py +++ b/modules/base/pymod/__init__.py @@ -27,6 +27,7 @@ from ost import seq try: from ost import gfx scene = gfx.Scene() + scene.Stereo=gfx.Stereo except ImportError: pass diff --git a/modules/gfx/pymod/__init__.py b/modules/gfx/pymod/__init__.py index 8c0b24a8872811e1cca02cd6a350b9fcf8d47de7..11fb994719d9243b29256afa445a0f5b488a82b5 100644 --- a/modules/gfx/pymod/__init__.py +++ b/modules/gfx/pymod/__init__.py @@ -47,6 +47,23 @@ DARKORANGE=Color(0.5,0.25,0.0) LIGHTORANGE=Color(1.0,0.75,0.5) +def Stereo(mode,flip=None,alg=None): + """ + Stereo control + + :param mode: 0=off, 1=quad-buffered, 2=interlaced + :type mode: int + :param flip: invert order of left/right display + :type flip: bool + :param alg: stereo algorithm (0 or 1) + :type param: int + """ + if(flip): + _gfx.Scene().SetStereoFlip(flip) + if(alg): + _gfx.Scene().SetStereoAlg(alg) + if(mode): + _gfx.Scene().SetStereoMode(mode) def FitToScreen(gfx_ent, width=None, height=None, margin=0.01): """ diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc index b143288451273f7c9b81edffbc75b82933dbde1e..706767f8b2bfabffd6827e06c4aada663d986dc3 100644 --- a/modules/gfx/pymod/export_scene.cc +++ b/modules/gfx/pymod/export_scene.cc @@ -135,11 +135,21 @@ void export_Scene() .add_property("smode", &Scene::GetSelectionMode, &Scene::SetSelectionMode) - .def("Stereo",&Scene::Stereo) - .def("SetStereoInverted",&Scene::SetStereoInverted) + .def("SetStereoMode",&Scene::SetStereoMode) + .def("GetStereoMode",&Scene::GetStereoMode) + .add_property("stereo_mode",&Scene::GetStereoMode,&Scene::SetStereoMode) + .def("SetStereoFlip",&Scene::SetStereoFlip) + .def("GetStereoFlip",&Scene::GetStereoFlip) + .add_property("stereo_flip",&Scene::GetStereoFlip,&Scene::SetStereoFlip) .def("SetStereoView",&Scene::SetStereoView) - .def("SetStereoEyeDist",&Scene::SetStereoEyeDist) - .def("SetStereoEyeOff",&Scene::SetStereoEyeOff) + .def("GetStereoView",&Scene::GetStereoView) + .add_property("stereo_view",&Scene::GetStereoView,&Scene::SetStereoView) + .def("SetStereoIOD",&Scene::SetStereoIOD) + .def("GetStereoIOD",&Scene::GetStereoIOD) + .add_property("stereo_iod",&Scene::GetStereoIOD,&Scene::SetStereoIOD) + .def("SetStereoAlg",&Scene::SetStereoAlg) + .def("GetStereoAlg",&Scene::GetStereoAlg) + .add_property("stereo_alg",&Scene::GetStereoAlg,&Scene::SetStereoAlg) .def("SetLightDir",&Scene::SetLightDir) .def("SetLightProp",set_light_prop1) .def("SetLightProp",set_light_prop2) diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc index 92707149d8f387dfbf80ebff41617d1c4b86e228..1574d5f509b871524a7b6e76674f18561316a059 100644 --- a/modules/gfx/src/scene.cc +++ b/modules/gfx/src/scene.cc @@ -123,11 +123,11 @@ Scene::Scene(): def_text_size_(32.0), blur_count_(0), blur_buffer_(), - stereo_(0), + stereo_mode_(0), + stereo_alg_(0), stereo_inverted_(false), stereo_eye_(0), - stereo_eye_dist_(2.4), - stereo_eye_off_(0.0), + stereo_eye_dist_(40.0), scene_left_tex_(), scene_right_tex_() { @@ -636,7 +636,7 @@ void Scene::RenderGL() prep_blur(); - if(stereo_==1 || stereo_==2) { + if(stereo_mode_==1 || stereo_mode_==2) { render_stereo(); } else { render_scene(); @@ -1279,48 +1279,52 @@ void Scene::SetFogOffsets(float no, float fo) RequestRedraw(); } -void Scene::Stereo(unsigned int m) +void Scene::SetStereoMode(unsigned int m) { if(m==1) { if(win_ && win_->HasStereo()) { - stereo_=1; + stereo_mode_=1; } else { LOG_INFO("Scene: No visual present for quad-buffered stereo"); - stereo_=0; + stereo_mode_=0; } } else if(m==2) { - stereo_=2; + stereo_mode_=2; } else { - stereo_=0; + stereo_mode_=0; } RequestRedraw(); } -void Scene::SetStereoInverted(bool f) +void Scene::SetStereoFlip(bool f) { stereo_inverted_=f; RequestRedraw(); } -void Scene::SetStereoView(unsigned int m) +void Scene::SetStereoView(int m) { - stereo_eye_= (m>2) ? 0: m; + stereo_eye_= m; ResetProjection(); RequestRedraw(); } -void Scene::SetStereoEyeDist(float d) +void Scene::SetStereoIOD(float d) { stereo_eye_dist_=d; - if(stereo_>0) { + if(stereo_mode_>0) { RequestRedraw(); } } -void Scene::SetStereoEyeOff(float d) +void Scene::SetStereoAlg(unsigned int a) { - stereo_eye_off_=d; - if(stereo_>0) { + if(a==0 || a==1) { + stereo_alg_=a; + } else { + stereo_alg_=0; + } + if(stereo_mode_>0) { RequestRedraw(); } } @@ -1812,37 +1816,48 @@ void Scene::render_glow() #endif } -void Scene::stereo_projection(unsigned int view) +void Scene::stereo_projection(int view) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - - GLdouble zn=std::max<float>(1.0,znear_); - GLdouble zf=std::max<float>(1.1,zfar_); - - GLdouble top = zn * std::tan(fov_*M_PI/360.0); - GLdouble bot = -top; - GLdouble right = top*aspect_ratio_; - GLdouble left = -right; + Real zn=std::max<Real>(1.0,znear_); + Real zf=std::max<Real>(1.1,zfar_); + + Real top = zn * std::tan(fov_*M_PI/360.0); + Real bot = -top; + Real right = top*aspect_ratio_; + Real left = -right; + glFrustum(left,right,bot,top,zn,zf); - - if(view==1 || view==2) { - float ff=(view==1 ? -1.0 : 1.0); - float dist=-transform_.GetTrans()[2]; - geom::Mat4 skew=geom::Transpose(geom::Mat4(1.0,0.0,ff*stereo_eye_dist_/dist,ff*stereo_eye_dist_, - 0.0,1.0,0.0,0.0, - 0.0,0.0,1.0,0.0, - 0.0,0.0,0.0,1.0)); - glMultMatrix(skew.Data()); + + if(view!=0) { + Real ff=(view<0 ? 1.0 : -1.0); + Real dist=-transform_.GetTrans()[2]; + if(stereo_alg_==1) { + // physically precise stereo with skew, does + // not handle z translation well + // the 100.0 comes from visual matching with mode 0 at a reasonable distance + Real iod2=100.0/stereo_eye_dist_; + geom::Mat4 skew=geom::Transpose(geom::Mat4(1.0,0.0,ff*iod2/dist,ff*iod2, + 0.0,1.0,0.0,0.0, + 0.0,0.0,1.0,0.0, + 0.0,0.0,0.0,1.0)); + glMultMatrix(skew.Data()); + } else { + // default, dino style stereo, less physically precise but visually more pleasing + glTranslated(0.0,0.0,-dist); + glRotated(180.0/M_PI*atan(ff/stereo_eye_dist_),0.0,1.0,0.0); + glTranslated(0.0,0.0,dist); + } } - } void Scene::render_stereo() { - stereo_eye_=1; - stereo_projection(1); + int old_stereo_eye=stereo_eye_; + stereo_eye_=-1; + stereo_projection(-1); render_scene(); glEnable(GL_TEXTURE_2D); @@ -1854,8 +1869,8 @@ void Scene::render_stereo() glBindTexture(GL_TEXTURE_2D, scene_left_tex_); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, vp_width_, vp_height_, 0); - stereo_eye_=2; - stereo_projection(2); + stereo_eye_=1; + stereo_projection(1); render_scene(); glEnable(GL_TEXTURE_2D); #if OST_SHADER_SUPPORT_ENABLED @@ -1865,7 +1880,7 @@ void Scene::render_stereo() #endif glBindTexture(GL_TEXTURE_2D, scene_right_tex_); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, vp_width_, vp_height_, 0); - stereo_eye_=0; + stereo_eye_=old_stereo_eye; stereo_projection(0); #if OST_SHADER_SUPPORT_ENABLED @@ -1893,7 +1908,7 @@ void Scene::render_stereo() glPushMatrix(); glLoadIdentity(); - if(stereo_==2) { + if(stereo_mode_==2) { // draw interlace lines in stencil buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLineWidth(1.0); @@ -1915,10 +1930,10 @@ void Scene::render_stereo() } // right eye - if(stereo_==1) { + if(stereo_mode_==1) { glDrawBuffer(GL_BACK_RIGHT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } else if(stereo_==2) { + } else if(stereo_mode_==2) { glStencilFunc(GL_EQUAL,0x0,0x1); } #if OST_SHADER_SUPPORT_ENABLED @@ -1937,10 +1952,10 @@ void Scene::render_stereo() glEnd(); // left eye - if(stereo_==1) { + if(stereo_mode_==1) { glDrawBuffer(GL_BACK_LEFT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } else if(stereo_==2) { + } else if(stereo_mode_==2) { glStencilFunc(GL_EQUAL,0x1,0x1); } #if OST_SHADER_SUPPORT_ENABLED diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh index ec4c0e13745832a3117d050899bb518da29c6739..5a93998485fbbe8428074f71149e2e4bbc349445 100644 --- a/modules/gfx/src/scene.hh +++ b/modules/gfx/src/scene.hh @@ -168,34 +168,46 @@ class DLLEXPORT_OST_GFX Scene { void SetFogOffsets(float no, float fo); /// \brief adjust near and far clipping plane to fit visible objects + // TODO: use mode aka fast, precise, max void Autoslab(bool fast=false, bool redraw=true); - // \brief adjust clipping planes to fix maximal extent of all objects - // even under rotation + + /// \brief adjust clipping planes to fix maximal extent of all objects + /// even under rotation + // TODO: merge with Autoslab void AutoslabMax(); /// \brief turn on automatic auto-slabbing (using the fast bounding box alg) + // TODO: more sophisticated mode, aka fast, precise, max void AutoAutoslab(bool f); //@} - /// \brief switch stereo mode - /* - 0=off - 1=quad-buffered - 2=interlaced stereo - */ - void Stereo(unsigned int); - - int GetStereo() const {return stereo_;} + /// \brief set stereo mode + /// one of 0 (off), 1 (quad-buffered) 2 (interlaced (for special monitors)) + void SetStereoMode(unsigned int mode); + int GetStereoMode() const {return stereo_mode_;} /// \brief invert stereo eyes for stereo mode=0 - void SetStereoInverted(bool f); - - /// \brief stereo view mode, 0=center, 1=left, 2=right - void SetStereoView(unsigned int); - - void SetStereoEyeDist(float); - void SetStereoEyeOff(float); - + void SetStereoFlip(bool f); + /// \brief return invert flag for stereo + bool GetStereoFlip() const {return stereo_inverted_;} + + /// \brief stereo view mode + /// one of 0 (center), -1 (left), 1 (right) + void SetStereoView(int); + /// \brief return current stereo view mode + int GetStereoView() const {return stereo_eye_;} + + /// \brief set stereo eye distance + void SetStereoIOD(float); + /// \brief return current stereo eye distance + float GetStereoIOD() const {return stereo_eye_dist_;} + + /// \brief set stereo algorithm + /// one of 0 or 1 + void SetStereoAlg(unsigned int); + /// \brief return current stereo algorithm + unsigned int GetStereoAlg() const {return stereo_alg_;} + /// \brief set main light direction void SetLightDir(const geom::Vec3& dir); /// \brief set ambient, diffuse and specular light color @@ -458,10 +470,11 @@ private: uint blur_count_; std::vector<boost::shared_array<unsigned char> > blur_buffer_; - unsigned int stereo_; + unsigned int stereo_mode_; + unsigned int stereo_alg_; bool stereo_inverted_; unsigned int stereo_eye_; - float stereo_eye_dist_,stereo_eye_off_; + float stereo_eye_dist_; unsigned int scene_left_tex_; unsigned int scene_right_tex_; @@ -471,7 +484,7 @@ private: void flag_all_dirty(); void prep_glyphs(); void prep_blur(); - void stereo_projection(unsigned int view); + void stereo_projection(int view); void render_scene(); void render_glow(); void render_stereo(); diff --git a/modules/gui/src/gl_canvas.cc b/modules/gui/src/gl_canvas.cc index 98f9ccc8444ba88568aef81449ab961d501e9a8f..d1a7aa9b89c9c75b93e837cd48047b6339fedf1f 100644 --- a/modules/gui/src/gl_canvas.cc +++ b/modules/gui/src/gl_canvas.cc @@ -436,10 +436,10 @@ void GLCanvas::keyPressEvent(QKeyEvent* event) DoRefresh(); return; } else if(event->key()==Qt::Key_Equal) { - if(gfx::Scene::Instance().GetStereo()>0) { - gfx::Scene::Instance().Stereo(0); + if(gfx::Scene::Instance().GetStereoMode()>0) { + gfx::Scene::Instance().SetStereoMode(0); } else { - gfx::Scene::Instance().Stereo(1); + gfx::Scene::Instance().SetStereoMode(1); } DoRefresh(); return;