Blender  V2.59
ImageRender.cpp
Go to the documentation of this file.
00001 
00004 /* $Id: ImageRender.cpp 35176 2011-02-25 13:39:34Z jesterking $
00005 -----------------------------------------------------------------------------
00006 This source file is part of VideoTexture library
00007 
00008 Copyright (c) 2007 The Zdeno Ash Miklas
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 
00026 // implementation
00027 
00028 #include <PyObjectPlus.h>
00029 #include <structmember.h>
00030 #include <float.h>
00031 #include <math.h>
00032 
00033 
00034 #include "GL/glew.h"
00035 
00036 #include "KX_PythonInit.h"
00037 #include "DNA_scene_types.h"
00038 #include "RAS_CameraData.h"
00039 #include "RAS_MeshObject.h"
00040 #include "BLI_math.h"
00041 
00042 #include "ImageRender.h"
00043 #include "ImageBase.h"
00044 #include "BlendType.h"
00045 #include "Exception.h"
00046 #include "Texture.h"
00047 
00048 ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid;
00049 ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall;
00050 ExpDesc SceneInvalidDesc (SceneInvalid, "Scene object is invalid");
00051 ExpDesc CameraInvalidDesc (CameraInvalid, "Camera object is invalid");
00052 ExpDesc ObserverInvalidDesc (ObserverInvalid, "Observer object is invalid");
00053 ExpDesc MirrorInvalidDesc (MirrorInvalid, "Mirror object is invalid");
00054 ExpDesc MirrorSizeInvalidDesc (MirrorSizeInvalid, "Mirror has no vertex or no size");
00055 ExpDesc MirrorNormalInvalidDesc (MirrorNormalInvalid, "Cannot determine mirror plane");
00056 ExpDesc MirrorHorizontalDesc (MirrorHorizontal, "Mirror is horizontal in local space");
00057 ExpDesc MirrorTooSmallDesc (MirrorTooSmall, "Mirror is too small");
00058 
00059 // constructor
00060 ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) : 
00061     ImageViewport(),
00062     m_render(true),
00063     m_scene(scene),
00064     m_camera(camera),
00065     m_owncamera(false),
00066     m_observer(NULL),
00067     m_mirror(NULL),
00068         m_clip(100.f)
00069 {
00070         // initialize background color
00071         setBackground(0, 0, 255, 255);
00072     // retrieve rendering objects
00073     m_engine = KX_GetActiveEngine();
00074     m_rasterizer = m_engine->GetRasterizer();
00075     m_canvas = m_engine->GetCanvas();
00076     m_rendertools = m_engine->GetRenderTools();
00077 }
00078 
00079 // destructor
00080 ImageRender::~ImageRender (void)
00081 {
00082     if (m_owncamera)
00083         m_camera->Release();
00084 }
00085 
00086 
00087 // set background color
00088 void ImageRender::setBackground (int red, int green, int blue, int alpha)
00089 {
00090     m_background[0] = (red < 0) ? 0.f : (red > 255) ? 1.f : float(red)/255.f;
00091         m_background[1] = (green < 0) ? 0.f : (green > 255) ? 1.f : float(green)/255.f;
00092         m_background[2] = (blue < 0) ? 0.f : (blue > 255) ? 1.f : float(blue)/255.f;
00093         m_background[3] = (alpha < 0) ? 0.f : (alpha > 255) ? 1.f : float(alpha)/255.f;
00094 }
00095 
00096 
00097 // capture image from viewport
00098 void ImageRender::calcImage (unsigned int texId, double ts)
00099 {
00100     if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED ||   // no need for texture
00101         m_camera->GetViewport() ||        // camera must be inactive
00102         m_camera == m_scene->GetActiveCamera())
00103     {
00104         // no need to compute texture in non texture rendering
00105         m_avail = false;
00106         return;
00107     }
00108     // render the scene from the camera
00109     Render();
00110         // get image from viewport
00111         ImageViewport::calcImage(texId, ts);
00112     // restore OpenGL state
00113     m_canvas->EndFrame();
00114 }
00115 
00116 void ImageRender::Render()
00117 {
00118         RAS_FrameFrustum frustrum;
00119 
00120     if (!m_render)
00121         return;
00122 
00123     if (m_mirror)
00124     {
00125         // mirror mode, compute camera frustrum, position and orientation
00126         // convert mirror position and normal in world space
00127         const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation();
00128         const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition();
00129         const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling();
00130         MT_Point3 mirrorWorldPos = 
00131             mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos);
00132         MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ;
00133         // get observer world position
00134         const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition();
00135         // get plane D term = mirrorPos . normal
00136         MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ);
00137         // compute distance of observer to mirror = D - observerPos . normal
00138         MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ);
00139         // if distance < 0.01 => observer is on wrong side of mirror, don't render
00140         if (observerDistance < 0.01f)
00141             return;
00142         // set camera world position = observerPos + normal * 2 * distance
00143         MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ;
00144         m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos);
00145         // set camera orientation: z=normal, y=mirror_up in world space, x= y x z
00146         MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY;
00147         MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX;
00148         MT_Matrix3x3 cameraWorldOri(
00149             mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0],
00150             mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1], 
00151             mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]);
00152         m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri);
00153         m_camera->GetSGNode()->UpdateWorldData(0.0);
00154         // compute camera frustrum:
00155         //   get position of mirror relative to camera: offset = mirrorPos-cameraPos
00156         MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos;
00157         //   convert to camera orientation
00158         mirrorOffset = mirrorOffset * cameraWorldOri;
00159         //   scale mirror size to world scale: 
00160         //     get closest local axis for mirror Y and X axis and scale height and width by local axis scale
00161         MT_Scalar x, y;
00162         x = fabs(m_mirrorY[0]);
00163         y = fabs(m_mirrorY[1]);
00164         float height = (x > y) ? 
00165             ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
00166             ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
00167         x = fabs(m_mirrorX[0]);
00168         y = fabs(m_mirrorX[1]);
00169         float width = (x > y) ? 
00170             ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
00171             ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
00172         width *= m_mirrorHalfWidth;
00173         height *= m_mirrorHalfHeight;
00174         //   left = offsetx-width
00175         //   right = offsetx+width
00176         //   top = offsety+height
00177         //   bottom = offsety-height
00178         //   near = -offsetz
00179         //   far = near+100
00180         frustrum.x1 = mirrorOffset[0]-width;
00181         frustrum.x2 = mirrorOffset[0]+width;
00182         frustrum.y1 = mirrorOffset[1]-height;
00183         frustrum.y2 = mirrorOffset[1]+height;
00184         frustrum.camnear = -mirrorOffset[2];
00185         frustrum.camfar = -mirrorOffset[2]+m_clip;
00186     }
00187         // Store settings to be restored later
00188     const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
00189         RAS_Rect area = m_canvas->GetWindowArea();
00190 
00191     // The screen area that ImageViewport will copy is also the rendering zone
00192     m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
00193     m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
00194     m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
00195     m_rasterizer->BeginFrame(RAS_IRasterizer::KX_TEXTURED,m_engine->GetClockTime());
00196     m_rendertools->BeginFrame(m_rasterizer);
00197     m_engine->SetWorldSettings(m_scene->GetWorldInfo());
00198     m_rendertools->SetAuxilaryClientInfo(m_scene);
00199     m_rasterizer->DisplayFog();
00200     // matrix calculation, don't apply any of the stereo mode
00201     m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO);
00202     if (m_mirror)
00203     {
00204         // frustrum was computed above
00205         // get frustrum matrix and set projection matrix
00206                 MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
00207                         frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
00208 
00209                 m_camera->SetProjectionMatrix(projmat);
00210     } else if (m_camera->hasValidProjectionMatrix())
00211         {
00212                 m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix());
00213     } else 
00214     {
00215                 float lens = m_camera->GetLens();
00216                 bool orthographic = !m_camera->GetCameraData()->m_perspective;
00217                 float nearfrust = m_camera->GetCameraNear();
00218                 float farfrust = m_camera->GetCameraFar();
00219         float aspect_ratio = 1.0f;
00220         Scene *blenderScene = m_scene->GetBlenderScene();
00221                 MT_Matrix4x4 projmat;
00222 
00223                 // compute the aspect ratio from frame blender scene settings so that render to texture
00224         // works the same in Blender and in Blender player
00225         if (blenderScene->r.ysch != 0)
00226             aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp);
00227 
00228                 if (orthographic) {
00229 
00230                         RAS_FramingManager::ComputeDefaultOrtho(
00231                                 nearfrust,
00232                                 farfrust,
00233                                 m_camera->GetScale(),
00234                                 aspect_ratio,
00235                                 frustrum
00236                         );
00237 
00238                         projmat = m_rasterizer->GetOrthoMatrix(
00239                                 frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
00240                 } else 
00241                 {
00242                         RAS_FramingManager::ComputeDefaultFrustum(
00243                                 nearfrust,
00244                                 farfrust,
00245                                 lens,
00246                                 aspect_ratio,
00247                                 frustrum);
00248                         
00249                         projmat = m_rasterizer->GetFrustumMatrix(
00250                                 frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
00251                 }
00252                 m_camera->SetProjectionMatrix(projmat);
00253         }
00254 
00255         MT_Transform camtrans(m_camera->GetWorldToCamera());
00256         MT_Matrix4x4 viewmat(camtrans);
00257         
00258         m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective);
00259         m_camera->SetModelviewMatrix(viewmat);
00260     // restore the stereo mode now that the matrix is computed
00261     m_rasterizer->SetStereoMode(stereomode);
00262 
00263         m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
00264 
00265         m_scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
00266 
00267         // restore the canvas area now that the render is completed
00268         m_canvas->GetWindowArea() = area;
00269 }
00270 
00271 
00272 // cast Image pointer to ImageRender
00273 inline ImageRender * getImageRender (PyImage * self)
00274 { return static_cast<ImageRender*>(self->m_image); }
00275 
00276 
00277 // python methods
00278 
00279 // Blender Scene type
00280 BlendType<KX_Scene> sceneType ("KX_Scene");
00281 // Blender Camera type
00282 BlendType<KX_Camera> cameraType ("KX_Camera");
00283 
00284 
00285 // object initialization
00286 static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
00287 {
00288         // parameters - scene object
00289         PyObject * scene;
00290         // camera object
00291         PyObject * camera;
00292         // parameter keywords
00293         static const char *kwlist[] = {"sceneObj", "cameraObj", NULL};
00294         // get parameters
00295         if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO",
00296                 const_cast<char**>(kwlist), &scene, &camera))
00297                 return -1;
00298         try
00299         {
00300                 // get scene pointer
00301                 KX_Scene * scenePtr (NULL);
00302                 if (scene != NULL) scenePtr = sceneType.checkType(scene);
00303                 // throw exception if scene is not available
00304                 if (scenePtr == NULL) THRWEXCP(SceneInvalid, S_OK);
00305 
00306                 // get camera pointer
00307                 KX_Camera * cameraPtr (NULL);
00308                 if (camera != NULL) cameraPtr = cameraType.checkType(camera);
00309                 // throw exception if camera is not available
00310                 if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK);
00311 
00312                 // get pointer to image structure
00313                 PyImage * self = reinterpret_cast<PyImage*>(pySelf);
00314                 // create source object
00315                 if (self->m_image != NULL) delete self->m_image;
00316                 self->m_image = new ImageRender(scenePtr, cameraPtr);
00317         }
00318         catch (Exception & exp)
00319         {
00320                 exp.report();
00321                 return -1;
00322         }
00323         // initialization succeded
00324         return 0;
00325 }
00326 
00327 
00328 // get background color
00329 PyObject * getBackground (PyImage * self, void * closure)
00330 {
00331         return Py_BuildValue("[BBBB]", 
00332         getImageRender(self)->getBackground(0),
00333                 getImageRender(self)->getBackground(1), 
00334         getImageRender(self)->getBackground(2),
00335         getImageRender(self)->getBackground(3));
00336 }
00337 
00338 // set color
00339 static int setBackground (PyImage * self, PyObject * value, void * closure)
00340 {
00341         // check validity of parameter
00342         if (value == NULL || !PySequence_Check(value) || PySequence_Size(value) != 4
00343                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0))
00344                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1))
00345                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 2))
00346                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 3)))
00347         {
00348                 PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 4 integer between 0 and 255");
00349                 return -1;
00350         }
00351         // set background color
00352         getImageRender(self)->setBackground((unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))),
00353                 (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1))),
00354                 (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2))),
00355         (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 3))));
00356         // success
00357         return 0;
00358 }
00359 
00360 
00361 // methods structure
00362 static PyMethodDef imageRenderMethods[] =
00363 { // methods from ImageBase class
00364         {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
00365         {NULL}
00366 };
00367 // attributes structure
00368 static PyGetSetDef imageRenderGetSets[] =
00369 { 
00370         {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL},
00371     // attribute from ImageViewport
00372         {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL},
00373         {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL},
00374         {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL},
00375         // attributes from ImageBase class
00376         {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
00377         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
00378         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
00379         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
00380         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
00381         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
00382         {NULL}
00383 };
00384 
00385 
00386 // define python type
00387 PyTypeObject ImageRenderType =
00388 { 
00389         PyVarObject_HEAD_INIT(NULL, 0)
00390         "VideoTexture.ImageRender",   /*tp_name*/
00391         sizeof(PyImage),          /*tp_basicsize*/
00392         0,                         /*tp_itemsize*/
00393         (destructor)Image_dealloc, /*tp_dealloc*/
00394         0,                         /*tp_print*/
00395         0,                         /*tp_getattr*/
00396         0,                         /*tp_setattr*/
00397         0,                         /*tp_compare*/
00398         0,                         /*tp_repr*/
00399         0,                         /*tp_as_number*/
00400         0,                         /*tp_as_sequence*/
00401         0,                         /*tp_as_mapping*/
00402         0,                         /*tp_hash */
00403         0,                         /*tp_call*/
00404         0,                         /*tp_str*/
00405         0,                         /*tp_getattro*/
00406         0,                         /*tp_setattro*/
00407         &imageBufferProcs,         /*tp_as_buffer*/
00408         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
00409         "Image source from render",       /* tp_doc */
00410         0,                             /* tp_traverse */
00411         0,                             /* tp_clear */
00412         0,                             /* tp_richcompare */
00413         0,                             /* tp_weaklistoffset */
00414         0,                             /* tp_iter */
00415         0,                             /* tp_iternext */
00416         imageRenderMethods,    /* tp_methods */
00417         0,                   /* tp_members */
00418         imageRenderGetSets,          /* tp_getset */
00419         0,                         /* tp_base */
00420         0,                         /* tp_dict */
00421         0,                         /* tp_descr_get */
00422         0,                         /* tp_descr_set */
00423         0,                         /* tp_dictoffset */
00424         (initproc)ImageRender_init,     /* tp_init */
00425         0,                         /* tp_alloc */
00426         Image_allocNew,           /* tp_new */
00427 };
00428 
00429 // object initialization
00430 static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
00431 {
00432         // parameters - scene object
00433         PyObject * scene;
00434         // reference object for mirror
00435         PyObject * observer;
00436     // object holding the mirror
00437     PyObject * mirror;
00438     // material of the mirror
00439     short materialID = 0;
00440         // parameter keywords
00441         static const char *kwlist[] = {"scene", "observer", "mirror", "material", NULL};
00442         // get parameters
00443         if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h",
00444                 const_cast<char**>(kwlist), &scene, &observer, &mirror, &materialID))
00445                 return -1;
00446         try
00447         {
00448                 // get scene pointer
00449                 KX_Scene * scenePtr (NULL);
00450         if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type))
00451             scenePtr = static_cast<KX_Scene*>BGE_PROXY_REF(scene);
00452                 else
00453             THRWEXCP(SceneInvalid, S_OK);
00454                 
00455                 if(scenePtr==NULL) /* incase the python proxy reference is invalid */
00456                         THRWEXCP(SceneInvalid, S_OK);
00457                 
00458                 // get observer pointer
00459                 KX_GameObject * observerPtr (NULL);
00460                 if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type))
00461             observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer);
00462         else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type))
00463             observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer);
00464                 else
00465             THRWEXCP(ObserverInvalid, S_OK);
00466                 
00467                 if(observerPtr==NULL) /* incase the python proxy reference is invalid */
00468                         THRWEXCP(ObserverInvalid, S_OK);
00469 
00470                 // get mirror pointer
00471                 KX_GameObject * mirrorPtr (NULL);
00472                 if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type))
00473             mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror);
00474                 else
00475             THRWEXCP(MirrorInvalid, S_OK);
00476                 
00477                 if(mirrorPtr==NULL) /* incase the python proxy reference is invalid */
00478                         THRWEXCP(MirrorInvalid, S_OK);
00479 
00480         // locate the material in the mirror
00481                 RAS_IPolyMaterial * material = getMaterial(mirror, materialID);
00482                 if (material == NULL)
00483             THRWEXCP(MaterialNotAvail, S_OK);
00484 
00485                 // get pointer to image structure
00486                 PyImage * self = reinterpret_cast<PyImage*>(pySelf);
00487 
00488                 // create source object
00489                 if (self->m_image != NULL) 
00490         {
00491             delete self->m_image;
00492             self->m_image = NULL;
00493         }
00494                 self->m_image = new ImageRender(scenePtr, observerPtr, mirrorPtr, material);
00495         }
00496         catch (Exception & exp)
00497         {
00498                 exp.report();
00499                 return -1;
00500         }
00501         // initialization succeded
00502         return 0;
00503 }
00504 
00505 // get background color
00506 PyObject * getClip (PyImage * self, void * closure)
00507 {
00508         return PyFloat_FromDouble(getImageRender(self)->getClip());
00509 }
00510 
00511 // set clip
00512 static int setClip (PyImage * self, PyObject * value, void * closure)
00513 {
00514         // check validity of parameter
00515         double clip;
00516         if (value == NULL || !PyFloat_Check(value) || (clip = PyFloat_AsDouble(value)) < 0.01 || clip > 5000.0)
00517         {
00518                 PyErr_SetString(PyExc_TypeError, "The value must be an float between 0.01 and 5000");
00519                 return -1;
00520         }
00521         // set background color
00522         getImageRender(self)->setClip(float(clip));
00523         // success
00524         return 0;
00525 }
00526 
00527 // attributes structure
00528 static PyGetSetDef imageMirrorGetSets[] =
00529 { 
00530         {(char*)"clip", (getter)getClip, (setter)setClip, (char*)"clipping distance", NULL},
00531         // attribute from ImageRender
00532         {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL},
00533     // attribute from ImageViewport
00534         {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL},
00535         {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL},
00536         {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL},
00537         // attributes from ImageBase class
00538         {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
00539         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
00540         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
00541         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
00542         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
00543         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
00544         {NULL}
00545 };
00546 
00547 
00548 // constructor
00549 ImageRender::ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat) :
00550     ImageViewport(),
00551     m_render(false),
00552     m_scene(scene),
00553     m_observer(observer),
00554     m_mirror(mirror),
00555         m_clip(100.f)
00556 {
00557     // this constructor is used for automatic planar mirror
00558     // create a camera, take all data by default, in any case we will recompute the frustrum on each frame
00559         RAS_CameraData camdata;
00560     vector<RAS_TexVert*> mirrorVerts;
00561     vector<RAS_TexVert*>::iterator it;
00562     float mirrorArea = 0.f;
00563     float mirrorNormal[3] = {0.f, 0.f, 0.f};
00564     float mirrorUp[3];
00565     float dist, vec[3], axis[3];
00566     float zaxis[3] = {0.f, 0.f, 1.f};
00567     float yaxis[3] = {0.f, 1.f, 0.f};
00568     float mirrorMat[3][3];
00569     float left, right, top, bottom, back;
00570         // make sure this camera will delete its node
00571         m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true, true);
00572         m_camera->SetName("__mirror__cam__");
00573     // don't add the camera to the scene object list, it doesn't need to be accessible
00574     m_owncamera = true;
00575     // retrieve rendering objects
00576     m_engine = KX_GetActiveEngine();
00577     m_rasterizer = m_engine->GetRasterizer();
00578     m_canvas = m_engine->GetCanvas();
00579     m_rendertools = m_engine->GetRenderTools();
00580     // locate the vertex assigned to mat and do following calculation in mesh coordinates
00581     for (int meshIndex = 0; meshIndex < mirror->GetMeshCount(); meshIndex++)
00582     {
00583         RAS_MeshObject* mesh = mirror->GetMesh(meshIndex);
00584         int numPolygons = mesh->NumPolygons();
00585         for (int polygonIndex=0; polygonIndex < numPolygons; polygonIndex++)
00586         {
00587             RAS_Polygon* polygon = mesh->GetPolygon(polygonIndex);
00588             if (polygon->GetMaterial()->GetPolyMaterial() == mat)
00589             {
00590                 RAS_TexVert *v1, *v2, *v3, *v4;
00591                 float normal[3];
00592                 float area;
00593                 // this polygon is part of the mirror,
00594                 v1 = polygon->GetVertex(0);
00595                 v2 = polygon->GetVertex(1);
00596                 v3 = polygon->GetVertex(2);
00597                 mirrorVerts.push_back(v1);
00598                 mirrorVerts.push_back(v2);
00599                 mirrorVerts.push_back(v3);
00600                 if (polygon->VertexCount() == 4) 
00601                 {
00602                     v4 = polygon->GetVertex(3);
00603                     mirrorVerts.push_back(v4);
00604                     area = normal_quad_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ());
00605                 } else
00606                 {
00607                     area = normal_tri_v3( normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ());
00608                 }
00609                 area = fabs(area);
00610                 mirrorArea += area;
00611                 mul_v3_fl(normal, area);
00612                 add_v3_v3v3(mirrorNormal, mirrorNormal, normal);
00613             }
00614         }
00615     }
00616     if (mirrorVerts.size() == 0 || mirrorArea < FLT_EPSILON)
00617     {
00618         // no vertex or zero size mirror
00619        THRWEXCP(MirrorSizeInvalid, S_OK);
00620     }
00621     // compute average normal of mirror faces
00622     mul_v3_fl(mirrorNormal, 1.0f/mirrorArea);
00623     if (normalize_v3(mirrorNormal) == 0.f)
00624     {
00625         // no normal
00626         THRWEXCP(MirrorNormalInvalid, S_OK);
00627     }
00628     // the mirror plane has an equation of the type ax+by+cz = d where (a,b,c) is the normal vector
00629         // if the mirror is more vertical then horizontal, the Z axis is the up direction.
00630         // otherwise the Y axis is the up direction.
00631         // If the mirror is not perfectly vertical(horizontal), the Z(Y) axis projection on the mirror
00632         // plan by the normal will be the up direction.
00633         if (fabs(mirrorNormal[2]) > fabs(mirrorNormal[1]) &&
00634                 fabs(mirrorNormal[2]) > fabs(mirrorNormal[0]))
00635         {
00636                 // the mirror is more horizontal than vertical
00637         copy_v3_v3(axis, yaxis);
00638         }
00639         else
00640         {
00641                 // the mirror is more vertical than horizontal
00642         copy_v3_v3(axis, zaxis);
00643         }
00644     dist = dot_v3v3(mirrorNormal, axis);
00645     if (fabs(dist) < FLT_EPSILON)
00646     {
00647         // the mirror is already fully aligned with up axis
00648         copy_v3_v3(mirrorUp, axis);
00649     }
00650     else
00651     {
00652         // projection of axis to mirror plane through normal
00653         copy_v3_v3(vec, mirrorNormal);
00654         mul_v3_fl(vec, dist);
00655         sub_v3_v3v3(mirrorUp, axis, vec);
00656         if (normalize_v3(mirrorUp) == 0.f)
00657         {
00658             // should not happen
00659             THRWEXCP(MirrorHorizontal, S_OK);
00660             return;
00661         }
00662     }
00663     // compute rotation matrix between local coord and mirror coord
00664     // to match camera orientation, we select mirror z = -normal, y = up, x = y x z
00665     negate_v3_v3(mirrorMat[2], mirrorNormal);
00666     copy_v3_v3(mirrorMat[1], mirrorUp);
00667     cross_v3_v3v3(mirrorMat[0], mirrorMat[1], mirrorMat[2]);
00668     // transpose to make it a orientation matrix from local space to mirror space
00669     transpose_m3(mirrorMat);
00670     // transform all vertex to plane coordinates and determine mirror position
00671     left = FLT_MAX; 
00672     right = -FLT_MAX;
00673     bottom = FLT_MAX;
00674     top = -FLT_MAX;
00675     back = -FLT_MAX; // most backward vertex (=highest Z coord in mirror space)
00676     for (it = mirrorVerts.begin(); it != mirrorVerts.end(); it++)
00677     {   
00678         copy_v3_v3(vec, (float*)(*it)->getXYZ());
00679         mul_m3_v3(mirrorMat, vec);
00680         if (vec[0] < left)
00681             left = vec[0];
00682         if (vec[0] > right)
00683             right = vec[0];
00684         if (vec[1] < bottom)
00685             bottom = vec[1];
00686         if (vec[1] > top)
00687             top = vec[1];
00688         if (vec[2] > back)
00689             back = vec[2];
00690     }
00691     // now store this information in the object for later rendering
00692     m_mirrorHalfWidth = (right-left)*0.5f;
00693     m_mirrorHalfHeight = (top-bottom)*0.5f;
00694     if (m_mirrorHalfWidth < 0.01f || m_mirrorHalfHeight < 0.01f)
00695     {
00696         // mirror too small
00697         THRWEXCP(MirrorTooSmall, S_OK);
00698     }
00699     // mirror position in mirror coord
00700     vec[0] = (left+right)*0.5f;
00701     vec[1] = (top+bottom)*0.5f;
00702     vec[2] = back;
00703     // convert it in local space: transpose again the matrix to get back to mirror to local transform
00704     transpose_m3(mirrorMat);
00705     mul_m3_v3(mirrorMat, vec);
00706     // mirror position in local space
00707     m_mirrorPos.setValue(vec[0], vec[1], vec[2]);
00708     // mirror normal vector (pointed towards the back of the mirror) in local space
00709     m_mirrorZ.setValue(-mirrorNormal[0], -mirrorNormal[1], -mirrorNormal[2]);
00710     m_mirrorY.setValue(mirrorUp[0], mirrorUp[1], mirrorUp[2]);
00711     m_mirrorX = m_mirrorY.cross(m_mirrorZ);
00712     m_render = true;
00713 
00714         setBackground(0, 0, 255, 255);
00715 }
00716 
00717 
00718 
00719 
00720 // define python type
00721 PyTypeObject ImageMirrorType =
00722 { 
00723         PyVarObject_HEAD_INIT(NULL, 0)
00724         "VideoTexture.ImageMirror",   /*tp_name*/
00725         sizeof(PyImage),          /*tp_basicsize*/
00726         0,                         /*tp_itemsize*/
00727         (destructor)Image_dealloc, /*tp_dealloc*/
00728         0,                         /*tp_print*/
00729         0,                         /*tp_getattr*/
00730         0,                         /*tp_setattr*/
00731         0,                         /*tp_compare*/
00732         0,                         /*tp_repr*/
00733         0,                         /*tp_as_number*/
00734         0,                         /*tp_as_sequence*/
00735         0,                         /*tp_as_mapping*/
00736         0,                         /*tp_hash */
00737         0,                         /*tp_call*/
00738         0,                         /*tp_str*/
00739         0,                         /*tp_getattro*/
00740         0,                         /*tp_setattro*/
00741         &imageBufferProcs,         /*tp_as_buffer*/
00742         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
00743         "Image source from mirror",       /* tp_doc */
00744         0,                             /* tp_traverse */
00745         0,                             /* tp_clear */
00746         0,                             /* tp_richcompare */
00747         0,                             /* tp_weaklistoffset */
00748         0,                             /* tp_iter */
00749         0,                             /* tp_iternext */
00750         imageRenderMethods,    /* tp_methods */
00751         0,                   /* tp_members */
00752         imageMirrorGetSets,          /* tp_getset */
00753         0,                         /* tp_base */
00754         0,                         /* tp_dict */
00755         0,                         /* tp_descr_get */
00756         0,                         /* tp_descr_set */
00757         0,                         /* tp_dictoffset */
00758         (initproc)ImageMirror_init,     /* tp_init */
00759         0,                         /* tp_alloc */
00760         Image_allocNew,           /* tp_new */
00761 };
00762 
00763