Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-12-14 20:32:24 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-12-14 20:32:24 +0300
commitec00764dd2349f723ba22b45515ec34ee81edcc3 (patch)
treecf506e71af7172ec63b89aa3d284fab27a2085e6 /source/gameengine/VideoTexture
parent131fa2e00c35ff78042a4f793891eaeb880d715c (diff)
parent8449f0d77640c466acbda7d6ceeb71bc48317b44 (diff)
2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17434:HEAD
Diffstat (limited to 'source/gameengine/VideoTexture')
-rw-r--r--source/gameengine/VideoTexture/Exception.cpp6
-rw-r--r--source/gameengine/VideoTexture/Exception.h6
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp595
-rw-r--r--source/gameengine/VideoTexture/ImageRender.h48
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.cpp66
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.h14
-rw-r--r--source/gameengine/VideoTexture/Texture.h6
-rw-r--r--source/gameengine/VideoTexture/blendVideoTex.cpp4
8 files changed, 651 insertions, 94 deletions
diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp
index 3f939de6bc2..8704d49f2a7 100644
--- a/source/gameengine/VideoTexture/Exception.cpp
+++ b/source/gameengine/VideoTexture/Exception.cpp
@@ -204,6 +204,12 @@ void registerAllExceptions(void)
ImageSizesNotMatchDesc.registerDesc();
SceneInvalidDesc.registerDesc();
CameraInvalidDesc.registerDesc();
+ ObserverInvalidDesc.registerDesc();
+ MirrorInvalidDesc.registerDesc();
+ MirrorSizeInvalidDesc.registerDesc();
+ MirrorNormalInvalidDesc.registerDesc();
+ MirrorHorizontalDesc.registerDesc();
+ MirrorTooSmallDesc.registerDesc();
SourceVideoEmptyDesc.registerDesc();
SourceVideoCreationDesc.registerDesc();
}
diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h
index 5345e87f199..1a3c25071b1 100644
--- a/source/gameengine/VideoTexture/Exception.h
+++ b/source/gameengine/VideoTexture/Exception.h
@@ -202,6 +202,12 @@ extern ExpDesc MaterialNotAvailDesc;
extern ExpDesc ImageSizesNotMatchDesc;
extern ExpDesc SceneInvalidDesc;
extern ExpDesc CameraInvalidDesc;
+extern ExpDesc ObserverInvalidDesc;
+extern ExpDesc MirrorInvalidDesc;
+extern ExpDesc MirrorSizeInvalidDesc;
+extern ExpDesc MirrorNormalInvalidDesc;
+extern ExpDesc MirrorHorizontalDesc;
+extern ExpDesc MirrorTooSmallDesc;
extern ExpDesc SourceVideoEmptyDesc;
extern ExpDesc SourceVideoCreationDesc;
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index a8f7871fa21..58697ed3cc7 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -24,96 +24,238 @@ http://www.gnu.org/copyleft/lesser.txt.
#include <PyObjectPlus.h>
#include <structmember.h>
+#include <float.h>
+#include <math.h>
-#include <KX_BlenderCanvas.h>
-#include <KX_BlenderRenderTools.h>
-#include <RAS_IRasterizer.h>
-#include <RAS_OpenGLRasterizer.h>
-#include <KX_WorldInfo.h>
-#include <KX_Light.h>
-#include "ImageRender.h"
+#include <BIF_gl.h>
+
+#include "KX_PythonInit.h"
+#include "DNA_scene_types.h"
+#include "RAS_CameraData.h"
+#include "RAS_MeshObject.h"
+#include "BLI_arithb.h"
+#include "ImageRender.h"
#include "ImageBase.h"
#include "BlendType.h"
#include "Exception.h"
+#include "Texture.h"
-ExceptionID SceneInvalid, CameraInvalid;
+ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid;
+ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall;
ExpDesc SceneInvalidDesc (SceneInvalid, "Scene object is invalid");
ExpDesc CameraInvalidDesc (CameraInvalid, "Camera object is invalid");
-
-#if 0 // not yet supported
+ExpDesc ObserverInvalidDesc (ObserverInvalid, "Observer object is invalid");
+ExpDesc MirrorInvalidDesc (MirrorInvalid, "Mirror object is invalid");
+ExpDesc MirrorSizeInvalidDesc (MirrorSizeInvalid, "Mirror has no vertex or no size");
+ExpDesc MirrorNormalInvalidDesc (MirrorNormalInvalid, "Cannot determine mirror plane");
+ExpDesc MirrorHorizontalDesc (MirrorHorizontal, "Mirror is horizontal in local space");
+ExpDesc MirrorTooSmallDesc (MirrorTooSmall, "Mirror is too small");
// constructor
-ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) : m_scene(scene),
-m_camera(camera)
+ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) :
+ ImageViewport(),
+ m_render(true),
+ m_scene(scene),
+ m_camera(camera),
+ m_owncamera(false),
+ m_observer(NULL),
+ m_mirror(NULL),
+ m_clip(100.f)
{
- // create screen area
- m_area.winrct.xmin = m_upLeft[0];
- m_area.winrct.ymin = m_upLeft[1];
- m_area.winx = m_size[0];
- m_area.winy = m_size[1];
- // create canvas
- m_canvas = new KX_BlenderCanvas(&m_area);
- // create render tools
- m_rendertools = new KX_BlenderRenderTools();
- // create rasterizer
- m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
- m_rasterizer->Init();
// initialize background colour
- setBackground(0, 0, 255);
- // refresh lights
- refreshLights();
+ setBackground(0, 0, 255, 255);
+ // retrieve rendering objects
+ m_engine = KX_GetActiveEngine();
+ m_rasterizer = m_engine->GetRasterizer();
+ m_canvas = m_engine->GetCanvas();
+ m_rendertools = m_engine->GetRenderTools();
}
// destructor
ImageRender::~ImageRender (void)
{
- // release allocated objects
- delete m_rasterizer;
- delete m_rendertools;
- delete m_canvas;
+ if (m_owncamera)
+ m_camera->Release();
}
// set background color
-void ImageRender::setBackground (unsigned char red, unsigned char green, unsigned char blue)
+void ImageRender::setBackground (int red, int green, int blue, int alpha)
{
- m_background[0] = red;
- m_background[1] = green;
- m_background[2] = blue;
- m_rasterizer->SetBackColor(m_background[0], m_background[1], m_background[2], 1.0);
+ m_background[0] = (red < 0) ? 0.f : (red > 255) ? 1.f : float(red)/255.f;
+ m_background[1] = (green < 0) ? 0.f : (green > 255) ? 1.f : float(green)/255.f;
+ m_background[2] = (blue < 0) ? 0.f : (blue > 255) ? 1.f : float(blue)/255.f;
+ m_background[3] = (alpha < 0) ? 0.f : (alpha > 255) ? 1.f : float(alpha)/255.f;
}
// capture image from viewport
void ImageRender::calcImage (unsigned int texId)
{
- // setup camera
- bool cameraPasive = !m_camera->GetViewport();
- // render scene
- Render();
- // reset camera
- if (cameraPasive) m_camera->EnableViewport(false);
+ if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture
+ m_camera->GetViewport() || // camera must be inactive
+ m_camera == m_scene->GetActiveCamera())
+ {
+ // no need to compute texture in non texture rendering
+ m_avail = false;
+ return;
+ }
+ // render the scene from the camera
+ Render();
// get image from viewport
ImageViewport::calcImage(texId);
+ // restore OpenGL state
+ m_canvas->EndFrame();
}
void ImageRender::Render()
{
- //
-}
+ RAS_FrameFrustum frustrum;
+
+ if (!m_render)
+ return;
+
+ if (m_mirror)
+ {
+ // mirror mode, compute camera frustrum, position and orientation
+ // convert mirror position and normal in world space
+ const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation();
+ const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition();
+ const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling();
+ MT_Point3 mirrorWorldPos =
+ mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos);
+ MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ;
+ // get observer world position
+ const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition();
+ // get plane D term = mirrorPos . normal
+ MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ);
+ // compute distance of observer to mirror = D - observerPos . normal
+ MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ);
+ // if distance < 0.01 => observer is on wrong side of mirror, don't render
+ if (observerDistance < 0.01f)
+ return;
+ // set camera world position = observerPos + normal * 2 * distance
+ MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ;
+ m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos);
+ // set camera orientation: z=normal, y=mirror_up in world space, x= y x z
+ MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY;
+ MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX;
+ MT_Matrix3x3 cameraWorldOri(
+ mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0],
+ mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1],
+ mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]);
+ m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri);
+ m_camera->GetSGNode()->UpdateWorldData(0.0);
+ // compute camera frustrum:
+ // get position of mirror relative to camera: offset = mirrorPos-cameraPos
+ MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos;
+ // convert to camera orientation
+ mirrorOffset = mirrorOffset * cameraWorldOri;
+ // scale mirror size to world scale:
+ // get closest local axis for mirror Y and X axis and scale height and width by local axis scale
+ MT_Scalar x, y;
+ x = fabs(m_mirrorY[0]);
+ y = fabs(m_mirrorY[1]);
+ float height = (x > y) ?
+ ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
+ ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
+ x = fabs(m_mirrorX[0]);
+ y = fabs(m_mirrorX[1]);
+ float width = (x > y) ?
+ ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
+ ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
+ width *= m_mirrorHalfWidth;
+ height *= m_mirrorHalfHeight;
+ // left = offsetx-width
+ // right = offsetx+width
+ // top = offsety+height
+ // bottom = offsety-height
+ // near = -offsetz
+ // far = near+100
+ frustrum.x1 = mirrorOffset[0]-width;
+ frustrum.x2 = mirrorOffset[0]+width;
+ frustrum.y1 = mirrorOffset[1]-height;
+ frustrum.y2 = mirrorOffset[1]+height;
+ frustrum.camnear = -mirrorOffset[2];
+ frustrum.camfar = -mirrorOffset[2]+m_clip;
+ }
+ const float ortho = 100.0;
+ const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
+
+ // The screen area that ImageViewport will copy is also the rendering zone
+ m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
+ m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
+ m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
+ m_rasterizer->BeginFrame(RAS_IRasterizer::KX_TEXTURED,m_engine->GetClockTime());
+ m_rendertools->BeginFrame(m_rasterizer);
+ m_engine->SetWorldSettings(m_scene->GetWorldInfo());
+ m_rendertools->SetAuxilaryClientInfo(m_scene);
+ m_rasterizer->DisplayFog();
+ // matrix calculation, don't apply any of the stereo mode
+ m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO);
+ if (m_mirror)
+ {
+ // frustrum was computed above
+ // get frustrum matrix and set projection matrix
+ MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
+ frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
+
+ m_camera->SetProjectionMatrix(projmat);
+ } else if (m_camera->hasValidProjectionMatrix())
+ {
+ m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix());
+ } else
+ {
+ float lens = m_camera->GetLens();
+ bool orthographic = !m_camera->GetCameraData()->m_perspective;
+ float nearfrust = m_camera->GetCameraNear();
+ float farfrust = m_camera->GetCameraFar();
+ float aspect_ratio = 1.0f;
+ Scene *blenderScene = m_scene->GetBlenderScene();
+
+ if (orthographic) {
+ lens *= ortho;
+ nearfrust = (nearfrust + 1.0)*ortho;
+ farfrust *= ortho;
+ }
+ // compute the aspect ratio from frame blender scene settings so that render to texture
+ // works the same in Blender and in Blender player
+ if (blenderScene->r.ysch != 0)
+ aspect_ratio = float(blenderScene->r.xsch) / float(blenderScene->r.ysch);
+
+ RAS_FramingManager::ComputeDefaultFrustum(
+ nearfrust,
+ farfrust,
+ lens,
+ aspect_ratio,
+ frustrum);
+
+ MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
+ frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
+
+ m_camera->SetProjectionMatrix(projmat);
+ }
-// refresh lights
-void ImageRender::refreshLights (void)
-{
- // clear lights list
- //m_rendertools->RemoveAllLights();
- // set lights
- //for (int idx = 0; idx < scene->GetLightList()->GetCount(); ++idx)
- // m_rendertools->AddLight(((KX_LightObject*)(scene->GetLightList()->GetValue(idx)))->GetLightData());
-}
+ MT_Transform camtrans(m_camera->GetWorldToCamera());
+ if (!m_camera->GetCameraData()->m_perspective)
+ camtrans.getOrigin()[2] *= ortho;
+ MT_Matrix4x4 viewmat(camtrans);
+
+ m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldPosition(),
+ m_camera->GetCameraLocation(), m_camera->GetCameraOrientation());
+ m_camera->SetModelviewMatrix(viewmat);
+ // restore the stereo mode now that the matrix is computed
+ m_rasterizer->SetStereoMode(stereomode);
+
+ // do not update the mesh, we don't want to do it more than once per frame
+ //m_scene->UpdateMeshTransformations();
+ m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
+
+ m_scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
+}
// cast Image pointer to ImageRender
@@ -174,26 +316,31 @@ static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds
// get background color
PyObject * getBackground (PyImage * self, void * closure)
{
- return Py_BuildValue("[BBB]", getImageRender(self)->getBackground()[0],
- getImageRender(self)->getBackground()[1], getImageRender(self)->getBackground()[2]);
+ return Py_BuildValue("[BBBB]",
+ getImageRender(self)->getBackground(0),
+ getImageRender(self)->getBackground(1),
+ getImageRender(self)->getBackground(2),
+ getImageRender(self)->getBackground(3));
}
// set color
static int setBackground (PyImage * self, PyObject * value, void * closure)
{
// check validity of parameter
- if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 3
+ if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 4
|| !PyInt_Check(PySequence_Fast_GET_ITEM(value, 0))
|| !PyInt_Check(PySequence_Fast_GET_ITEM(value, 1))
- || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 2)))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 2))
+ || !PyInt_Check(PySequence_Fast_GET_ITEM(value, 3)))
{
- PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 3 ints");
+ PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 4 integer between 0 and 255");
return -1;
}
// set background color
getImageRender(self)->setBackground((unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
(unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 1))),
- (unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 2))));
+ (unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 2))),
+ (unsigned char)(PyInt_AsLong(PySequence_Fast_GET_ITEM(value, 3))));
// success
return 0;
}
@@ -209,6 +356,10 @@ static PyMethodDef imageRenderMethods[] =
static PyGetSetDef imageRenderGetSets[] =
{
{(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL},
+ // attribute from ImageViewport
+ {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL},
+ {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL},
+ {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", 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},
@@ -263,5 +414,329 @@ PyTypeObject ImageRenderType =
Image_allocNew, /* tp_new */
};
+// object initialization
+static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ // parameters - scene object
+ PyObject * scene;
+ // reference object for mirror
+ PyObject * observer;
+ // object holding the mirror
+ PyObject * mirror;
+ // material of the mirror
+ short materialID = 0;
+ // parameter keywords
+ static char *kwlist[] = {"scene", "observer", "mirror", "material", NULL};
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h", kwlist, &scene, &observer, &mirror, &materialID))
+ return -1;
+ try
+ {
+ // get scene pointer
+ KX_Scene * scenePtr (NULL);
+ if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type))
+ scenePtr = static_cast<KX_Scene*>(scene);
+ else
+ THRWEXCP(SceneInvalid, S_OK);
+
+ // get observer pointer
+ KX_GameObject * observerPtr (NULL);
+ if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type))
+ observerPtr = static_cast<KX_GameObject*>(observer);
+ else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type))
+ observerPtr = static_cast<KX_Camera*>(observer);
+ else
+ THRWEXCP(ObserverInvalid, S_OK);
+
+ // get mirror pointer
+ KX_GameObject * mirrorPtr (NULL);
+ if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type))
+ mirrorPtr = static_cast<KX_GameObject*>(mirror);
+ else
+ THRWEXCP(MirrorInvalid, S_OK);
+
+ // locate the material in the mirror
+ RAS_IPolyMaterial * material = getMaterial(mirror, materialID);
+ if (material == NULL)
+ THRWEXCP(MaterialNotAvail, S_OK);
+
+ // get pointer to image structure
+ PyImage * self = reinterpret_cast<PyImage*>(pySelf);
+
+ // create source object
+ if (self->m_image != NULL)
+ {
+ delete self->m_image;
+ self->m_image = NULL;
+ }
+ self->m_image = new ImageRender(scenePtr, observerPtr, mirrorPtr, material);
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+// get background color
+PyObject * getClip (PyImage * self, void * closure)
+{
+ return PyFloat_FromDouble(getImageRender(self)->getClip());
+}
+
+// set clip
+static int setClip (PyImage * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ double clip;
+ if (value == NULL || !PyFloat_Check(value) || (clip = PyFloat_AsDouble(value)) < 0.01 || clip > 5000.0)
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be an float between 0.01 and 5000");
+ return -1;
+ }
+ // set background color
+ getImageRender(self)->setClip(float(clip));
+ // success
+ return 0;
+}
+
+// attributes structure
+static PyGetSetDef imageMirrorGetSets[] =
+{
+ {(char*)"clip", (getter)getClip, (setter)setClip, (char*)"clipping distance", NULL},
+ // attribute from ImageRender
+ {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL},
+ // attribute from ImageViewport
+ {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL},
+ {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL},
+ {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", 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},
+ {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
+ {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+ {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
+ {NULL}
+};
+
+
+// constructor
+ImageRender::ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat) :
+ ImageViewport(),
+ m_render(false),
+ m_scene(scene),
+ m_observer(observer),
+ m_mirror(mirror),
+ m_clip(100.f)
+{
+ // this constructor is used for automatic planar mirror
+ // create a camera, take all data by default, in any case we will recompute the frustrum on each frame
+ RAS_CameraData camdata;
+ vector<RAS_TexVert*> mirrorVerts;
+ vector<RAS_TexVert*>::iterator it;
+ float mirrorArea = 0.f;
+ float mirrorNormal[3] = {0.f, 0.f, 0.f};
+ float mirrorUp[3];
+ float dist, vec[3], axis[3];
+ float zaxis[3] = {0.f, 0.f, 1.f};
+ float yaxis[3] = {0.f, 1.f, 0.f};
+ float mirrorMat[3][3];
+ float left, right, top, bottom, back;
+
+ m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata);
+ m_camera->SetName("__mirror__cam__");
+ // don't add the camera to the scene object list, it doesn't need to be accessible
+ m_owncamera = true;
+ // retrieve rendering objects
+ m_engine = KX_GetActiveEngine();
+ m_rasterizer = m_engine->GetRasterizer();
+ m_canvas = m_engine->GetCanvas();
+ m_rendertools = m_engine->GetRenderTools();
+ // locate the vertex assigned to mat and do following calculation in mesh coordinates
+ for (int meshIndex = 0; meshIndex < mirror->GetMeshCount(); meshIndex++)
+ {
+ RAS_MeshObject* mesh = mirror->GetMesh(meshIndex);
+ int numPolygons = mesh->NumPolygons();
+ for (int polygonIndex=0; polygonIndex < numPolygons; polygonIndex++)
+ {
+ RAS_Polygon* polygon = mesh->GetPolygon(polygonIndex);
+ if (polygon->GetMaterial()->GetPolyMaterial() == mat)
+ {
+ RAS_TexVert *v1, *v2, *v3, *v4;
+ float normal[3];
+ float area;
+ // this polygon is part of the mirror,
+ v1 = polygon->GetVertex(0);
+ v2 = polygon->GetVertex(1);
+ v3 = polygon->GetVertex(2);
+ mirrorVerts.push_back(v1);
+ mirrorVerts.push_back(v2);
+ mirrorVerts.push_back(v3);
+ if (polygon->VertexCount() == 4)
+ {
+ v4 = polygon->GetVertex(3);
+ mirrorVerts.push_back(v4);
+ area = CalcNormFloat4((float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ(), normal);
+ } else
+ {
+ area = CalcNormFloat((float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), normal);
+ }
+ area = fabs(area);
+ mirrorArea += area;
+ VecMulf(normal, area);
+ VecAddf(mirrorNormal, mirrorNormal, normal);
+ }
+ }
+ }
+ if (mirrorVerts.size() == 0 || mirrorArea < FLT_EPSILON)
+ {
+ // no vertex or zero size mirror
+ THRWEXCP(MirrorSizeInvalid, S_OK);
+ }
+ // compute average normal of mirror faces
+ VecMulf(mirrorNormal, 1.0f/mirrorArea);
+ if (Normalize(mirrorNormal) == 0.f)
+ {
+ // no normal
+ THRWEXCP(MirrorNormalInvalid, S_OK);
+ }
+ // the mirror plane has an equation of the type ax+by+cz = d where (a,b,c) is the normal vector
+ // if the mirror is more vertical then horizontal, the Z axis is the up direction.
+ // otherwise the Y axis is the up direction.
+ // If the mirror is not perfectly vertical(horizontal), the Z(Y) axis projection on the mirror
+ // plan by the normal will be the up direction.
+ if (fabs(mirrorNormal[2]) > fabs(mirrorNormal[1]) &&
+ fabs(mirrorNormal[2]) > fabs(mirrorNormal[0]))
+ {
+ // the mirror is more horizontal than vertical
+ VecCopyf(axis, yaxis);
+ }
+ else
+ {
+ // the mirror is more vertical than horizontal
+ VecCopyf(axis, zaxis);
+ }
+ dist = Inpf(mirrorNormal, axis);
+ if (fabs(dist) < FLT_EPSILON)
+ {
+ // the mirror is already fully aligned with up axis
+ VecCopyf(mirrorUp, axis);
+ }
+ else
+ {
+ // projection of axis to mirror plane through normal
+ VecCopyf(vec, mirrorNormal);
+ VecMulf(vec, dist);
+ VecSubf(mirrorUp, axis, vec);
+ if (Normalize(mirrorUp) == 0.f)
+ {
+ // should not happen
+ THRWEXCP(MirrorHorizontal, S_OK);
+ return;
+ }
+ }
+ // compute rotation matrix between local coord and mirror coord
+ // to match camera orientation, we select mirror z = -normal, y = up, x = y x z
+ VecCopyf(mirrorMat[2], mirrorNormal);
+ VecMulf(mirrorMat[2], -1.0f);
+ VecCopyf(mirrorMat[1], mirrorUp);
+ Crossf(mirrorMat[0], mirrorMat[1], mirrorMat[2]);
+ // transpose to make it a orientation matrix from local space to mirror space
+ Mat3Transp(mirrorMat);
+ // transform all vertex to plane coordinates and determine mirror position
+ left = FLT_MAX;
+ right = -FLT_MAX;
+ bottom = FLT_MAX;
+ top = -FLT_MAX;
+ back = -FLT_MAX; // most backward vertex (=highest Z coord in mirror space)
+ for (it = mirrorVerts.begin(); it != mirrorVerts.end(); it++)
+ {
+ VecCopyf(vec, (float*)(*it)->getXYZ());
+ Mat3MulVecfl(mirrorMat, vec);
+ if (vec[0] < left)
+ left = vec[0];
+ if (vec[0] > right)
+ right = vec[0];
+ if (vec[1] < bottom)
+ bottom = vec[1];
+ if (vec[1] > top)
+ top = vec[1];
+ if (vec[2] > back)
+ back = vec[2];
+ }
+ // now store this information in the object for later rendering
+ m_mirrorHalfWidth = (right-left)*0.5f;
+ m_mirrorHalfHeight = (top-bottom)*0.5f;
+ if (m_mirrorHalfWidth < 0.01f || m_mirrorHalfHeight < 0.01f)
+ {
+ // mirror too small
+ THRWEXCP(MirrorTooSmall, S_OK);
+ }
+ // mirror position in mirror coord
+ vec[0] = (left+right)*0.5f;
+ vec[1] = (top+bottom)*0.5f;
+ vec[2] = back;
+ // convert it in local space: transpose again the matrix to get back to mirror to local transform
+ Mat3Transp(mirrorMat);
+ Mat3MulVecfl(mirrorMat, vec);
+ // mirror position in local space
+ m_mirrorPos.setValue(vec[0], vec[1], vec[2]);
+ // mirror normal vector (pointed towards the back of the mirror) in local space
+ m_mirrorZ.setValue(-mirrorNormal[0], -mirrorNormal[1], -mirrorNormal[2]);
+ m_mirrorY.setValue(mirrorUp[0], mirrorUp[1], mirrorUp[2]);
+ m_mirrorX = m_mirrorY.cross(m_mirrorZ);
+ m_render = true;
+
+ setBackground(0, 0, 255, 255);
+}
+
+
+
+
+// define python type
+PyTypeObject ImageMirrorType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.ImageMirror", /*tp_name*/
+ sizeof(PyImage), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Image_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "Image source from mirror", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ imageRenderMethods, /* tp_methods */
+ 0, /* tp_members */
+ imageMirrorGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ImageMirror_init, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
-#endif // #if 0
diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h
index 66255f04d2c..c94e2f1e718 100644
--- a/source/gameengine/VideoTexture/ImageRender.h
+++ b/source/gameengine/VideoTexture/ImageRender.h
@@ -42,42 +42,56 @@ class ImageRender : public ImageViewport
public:
/// constructor
ImageRender (KX_Scene * scene, KX_Camera * camera);
+ ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat);
/// destructor
virtual ~ImageRender (void);
/// get background color
- unsigned char * getBackground (void) { return m_background; }
+ int getBackground (int idx) { return (idx < 0 || idx > 3) ? 0 : int(m_background[idx]*255.f); }
/// set background color
- void setBackground (unsigned char red, unsigned char green, unsigned char blue);
+ void setBackground (int red, int green, int blue, int alpha);
+
+ /// clipping distance
+ float getClip (void) { return m_clip; }
+ /// set whole buffer use
+ void setClip (float clip) { m_clip = clip; }
protected:
+ /// true if ready to render
+ bool m_render;
/// rendered scene
KX_Scene * m_scene;
/// camera for render
KX_Camera * m_camera;
-
- /// screen area for rendering
- ScrArea m_area;
- /// rendering device
- RAS_ICanvas * m_canvas;
- /// rasterizer
- RAS_IRasterizer * m_rasterizer;
- /// render tools
- RAS_IRenderTools * m_rendertools;
+ /// do we own the camera?
+ bool m_owncamera;
+ /// for mirror operation
+ KX_GameObject * m_observer;
+ KX_GameObject * m_mirror;
+ float m_clip; // clipping distance
+ float m_mirrorHalfWidth; // mirror width in mirror space
+ float m_mirrorHalfHeight; // mirror height in mirror space
+ MT_Point3 m_mirrorPos; // mirror center position in local space
+ MT_Vector3 m_mirrorZ; // mirror Z axis in local space
+ MT_Vector3 m_mirrorY; // mirror Y axis in local space
+ MT_Vector3 m_mirrorX; // mirror X axis in local space
+ /// canvas
+ RAS_ICanvas* m_canvas;
+ /// rasterizer
+ RAS_IRasterizer* m_rasterizer;
+ /// render tools
+ RAS_IRenderTools* m_rendertools;
+ /// engine
+ KX_KetsjiEngine* m_engine;
/// background colour
- unsigned char m_background[3];
+ float m_background[4];
/// render 3d scene to image
virtual void calcImage (unsigned int texId);
- /// refresh lights
- void refreshLights (void);
- /// methods from KX_KetsjiEngine
- bool BeginFrame();
- void EndFrame();
void Render();
void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam);
void RenderFrame(KX_Scene* scene, KX_Camera* cam);
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},
diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h
index 4265906b8f5..0449249cf95 100644
--- a/source/gameengine/VideoTexture/ImageViewport.h
+++ b/source/gameengine/VideoTexture/ImageViewport.h
@@ -43,6 +43,12 @@ public:
bool getWhole (void) { return m_whole; }
/// set whole buffer use
void setWhole (bool whole);
+
+ /// is alpha channel used
+ bool getAlpha (void) { return m_alpha; }
+ /// set whole buffer use
+ void setAlpha (bool alpha) { m_alpha = alpha; }
+
/// get capture size in viewport
short * getCaptureSize (void) { return m_capSize; }
/// set capture size in viewport
@@ -61,6 +67,8 @@ protected:
short m_capSize[2];
/// use whole viewport
bool m_whole;
+ /// use alpha channel
+ bool m_alpha;
/// position of capture rectangle in viewport
GLint m_position[2];
@@ -79,6 +87,12 @@ protected:
GLint * getViewportSize (void) { return m_viewport + 2; }
};
+PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure);
+int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure);
+PyObject * ImageViewport_getWhole (PyImage * self, void * closure);
+int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure);
+PyObject * ImageViewport_getAlpha (PyImage * self, void * closure);
+int ImageViewport_setAlpha (PyImage * self, PyObject * value, void * closure);
#endif
diff --git a/source/gameengine/VideoTexture/Texture.h b/source/gameengine/VideoTexture/Texture.h
index 3c371e51537..1bbef8f0f9e 100644
--- a/source/gameengine/VideoTexture/Texture.h
+++ b/source/gameengine/VideoTexture/Texture.h
@@ -32,6 +32,7 @@ http://www.gnu.org/copyleft/lesser.txt.
#include "ImageBase.h"
#include "BlendType.h"
+#include "Exception.h"
// type Texture declaration
@@ -82,5 +83,10 @@ RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID);
// get material ID
short getMaterialID (PyObject * obj, char * name);
+// Exceptions
+extern ExceptionID MaterialNotAvail;
+
+// object type
+extern BlendType<KX_GameObject> gameObjectType;
#endif
diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp
index b38882f8164..ec066811a52 100644
--- a/source/gameengine/VideoTexture/blendVideoTex.cpp
+++ b/source/gameengine/VideoTexture/blendVideoTex.cpp
@@ -132,6 +132,7 @@ extern PyTypeObject FilterBGR24Type;
extern PyTypeObject ImageBuffType;
extern PyTypeObject ImageMixType;
extern PyTypeObject ImageRenderType;
+extern PyTypeObject ImageMirrorType;
extern PyTypeObject ImageViewportType;
extern PyTypeObject ImageViewportType;
@@ -144,7 +145,8 @@ static void registerAllTypes(void)
#endif
pyImageTypes.add(&ImageBuffType, "ImageBuff");
pyImageTypes.add(&ImageMixType, "ImageMix");
- //pyImageTypes.add(&ImageRenderType, "ImageRender");
+ pyImageTypes.add(&ImageRenderType, "ImageRender");
+ pyImageTypes.add(&ImageMirrorType, "ImageMirror");
pyImageTypes.add(&ImageViewportType, "ImageViewport");
pyFilterTypes.add(&FilterBlueScreenType, "FilterBlueScreen");