From 657eff7ed7f23e9218a22ff6b3c96d331d69dd47 Mon Sep 17 00:00:00 2001 From: Kester Maddock Date: Sun, 24 Oct 2004 11:03:18 +0000 Subject: [PATCH] Port stereo stuff from tuhopuu2: anaglyph, vinterlace --- source/blender/src/buttons_scene.c | 18 ++++-- .../gameengine/GamePlayer/ghost/GPG_ghost.cpp | 9 +++ source/gameengine/Ketsji/KX_PythonInit.cpp | 48 ++++++++++++++ source/gameengine/PyDoc/Rasterizer.py | 47 ++++++++++++++ source/gameengine/PyDoc/WhatsNew.py | 2 + .../gameengine/Rasterizer/RAS_IRasterizer.h | 10 ++- .../RAS_OpenGLRasterizer.cpp | 64 +++++++++++++++++-- .../RAS_OpenGLRasterizer.h | 5 ++ 8 files changed, 190 insertions(+), 13 deletions(-) diff --git a/source/blender/src/buttons_scene.c b/source/blender/src/buttons_scene.c index a6628478636..232b30bffcf 100644 --- a/source/blender/src/buttons_scene.c +++ b/source/blender/src/buttons_scene.c @@ -841,13 +841,13 @@ static uiBlock *post_render_menu(void *arg_unused) static uiBlock *framing_render_menu(void *arg_unused) { uiBlock *block; - short yco = 170, xco = 0; + short yco = 190, xco = 0; int randomcolorindex = 1234; block= uiNewBlock(&curarea->uiblocks, "framing_options", UI_EMBOSS, UI_HELV, curarea->win); /* use this for a fake extra empy space around the buttons */ - uiDefBut(block, LABEL, 0, "", -10, -10, 300, 209, NULL, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "", -10, -10, 300, 229, NULL, 0, 0, 0, 0, ""); uiDefBut(block, LABEL, B_NOP, "Framing:", xco, yco, 68,19, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); @@ -886,12 +886,18 @@ static uiBlock *framing_render_menu(void *arg_unused) * RAS_STEREO_QUADBUFFERED 2 * RAS_STEREO_ABOVEBELOW 3 * RAS_STEREO_INTERLACED 4 future + * RAS_STEREO_ANAGLYPH 5 + * RAS_STEREO_SIDEBYSIDE 6 + * RAS_STEREO_VINTERLACE 7 */ - uiDefBut(block, LABEL, 0, "Stereo:", xco, yco-=30, 68, 19, 0, 0.0, 0.0, 0, 0, ""); uiBlockBeginAlign(block); - uiDefButS(block, ROW, 0, "None", xco+=70, yco, 68, 19, &(G.scene->r.stereomode), 6.0, 1.0, 0, 0, "Disables stereo"); - uiDefButS(block, ROW, 0, "Pageflip", xco+=70, yco, 68, 19, &(G.scene->r.stereomode), 6.0, 2.0, 0, 0, "Enables hardware pageflip stereo method"); - uiDefButS(block, ROW, 0, "Syncdouble", xco+=70, yco, 68, 19, &(G.scene->r.stereomode), 6.0, 3.0, 0, 0, "Enables syncdoubling stereo method"); + uiDefButS(block, ROW, 0, "No Stereo", xco, yco-=30, 88, 19, &(G.scene->r.stereomode), 7.0, 1.0, 0, 0, "Disables stereo"); + uiDefButS(block, ROW, 0, "Pageflip", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 2.0, 0, 0, "Enables hardware pageflip stereo method"); + uiDefButS(block, ROW, 0, "Syncdouble", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 3.0, 0, 0, "Enables syncdoubling stereo method"); + uiDefButS(block, ROW, 0, "Anaglyph", xco-=180, yco-=21, 88, 19, &(G.scene->r.stereomode), 7.0, 5.0, 0, 0, "Enables anaglyph (Red-Blue) stereo method"); + uiDefButS(block, ROW, 0, "Side by Side", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 6.0, 0, 0, "Enables side by side left and right images"); + uiDefButS(block, ROW, 0, "V Interlace", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 7.0, 0, 0, "Enables interlaced vertical strips for autostereo display"); + uiBlockEndAlign(block); uiBlockSetDirection(block, UI_TOP); diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 5f702041c41..60d49d047da 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -124,6 +124,7 @@ void usage(char* program) printf(" syncdoubling (Above Below)\n"); printf(" sidebyside (Left Right)\n"); printf(" anaglyph (Red-Blue glasses)\n"); + printf(" vinterlace (Vertical interlace for autostereo display)\n"); printf(" depending on the type of stereo you want\n"); #ifdef _WIN32 printf(" -c: keep console window open\n"); @@ -379,6 +380,10 @@ int main(int argc, char** argv) i++; if ((i + 1) < argc) { + stereomode = (RAS_IRasterizer::StereoMode) atoi(argv[i]); + if (stereomode < RAS_IRasterizer::RAS_STEREO_NOSTEREO || stereomode >= RAS_IRasterizer::RAS_STEREO_MAXSTEREO) + stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO; + if(!strcmp(argv[i], "nostereo")) // ok, redundant but clear stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO; @@ -395,6 +400,10 @@ int main(int argc, char** argv) if(!strcmp(argv[i], "sidebyside")) stereomode = RAS_IRasterizer::RAS_STEREO_SIDEBYSIDE; + + if(!strcmp(argv[i], "vinterlace")) + stereomode = RAS_IRasterizer::RAS_STEREO_VINTERLACE; + #if 0 // future stuff if(strcmp(argv[i], "stencil") diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index ba466f20f64..42b26185b4c 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -341,7 +341,51 @@ static PyObject* gPySetMousePosition(PyObject*, Py_Return; } +static PyObject* gPySetEyeSeparation(PyObject*, + PyObject* args, + PyObject*) +{ + float sep; + if (PyArg_ParseTuple(args, "f", &sep)) + { + if (gp_Rasterizer) + gp_Rasterizer->SetEyeSeparation(sep); + + Py_Return; + } + + return NULL; +} +static PyObject* gPyGetEyeSeparation(PyObject*, PyObject*, PyObject*) +{ + if (gp_Rasterizer) + return PyFloat_FromDouble(gp_Rasterizer->GetEyeSeparation()); + + return NULL; +} + +static PyObject* gPySetFocalLength(PyObject*, + PyObject* args, + PyObject*) +{ + float focus; + if (PyArg_ParseTuple(args, "f", &focus)) + { + if (gp_Rasterizer) + gp_Rasterizer->SetFocalLength(focus); + Py_Return; + } + + return NULL; +} + +static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*) +{ + if (gp_Rasterizer) + return PyFloat_FromDouble(gp_Rasterizer->GetFocalLength()); + return NULL; +} static PyObject* gPySetBackgroundColor(PyObject*, PyObject* args, @@ -461,6 +505,10 @@ static struct PyMethodDef rasterizer_methods[] = { {"setMistStart",(PyCFunction)gPySetMistStart,METH_VARARGS,"set Mist Start(rgb)"}, {"setMistEnd",(PyCFunction)gPySetMistEnd,METH_VARARGS,"set Mist End(rgb)"}, + {"setEyeSeparation", (PyCFunction) gPySetEyeSeparation, METH_VARARGS, "set the eye separation for stereo mode"}, + {"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_VARARGS, "get the eye separation for stereo mode"}, + {"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"}, + {"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"}, { NULL, (PyCFunction) NULL, 0, NULL } }; diff --git a/source/gameengine/PyDoc/Rasterizer.py b/source/gameengine/PyDoc/Rasterizer.py index ef6ec4c0bea..78be4b4804f 100644 --- a/source/gameengine/PyDoc/Rasterizer.py +++ b/source/gameengine/PyDoc/Rasterizer.py @@ -56,6 +56,15 @@ def makeScreenshot(filename): """ Writes a screenshot to the given filename. + If filename starts with // the image will be saved relative to the current directory. + If the filename contains # it will be replaced with the frame number. + + The standalone player saves .png files. It does not support colour space conversion + or gamma correction. + + When run from Blender, makeScreenshot supports Iris, IrisZ, TGA, Raw TGA, PNG, HamX, and Jpeg. + Gamma, Colourspace conversion and Jpeg compression are taken from the Render settings panels. + @type filename: string """ @@ -106,4 +115,42 @@ def setMistEnd(end): @type end: float """ + +def setEyeSeparation(eyesep): + """ + Sets the eye separation for stereo mode. + + @param eyesep: The distance between the left and right eye. + If eyesep < 0.0, eye separation will be automatically determined from the projection + matrix. + @type eyesep: float + """ +def getEyeSeparation(): + """ + Gets the current eye separation for stereo mode. + + If the returned eye separation is < 0.0, the eye separation will be + automatically set on the next frame. + + @rtype: float + """ + +def setFocalLength(focallength): + """ + Sets the focal length for stereo mode. + + @param focallength: The focal length. If focallength < 0.0, the focal length will + be automatically determined. + @type focallength: float + """ + +def getFocalLength(): + """ + Gets the current focal length for stereo mode. + + If the returned focal length is < 0.0, the focal length will be + automatically set on the next frame. + + @rtype: float + """ diff --git a/source/gameengine/PyDoc/WhatsNew.py b/source/gameengine/PyDoc/WhatsNew.py index 777c87a2f48..dcc6ba4883c 100644 --- a/source/gameengine/PyDoc/WhatsNew.py +++ b/source/gameengine/PyDoc/WhatsNew.py @@ -8,6 +8,8 @@ This document lists what has been changed in the Game Engine Python API. Blender CVS ------------ - Added tic rate methods to L{GameLogic} + - Added stereo eye separation and focal length methods to L{Rasterizer}. + - Fixed L{Raterizer}.makeScreenshot() method. Blender 2.34 ------------ diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index 60edec7ada9..bd7f10e32a7 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -93,7 +93,10 @@ public: RAS_STEREO_ABOVEBELOW, RAS_STEREO_INTERLACED, RAS_STEREO_ANAGLYPH, - RAS_STEREO_SIDEBYSIDE + RAS_STEREO_SIDEBYSIDE, + RAS_STEREO_VINTERLACE, + + RAS_STEREO_MAXSTEREO }; /** * Render pass identifiers for stereo. @@ -157,12 +160,17 @@ public: * Sets which eye buffer subsequent primitives will be rendered to. */ virtual void SetEye(const StereoEye eye)=0; + virtual StereoEye GetEye()=0; /** + * Sets the distance between eyes for stereo mode. */ virtual void SetEyeSeparation(const float eyeseparation)=0; + virtual float GetEyeSeparation() = 0; /** + * Sets the focal length for stereo mode. */ virtual void SetFocalLength(const float focallength)=0; + virtual float GetFocalLength() = 0; /** * SwapBuffers swaps the back buffer with the front buffer. */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 8b949ac57b6..803ccbc2b63 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -58,6 +58,8 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas) m_time(0.0), m_stereomode(RAS_STEREO_NOSTEREO), m_curreye(RAS_STEREO_LEFTEYE), + m_eyeseparation(-1.0f), + m_focallength(-1.0f), m_noOfScanlines(32), m_materialCachingInfo(0) { @@ -265,7 +267,9 @@ void RAS_OpenGLRasterizer::Exit() glDepthMask (GL_TRUE); glDepthFunc(GL_LEQUAL); glBlendFunc(GL_ONE, GL_ZERO); - + + glDisable(GL_POLYGON_STIPPLE); + glDisable(GL_LIGHTING); if (bgl::QueryExtension(bgl::_GL_EXT_separate_specular_color) || bgl::QueryVersion(1, 2)) glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); @@ -273,15 +277,21 @@ void RAS_OpenGLRasterizer::Exit() EndFrame(); } - +bool RAS_OpenGLRasterizer::InterlacedStereo() const +{ + return m_stereomode == RAS_STEREO_VINTERLACE || m_stereomode == RAS_STEREO_INTERLACED; +} bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time) { m_time = time; m_drawingmode = drawingmode; - m_2DCanvas->ClearColor(m_redback,m_greenback,m_blueback,m_alphaback); - m_2DCanvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER); + if (!InterlacedStereo() || m_curreye == RAS_STEREO_LEFTEYE) + { + m_2DCanvas->ClearColor(m_redback,m_greenback,m_blueback,m_alphaback); + m_2DCanvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER); + } // Blender camera routine destroys the settings if (m_drawingmode < KX_SOLID) @@ -459,23 +469,63 @@ void RAS_OpenGLRasterizer::SetEye(StereoEye eye) ClearDepthBuffer(); } break; + case RAS_STEREO_VINTERLACE: + { + GLuint pat[32]; + const unsigned char mask = 0x55; // 01010101 + memset(pat, m_curreye == RAS_STEREO_RIGHTEYE?~mask:mask, sizeof(pat)); + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple((const GLubyte*) pat); + if (m_curreye == RAS_STEREO_RIGHTEYE) + ClearDepthBuffer(); + break; + } + case RAS_STEREO_INTERLACED: + { + GLuint pat[32]; + GLuint mask = m_curreye == RAS_STEREO_LEFTEYE?~0:0; + for (int y = 0; y < 32; y+=2) + { + pat[y] = mask; + pat[y+1] = ~mask; + } + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple((const GLubyte*) pat); + if (m_curreye == RAS_STEREO_RIGHTEYE) + ClearDepthBuffer(); + break; + } default: break; } } +RAS_IRasterizer::StereoEye RAS_OpenGLRasterizer::GetEye() +{ + return m_curreye; +} + void RAS_OpenGLRasterizer::SetEyeSeparation(float eyeseparation) { m_eyeseparation = eyeseparation; } +float RAS_OpenGLRasterizer::GetEyeSeparation() +{ + return m_eyeseparation; +} void RAS_OpenGLRasterizer::SetFocalLength(float focallength) { m_focallength = focallength; } +float RAS_OpenGLRasterizer::GetFocalLength() +{ + return m_focallength; +} + void RAS_OpenGLRasterizer::SwapBuffers() { @@ -1109,8 +1159,10 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( { float near_div_focallength; // next 2 params should be specified on command line and in Blender publisher - m_focallength = 1.5 * right; // derived from example - m_eyeseparation = 0.18 * right; // just a guess... + if (m_focallength < 0.0f) + m_focallength = 1.5 * right; // derived from example + if (m_eyeseparation < 0.0f) + m_eyeseparation = 0.18 * right; // just a guess... near_div_focallength = frustnear / m_focallength; switch(m_curreye) diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 4e63697b7ed..9ab7b772cf9 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -74,6 +74,8 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer float m_eyeseparation; float m_focallength; int m_noOfScanlines; + + bool InterlacedStereo() const; protected: int m_drawingmode; @@ -113,8 +115,11 @@ public: virtual void SetStereoMode(const StereoMode stereomode); virtual bool Stereo(); virtual void SetEye(const StereoEye eye); + virtual StereoEye GetEye(); virtual void SetEyeSeparation(const float eyeseparation); + virtual float GetEyeSeparation(); virtual void SetFocalLength(const float focallength); + virtual float GetFocalLength(); virtual void SwapBuffers(); virtual void IndexPrimitives(