BGE VideoTexture: add depth buffer access to ImageViewport and ImageRender.
authorBenoit Bolsee <benoit.bolsee@online.be>
Sat, 20 Oct 2012 22:28:44 +0000 (22:28 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Sat, 20 Oct 2012 22:28:44 +0000 (22:28 +0000)
2 new attributes to ImageViewport and ImageRender object:
depth: set to True to retrieve the depth buffer as an array of float
       (not suitable for texture source).
zbuff: set to True to retrieve the depth buffer as a grey scale pixel array
       (suitable for texture source).

A new mode 'F' is added to VideoTexture.imageToArray() to allow returning the image
buffer as a one dimensional array of float. This mode should only be used to retrieve
the depth buffer of ImageViewport and ImageRender objects.

Example:

viewport = VideoTexture.ImageViewport()
viewport.depth = True
depth = VideoTexture.imageToArray(viewport,'F')
# show depth of bottom left pixel
# 1.0 = infinite, 0.0 = on near clip plane.
print(depth[0])

doc/python_api/rst/bge.texture.rst
source/gameengine/VideoTexture/FilterBase.h
source/gameengine/VideoTexture/FilterSource.h
source/gameengine/VideoTexture/ImageBase.cpp
source/gameengine/VideoTexture/ImageBase.h
source/gameengine/VideoTexture/ImageRender.cpp
source/gameengine/VideoTexture/ImageViewport.cpp

index 07d83f66bd4de077a03fbcc66f89cbb1a6008f24..0c9e9da06612eeb9af249b3ba2dec21b5aa3c43e 100644 (file)
@@ -351,6 +351,15 @@ When the texture object is deleted, the new texture is deleted and the old textu
 
       use whole viewport to render
 
+   .. attribute:: depth
+
+      use depth component of render as array of float -  not suitable for texture source,
+      should only be used with bge.texture.imageToArray(mode='F')
+
+   .. attribute:: zbuff
+
+      use depth component of render as grey scale color -  suitable for texture source
+
 .. class:: ImageViewport()
 
    Image source from viewport
@@ -399,6 +408,15 @@ When the texture object is deleted, the new texture is deleted and the old textu
 
       use whole viewport to capture
 
+   .. attribute:: depth
+
+      use depth component of viewport as array of float -  not suitable for texture source,
+      should only be used with bge.texture.imageToArray(mode='F')
+
+   .. attribute:: zbuff
+
+      use depth component of viewport as grey scale color -  suitable for texture source
+
 .. class:: Texture(gameObj)
 
    Texture objects
@@ -518,13 +536,16 @@ When the texture object is deleted, the new texture is deleted and the old textu
       0 to force a fixed 0 color channel and 1 to force a fixed 255 color channel.
       Example: "BGR" will return 3 bytes per pixel with the Blue, Green and Red channels in that order.
       "RGB1" will return 4 bytes per pixel with the Red, Green, Blue channels in that order and the alpha channel forced to 255.
+      A special mode "F" allows to return the image as an array of float. This mode should only be used to retrieve
+      the depth buffer of the ImageViewport and ImageRender object.
       The default mode is "RGBA".
+          
 
    :type mode: string
    :rtype: :class:`~bgl.buffer`
    :return: A object representing the image as one dimensional array of bytes of size (pixel_size*width*height),
       line by line starting from the bottom of the image. The pixel size and format is determined by the mode
-      parameter.
+      parameter. For mode 'F', the array is a one dimensional array of float of size (width*height).
 
 .. function:: materialID(object,name)
 
index 422cf86f23e15316fadd0b3bddc6ef18cf07c750..98bc495375aaa077fc3179dd13562f14dbb87382 100644 (file)
@@ -95,6 +95,10 @@ protected:
        virtual unsigned int filter (unsigned int * src, short x, short y,
                short * size, unsigned int pixSize, unsigned int val = 0)
        { return val; }
+       /// filter pixel, source float buffer
+       virtual unsigned int filter (float * src, short x, short y,
+               short * size, unsigned int pixSize, unsigned int val = 0)
+       { return val; }
 
        /// get source pixel size
        virtual unsigned int getPixelSize (void) { return 1; }
index a4900e8c1485ee355e5a131308c29bea639bc832..0e0a3e8d1b9a5e92e92806534747e8405d7dac35 100644 (file)
@@ -31,7 +31,6 @@ http://www.gnu.org/copyleft/lesser.txt.
 
 #include "FilterBase.h"
 
-
 /// class for RGB24 conversion
 class FilterRGB24 : public FilterBase
 {
@@ -97,6 +96,65 @@ protected:
        { VT_RGBA(val,src[2],src[1],src[0],0xFF); return val; }
 };
 
+/// class for Z_buffer conversion
+class FilterZZZA : public FilterBase
+{
+public:
+       /// constructor
+       FilterZZZA (void) {}
+       /// destructor
+       virtual ~FilterZZZA (void) {}
+
+       /// get source pixel size
+       virtual unsigned int getPixelSize (void) { return 1; }
+
+protected:
+       /// filter pixel, source float buffer
+       virtual unsigned int filter (float * src, short x, short y,
+               short * size, unsigned int pixSize, unsigned int val)
+       {
+               // calculate gray value
+        // convert float to unsigned char
+               unsigned int depth = int(src[0] * 255);
+               // return depth scale value
+               VT_R(val) = depth;
+               VT_G(val) = depth;
+               VT_B(val) = depth;
+               VT_A(val) = 0xFF;
+
+               return val;
+       }
+};
+
+
+/// class for Z_buffer conversion
+class FilterDEPTH : public FilterBase
+{
+public:
+       /// constructor
+       FilterDEPTH (void) {}
+       /// destructor
+       virtual ~FilterDEPTH (void) {}
+
+       /// get source pixel size
+       virtual unsigned int getPixelSize (void) { return 1; }
+
+protected:
+       /// filter pixel, source float buffer
+       virtual unsigned int filter (float * src, short x, short y,
+               short * size, unsigned int pixSize, unsigned int val)
+       {
+        // Copy the float value straight away
+               // The user can retrieve the original float value by using 
+               // 'F' mode in BGL buffer
+        memcpy(&val, src, sizeof (unsigned int));
+               return val;
+       }
+};
+
+
+
+
 /// class for YV12 conversion
 class FilterYV12 : public FilterBase
 {
index 2de49795681521b85f2622a5761692b3a4b3a05e..de54d8e8940c33b34959519a6b116d3134d5d423 100644 (file)
@@ -49,6 +49,8 @@ extern "C" {
 // constructor
 ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0),
 m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false),
+m_zbuff(false),
+m_depth(false),
 m_staticSources(staticSrc), m_pyfilter(NULL)
 {
        m_size[0] = m_size[1] = 0;
@@ -402,6 +404,18 @@ PyObject *Image_getImage (PyImage *self, char * mode)
                        {
                                buffer = BGL_MakeBuffer( GL_BYTE, 1, &dimensions, image);
                        }
+                       else if (!strcasecmp(mode, "F"))
+                       {
+                               // this mode returns the image as an array of float.
+                               // This makes sense ONLY for the depth buffer:
+                               //   source = VideoTexture.ImageViewport()
+                               //   source.depth = True
+                               //   depth = VideoTexture.imageToArray(source, 'F')
+
+                               // adapt dimension from byte to float
+                               dimensions /= sizeof(float);
+                               buffer = BGL_MakeBuffer( GL_FLOAT, 1, &dimensions, image);
+                       }
                        else 
                        {
                                int i, c, ncolor, pixels;
@@ -532,6 +546,52 @@ int Image_setFlip (PyImage *self, PyObject *value, void *closure)
        return 0;
 }
 
+// get zbuff
+PyObject * Image_getZbuff (PyImage * self, void * closure)
+{
+       if (self->m_image != NULL && self->m_image->getZbuff()) Py_RETURN_TRUE;
+       else Py_RETURN_FALSE;
+}
+
+// set zbuff
+int Image_setZbuff (PyImage * self, PyObject * value, void * closure)
+{
+       // check parameter, report failure
+       if (value == NULL || !PyBool_Check(value))
+       {
+               PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+               return -1;
+       }
+       // set scale
+       if (self->m_image != NULL) self->m_image->setZbuff(value == Py_True);
+       // success
+       return 0;
+}
+
+// get depth
+PyObject * Image_getDepth (PyImage * self, void * closure)
+{
+       if (self->m_image != NULL && self->m_image->getDepth()) Py_RETURN_TRUE;
+       else Py_RETURN_FALSE;
+}
+
+// set depth
+int Image_setDepth (PyImage * self, PyObject * value, void * closure)
+{
+       // check parameter, report failure
+       if (value == NULL || !PyBool_Check(value))
+       {
+               PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+               return -1;
+       }
+       // set scale
+       if (self->m_image != NULL) self->m_image->setDepth(value == Py_True);
+       // success
+       return 0;
+}
+
+
+
 
 // get filter source object
 PyObject *Image_getSource (PyImage *self, PyObject *args)
index bb3f0c19e4b09c09136c415a1f315dfaa81e44a7..a9f25f614069a70e9016d45a9431b8e563bbf4a5 100644 (file)
@@ -78,6 +78,14 @@ public:
        bool getFlip (void) { return m_flip; }
        /// set vertical flip
        void setFlip (bool flip) { m_flip = flip; }
+       /// get Z buffer
+       bool getZbuff (void) { return m_zbuff; }
+       /// set Z buffer
+       void setZbuff (bool zbuff) { m_zbuff = zbuff; }
+       /// get depth
+       bool getDepth (void) { return m_depth; }
+       /// set depth
+       void setDepth (bool depth) { m_depth = depth; }
 
        /// get source object
        PyImage * getSource (const char * id);
@@ -111,6 +119,10 @@ protected:
        bool m_scaleChange;
        /// flip image vertically
        bool m_flip;
+       /// use the Z buffer as a texture
+       bool m_zbuff;
+       /// extract the Z buffer with unisgned int precision
+       bool m_depth;
 
        /// source image list
        ImageSourceList m_sources;
@@ -347,7 +359,15 @@ int Image_setFlip (PyImage *self, PyObject *value, void *closure);
 PyObject *Image_getSource (PyImage *self, PyObject *args);
 // set filter source object
 PyObject *Image_setSource (PyImage *self, PyObject *args);
-
+// get Z buffer
+PyObject * Image_getZbuff (PyImage * self, void * closure);
+// set Z buffer
+int Image_setZbuff (PyImage * self, PyObject * value, void * closure);
+// get depth
+PyObject * Image_getDepth (PyImage * self, void * closure);
+// set depth
+int Image_setDepth (PyImage * self, PyObject * value, void * closure);
 // get pixel filter object
 PyObject *Image_getFilter (PyImage *self, void *closure);
 // set pixel filter object
index 2135d0a07eb5a0798388ca8e36a556889237fd17..85857165403823d6450a05cd3909e1a8f9c20807 100644 (file)
@@ -385,6 +385,8 @@ static PyGetSetDef imageRenderGetSets[] =
        {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
        {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)",  NULL},
        {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+       {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
+       {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL},
        {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
        {NULL}
 };
@@ -547,6 +549,8 @@ static PyGetSetDef imageMirrorGetSets[] =
        {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
        {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)",  NULL},
        {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+       {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
+       {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL},
        {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
        {NULL}
 };
index 9b503efcf39783338b1abb1da8c8235a30f4e569..0836422576ff6e0b4d7b875831723a7e1b469773 100644 (file)
@@ -50,6 +50,8 @@ ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
        
        //glGetIntegerv(GL_VIEWPORT, m_viewport);
        // create buffer for viewport image
+       // Warning: this buffer is also used to get the depth buffer as an array of
+       //          float (1 float = 4 bytes per pixel)
        m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]];
        // set attributes
        setWhole(false);
@@ -57,7 +59,9 @@ ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false)
 
 // destructor
 ImageViewport::~ImageViewport (void)
-{ delete [] m_viewportImage; }
+{
+    delete [] m_viewportImage;
+}
 
 
 // use whole viewport to capture image
@@ -131,7 +135,7 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
        }
        // if texture can be directly created
        if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0])
-               && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip)
+               && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip && !m_zbuff && !m_depth)
        {
                // just copy current viewport to texture
                glBindTexture(GL_TEXTURE_2D, texId);
@@ -142,6 +146,32 @@ void ImageViewport::calcImage (unsigned int texId, double ts)
        // otherwise copy viewport to buffer, if image is not available
        else if (!m_avail)
        {
+        if (m_zbuff)
+        {
+            // Use read pixels with the depth buffer
+                       // *** misusing m_viewportImage here, but since it has the correct size
+                       //     (4 bytes per pixel = size of float) and we just need it to apply 
+                       //     the filter, it's ok
+            glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
+                    GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage);
+            // filter loaded data
+            FilterZZZA filt;
+            filterImage(filt, (float *)m_viewportImage, m_capSize);
+        }
+        else
+
+        if (m_depth)
+        {
+            // Use read pixels with the depth buffer
+                       // See warning above about m_viewportImage.
+            glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
+                    GL_DEPTH_COMPONENT, GL_FLOAT, m_viewportImage);
+            // filter loaded data
+            FilterDEPTH filt;
+            filterImage(filt, (float *)m_viewportImage, m_capSize);
+        }
+        else
+
                // get frame buffer data
                if (m_alpha)
                {
@@ -310,6 +340,8 @@ static PyGetSetDef imageViewportGetSets[] =
        {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
        {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)", NULL},
        {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+       {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
+       {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer as array of float", NULL},
        {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
        {NULL}
 };