diff options
author | Benoit Bolsee <benoit.bolsee@online.be> | 2008-11-26 20:47:42 +0300 |
---|---|---|
committer | Benoit Bolsee <benoit.bolsee@online.be> | 2008-11-26 20:47:42 +0300 |
commit | 6a51ba54cd464ef07bb09f1fa84bd2407ff3e8e7 (patch) | |
tree | 27ce0a91617cb08f3039871972df772bf9abfb0d /source/gameengine/VideoTexture/ImageViewport.cpp | |
parent | 15e193f2535be17a89b5d148155f9ee12a5e142a (diff) |
VideoTexture: new ImageRender class for Render To Texture
The new class VideoTexture.ImageRender() is available to perform
render to texture in the GE.
Constructor:
VideoTexture.ImageRender(scene,cam)
cam : camera object that will be used for the render.
It must be an inactive camera.
scene: reference to the scene that will be rendered.
The camera must be part of that scene.
Returns an object that can be used as a source of a VideoTexture.Texture object
Methods: none
Attributes:
background:
4-tuple representing the background color of the rendering
as RGBA color components, each component being an integer
between 0 and 255.
Default value = [0,0,255,255] (=saturated blue)
Note: athough the alpha component can be specified, it is not
supported at the moment, the alpha channel of the rendered
texture will always be 255. You can however introduce an
alpha channel by appending a FilterBlueScreen() filter, it
will set the alpha to 0 (transparent) on all pixels that were
not rendered.
capsize:
2-tuple representing the size of the render area as [x,y] number of pixels.
Default value = largest rectangle with power of 2 dimensions that fits in the canvas
You may want to reduce the render area to increase performance. For example,
a render area of [256,128] is probably sufficient to implement a car inner mirror.
For best performance, use power of 2 dimensions and don't set any filter: this
allows direct transfer between the GPU frame buffer and texture memory
without going through the host.
alpha:
Boolean indicating if the render alpha channel should be copied to the texture.
Default value: False
Experimental, do not use.
whole:
Boolean indicating if the entire canvas should be used for the rendering.
Default value: False
Note: There is no reason to set this attribute to True: the rendering will
in any case be scaled down to the largest rectangle with power of 2
dimensions before transfering to the texture.
Attributes inherited from the ImageBase class:
image : image binary data, read-only
size : [x,y] size of the texture, read-only
scale : set to True for fast scale down in case the render area dimensions are not power of 2
flip : set to True for vertical flip.
filter: set a post-processing filter on the render.
Notes:
* Aspect Ratio
For consistent results in Blender and Blenderplayer, the same aspect ratio used
by Blender to draw the camera viewport (Scene(F10)->Format tab->Size X/Size Y)
is also used during the rendering. You can control the portion of the scene that
will be rendered by "looking through the camera": the zone inside the outer dotted
rectangle will be rendered to the texture.
In order to reproduce the scene without X/Y distortion, you must apply the texture
on an object or portion of object that has the same aspect ratio.
* Order of rendering
The rendereing is performed when you call the refresh() method of the parent
Texture object. This happens outside the normal frame rendering and will have no
effect on it.
However, if you want to use ImageViewport and ImageRender at the same time, be
sure to refresh the viewport texture before the render texture because the latter
will destroy the frame buffer that is used by the former to update the texture.
* Scene status
The meshes are not updated during the render to texture: the rendered texture
is one frame late to the rendered frame with regards to mesh deformation.
* Example:
cont = GameLogic.getCurrentController()
# object that receives the texture
obj = contr.getOwner()
scene = GameLogic.getCurrentScene()
# camera used for the render
tvcam = scene.getObjectList()['OBtvcam']
# assume obj has some faces UV assigned to tv.png
matID = VideoTexture.materialID(obj, 'IMtv.png')
GameLogic.tv = VideoTexture.Texture(obj, matID)
GameLogic.tv.source = VideoTexture.ImageRender(scene,tvcam)
GameLogic.tv.source.capsize = [256,256]
# to render the texture, just call GameLogic.tv.refresh(True) on each frame.
You can download a demo game (with a video file) here:
http://home.scarlet.be/~tsi46445/blender/VideoTextureDemo.zip
For those who have already downloaded the demo, you can just update the blend file:
http://home.scarlet.be/~tsi46445/blender/VideoTextureDemo.blend
Diffstat (limited to 'source/gameengine/VideoTexture/ImageViewport.cpp')
-rw-r--r-- | source/gameengine/VideoTexture/ImageViewport.cpp | 66 |
1 files changed, 50 insertions, 16 deletions
diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp index deb66ffb6ba..4c2c81e2208 100644 --- a/source/gameengine/VideoTexture/ImageViewport.cpp +++ b/source/gameengine/VideoTexture/ImageViewport.cpp @@ -34,12 +34,12 @@ http://www.gnu.org/copyleft/lesser.txt. // constructor -ImageViewport::ImageViewport (void) : m_texInit(false) +ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false) { // get viewport rectangle glGetIntegerv(GL_VIEWPORT, m_viewport); // create buffer for viewport image - m_viewportImage = new BYTE [3 * getViewportSize()[0] * getViewportSize()[1]]; + m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]]; // set attributes setWhole(false); } @@ -62,7 +62,7 @@ void ImageViewport::setWhole (bool whole) m_capSize[idx] = whole ? short(getViewportSize()[idx]) : calcSize(short(getViewportSize()[idx])); // position - m_position[idx] = whole ? 0 : (getViewportSize()[idx] - m_capSize[idx]) >> 1; + m_position[idx] = whole ? 0 : ((getViewportSize()[idx] - m_capSize[idx]) >> 1); } // init image init(m_capSize[0], m_capSize[1]); @@ -123,20 +123,31 @@ void ImageViewport::calcImage (unsigned int texId) && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip) { // just copy current viewport to texture - glBindTexture(GL_TEXTURE_2D, texId); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]); - // image is not available - m_avail = false; + glBindTexture(GL_TEXTURE_2D, texId); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]); + // image is not available + m_avail = false; } // otherwise copy viewport to buffer, if image is not available else if (!m_avail) { // get frame buffer data - glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB, - GL_UNSIGNED_BYTE, m_viewportImage); - // filter loaded data - FilterRGB24 filt; - filterImage(filt, m_viewportImage, m_capSize); + if (m_alpha) + { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA, + GL_UNSIGNED_BYTE, m_viewportImage); + // filter loaded data + FilterRGBA32 filt; + filterImage(filt, m_viewportImage, m_capSize); + } + else + { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB, + GL_UNSIGNED_BYTE, m_viewportImage); + // filter loaded data + FilterRGB24 filt; + filterImage(filt, m_viewportImage, m_capSize); + } } } @@ -151,14 +162,14 @@ inline ImageViewport * getImageViewport (PyImage * self) // get whole -static PyObject * ImageViewport_getWhole (PyImage * self, void * closure) +PyObject * ImageViewport_getWhole (PyImage * self, void * closure) { if (self->m_image != NULL && getImageViewport(self)->getWhole()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } // set whole -static int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure) +int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure) { // check parameter, report failure if (value == NULL || !PyBool_Check(value)) @@ -172,6 +183,28 @@ static int ImageViewport_setWhole (PyImage * self, PyObject * value, void * clos return 0; } +// get alpha +PyObject * ImageViewport_getAlpha (PyImage * self, void * closure) +{ + if (self->m_image != NULL && getImageViewport(self)->getAlpha()) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +// set whole +int ImageViewport_setAlpha (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 alpha + if (self->m_image != NULL) getImageViewport(self)->setAlpha(value == Py_True); + // success + return 0; +} + // get position static PyObject * ImageViewport_getPosition (PyImage * self, void * closure) @@ -202,14 +235,14 @@ static int ImageViewport_setPosition (PyImage * self, PyObject * value, void * c } // get capture size -static PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure) +PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure) { return Py_BuildValue("(ii)", getImageViewport(self)->getCaptureSize()[0], getImageViewport(self)->getCaptureSize()[1]); } // set capture size -static int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure) +int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure) { // check validity of parameter if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2 @@ -242,6 +275,7 @@ static PyGetSetDef imageViewportGetSets[] = {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to capture", NULL}, {(char*)"position", (getter)ImageViewport_getPosition, (setter)ImageViewport_setPosition, (char*)"upper left corner of captured area", NULL}, {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of viewport area being captured", NULL}, + {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, // attributes from ImageBase class {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, |