Merging r57570 through r57601 from trunk into soc-2013-depsgraph_mt
[blender-staging.git] / source / gameengine / VideoTexture / ImageRender.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Copyright (c) 2007 The Zdeno Ash Miklas
19  *
20  * This source file is part of VideoTexture library
21  *
22  * Contributor(s):
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file gameengine/VideoTexture/ImageRender.cpp
28  *  \ingroup bgevideotex
29  */
30
31 // implementation
32
33 #include "PyObjectPlus.h"
34 #include <structmember.h>
35 #include <float.h>
36 #include <math.h>
37
38
39 #include "GL/glew.h"
40
41 #include "KX_PythonInit.h"
42 #include "DNA_scene_types.h"
43 #include "RAS_CameraData.h"
44 #include "RAS_MeshObject.h"
45 #include "BLI_math.h"
46
47 #include "ImageRender.h"
48 #include "ImageBase.h"
49 #include "BlendType.h"
50 #include "Exception.h"
51 #include "Texture.h"
52
53 ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid;
54 ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall;
55 ExpDesc SceneInvalidDesc(SceneInvalid, "Scene object is invalid");
56 ExpDesc CameraInvalidDesc(CameraInvalid, "Camera object is invalid");
57 ExpDesc ObserverInvalidDesc(ObserverInvalid, "Observer object is invalid");
58 ExpDesc MirrorInvalidDesc(MirrorInvalid, "Mirror object is invalid");
59 ExpDesc MirrorSizeInvalidDesc(MirrorSizeInvalid, "Mirror has no vertex or no size");
60 ExpDesc MirrorNormalInvalidDesc(MirrorNormalInvalid, "Cannot determine mirror plane");
61 ExpDesc MirrorHorizontalDesc(MirrorHorizontal, "Mirror is horizontal in local space");
62 ExpDesc MirrorTooSmallDesc(MirrorTooSmall, "Mirror is too small");
63
64 // constructor
65 ImageRender::ImageRender (KX_Scene *scene, KX_Camera * camera) :
66     ImageViewport(),
67     m_render(true),
68     m_scene(scene),
69     m_camera(camera),
70     m_owncamera(false),
71     m_observer(NULL),
72     m_mirror(NULL),
73     m_clip(100.f)
74 {
75         // initialize background color
76         setBackground(0, 0, 255, 255);
77         // retrieve rendering objects
78         m_engine = KX_GetActiveEngine();
79         m_rasterizer = m_engine->GetRasterizer();
80         m_canvas = m_engine->GetCanvas();
81         m_rendertools = m_engine->GetRenderTools();
82 }
83
84 // destructor
85 ImageRender::~ImageRender (void)
86 {
87         if (m_owncamera)
88                 m_camera->Release();
89 }
90
91
92 // set background color
93 void ImageRender::setBackground (int red, int green, int blue, int alpha)
94 {
95         m_background[0] = (red < 0) ? 0.f : (red > 255) ? 1.f : float(red)/255.f;
96         m_background[1] = (green < 0) ? 0.f : (green > 255) ? 1.f : float(green)/255.f;
97         m_background[2] = (blue < 0) ? 0.f : (blue > 255) ? 1.f : float(blue)/255.f;
98         m_background[3] = (alpha < 0) ? 0.f : (alpha > 255) ? 1.f : float(alpha)/255.f;
99 }
100
101
102 // capture image from viewport
103 void ImageRender::calcImage (unsigned int texId, double ts)
104 {
105         if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED ||   // no need for texture
106                 m_camera->GetViewport() ||        // camera must be inactive
107                 m_camera == m_scene->GetActiveCamera())
108         {
109                 // no need to compute texture in non texture rendering
110                 m_avail = false;
111                 return;
112         }
113         // render the scene from the camera
114         Render();
115         // get image from viewport
116         ImageViewport::calcImage(texId, ts);
117         // restore OpenGL state
118         m_canvas->EndFrame();
119 }
120
121 void ImageRender::Render()
122 {
123         RAS_FrameFrustum frustrum;
124
125         if (!m_render)
126                 return;
127
128         if (m_mirror)
129         {
130                 // mirror mode, compute camera frustrum, position and orientation
131                 // convert mirror position and normal in world space
132                 const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation();
133                 const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition();
134                 const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling();
135                 MT_Point3 mirrorWorldPos =
136                         mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos);
137                 MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ;
138                 // get observer world position
139                 const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition();
140                 // get plane D term = mirrorPos . normal
141                 MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ);
142                 // compute distance of observer to mirror = D - observerPos . normal
143                 MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ);
144                 // if distance < 0.01 => observer is on wrong side of mirror, don't render
145                 if (observerDistance < 0.01)
146                         return;
147                 // set camera world position = observerPos + normal * 2 * distance
148                 MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ;
149                 m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos);
150                 // set camera orientation: z=normal, y=mirror_up in world space, x= y x z
151                 MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY;
152                 MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX;
153                 MT_Matrix3x3 cameraWorldOri(
154                             mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0],
155                             mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1],
156                             mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]);
157                 m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri);
158                 m_camera->GetSGNode()->UpdateWorldData(0.0);
159                 // compute camera frustrum:
160                 //   get position of mirror relative to camera: offset = mirrorPos-cameraPos
161                 MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos;
162                 //   convert to camera orientation
163                 mirrorOffset = mirrorOffset * cameraWorldOri;
164                 //   scale mirror size to world scale:
165                 //     get closest local axis for mirror Y and X axis and scale height and width by local axis scale
166                 MT_Scalar x, y;
167                 x = fabs(m_mirrorY[0]);
168                 y = fabs(m_mirrorY[1]);
169                 float height = (x > y) ?
170                             ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
171                             ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
172                 x = fabs(m_mirrorX[0]);
173                 y = fabs(m_mirrorX[1]);
174                 float width = (x > y) ?
175                             ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]):
176                             ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]);
177                 width *= m_mirrorHalfWidth;
178                 height *= m_mirrorHalfHeight;
179                 //   left = offsetx-width
180                 //   right = offsetx+width
181                 //   top = offsety+height
182                 //   bottom = offsety-height
183                 //   near = -offsetz
184                 //   far = near+100
185                 frustrum.x1 = mirrorOffset[0]-width;
186                 frustrum.x2 = mirrorOffset[0]+width;
187                 frustrum.y1 = mirrorOffset[1]-height;
188                 frustrum.y2 = mirrorOffset[1]+height;
189                 frustrum.camnear = -mirrorOffset[2];
190                 frustrum.camfar = -mirrorOffset[2]+m_clip;
191         }
192         // Store settings to be restored later
193         const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
194         RAS_Rect area = m_canvas->GetWindowArea();
195
196         // The screen area that ImageViewport will copy is also the rendering zone
197         m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
198         m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
199         m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
200         m_rasterizer->BeginFrame(RAS_IRasterizer::KX_TEXTURED,m_engine->GetClockTime());
201         m_rendertools->BeginFrame(m_rasterizer);
202         m_engine->SetWorldSettings(m_scene->GetWorldInfo());
203         m_rendertools->SetAuxilaryClientInfo(m_scene);
204         m_rasterizer->DisplayFog();
205         // matrix calculation, don't apply any of the stereo mode
206         m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO);
207         if (m_mirror)
208         {
209                 // frustrum was computed above
210                 // get frustrum matrix and set projection matrix
211                 MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
212                             frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
213
214                 m_camera->SetProjectionMatrix(projmat);
215         }
216         else if (m_camera->hasValidProjectionMatrix()) {
217                 m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix());
218         }
219         else {
220                 float lens = m_camera->GetLens();
221                 float sensor_x = m_camera->GetSensorWidth();
222                 float sensor_y = m_camera->GetSensorHeight();
223                 bool orthographic = !m_camera->GetCameraData()->m_perspective;
224                 float nearfrust = m_camera->GetCameraNear();
225                 float farfrust = m_camera->GetCameraFar();
226                 float aspect_ratio = 1.0f;
227                 Scene *blenderScene = m_scene->GetBlenderScene();
228                 MT_Matrix4x4 projmat;
229
230                 // compute the aspect ratio from frame blender scene settings so that render to texture
231                 // works the same in Blender and in Blender player
232                 if (blenderScene->r.ysch != 0)
233                         aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp);
234
235                 if (orthographic) {
236
237                         RAS_FramingManager::ComputeDefaultOrtho(
238                                     nearfrust,
239                                     farfrust,
240                                     m_camera->GetScale(),
241                                     aspect_ratio,
242                                                 m_camera->GetSensorFit(),
243                                     frustrum
244                                     );
245
246                         projmat = m_rasterizer->GetOrthoMatrix(
247                                     frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
248                 }
249                 else {
250                         RAS_FramingManager::ComputeDefaultFrustum(
251                                     nearfrust,
252                                     farfrust,
253                                     lens,
254                                     sensor_x,
255                                     sensor_y,
256                                     RAS_SENSORFIT_AUTO,
257                                     aspect_ratio,
258                                     frustrum);
259                         
260                         projmat = m_rasterizer->GetFrustumMatrix(
261                                     frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
262                 }
263                 m_camera->SetProjectionMatrix(projmat);
264         }
265
266         MT_Transform camtrans(m_camera->GetWorldToCamera());
267         MT_Matrix4x4 viewmat(camtrans);
268         
269         m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective);
270         m_camera->SetModelviewMatrix(viewmat);
271         // restore the stereo mode now that the matrix is computed
272         m_rasterizer->SetStereoMode(stereomode);
273
274         m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
275
276         m_scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
277
278         m_scene->RenderFonts();
279
280         // restore the canvas area now that the render is completed
281         m_canvas->GetWindowArea() = area;
282 }
283
284
285 // cast Image pointer to ImageRender
286 inline ImageRender * getImageRender (PyImage *self)
287 { return static_cast<ImageRender*>(self->m_image); }
288
289
290 // python methods
291
292 // Blender Scene type
293 static BlendType<KX_Scene> sceneType ("KX_Scene");
294 // Blender Camera type
295 static BlendType<KX_Camera> cameraType ("KX_Camera");
296
297
298 // object initialization
299 static int ImageRender_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
300 {
301         // parameters - scene object
302         PyObject *scene;
303         // camera object
304         PyObject *camera;
305         // parameter keywords
306         static const char *kwlist[] = {"sceneObj", "cameraObj", NULL};
307         // get parameters
308         if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO",
309                 const_cast<char**>(kwlist), &scene, &camera))
310                 return -1;
311         try
312         {
313                 // get scene pointer
314                 KX_Scene * scenePtr (NULL);
315                 if (scene != NULL) scenePtr = sceneType.checkType(scene);
316                 // throw exception if scene is not available
317                 if (scenePtr == NULL) THRWEXCP(SceneInvalid, S_OK);
318
319                 // get camera pointer
320                 KX_Camera * cameraPtr (NULL);
321                 if (camera != NULL) cameraPtr = cameraType.checkType(camera);
322                 // throw exception if camera is not available
323                 if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK);
324
325                 // get pointer to image structure
326                 PyImage *self = reinterpret_cast<PyImage*>(pySelf);
327                 // create source object
328                 if (self->m_image != NULL) delete self->m_image;
329                 self->m_image = new ImageRender(scenePtr, cameraPtr);
330         }
331         catch (Exception & exp)
332         {
333                 exp.report();
334                 return -1;
335         }
336         // initialization succeded
337         return 0;
338 }
339
340
341 // get background color
342 static PyObject *getBackground (PyImage *self, void *closure)
343 {
344         return Py_BuildValue("[BBBB]",
345                              getImageRender(self)->getBackground(0),
346                              getImageRender(self)->getBackground(1),
347                              getImageRender(self)->getBackground(2),
348                              getImageRender(self)->getBackground(3));
349 }
350
351 // set color
352 static int setBackground(PyImage *self, PyObject *value, void *closure)
353 {
354         // check validity of parameter
355         if (value == NULL || !PySequence_Check(value) || PySequence_Size(value) != 4
356                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0))
357                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1))
358                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 2))
359                 || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 3)))
360         {
361                 PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 4 integer between 0 and 255");
362                 return -1;
363         }
364         // set background color
365         getImageRender(self)->setBackground(
366                 (unsigned char)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 0))),
367                 (unsigned char)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 1))),
368                 (unsigned char)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 2))),
369                 (unsigned char)(PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 3))));
370         // success
371         return 0;
372 }
373
374
375 // methods structure
376 static PyMethodDef imageRenderMethods[] =
377 { // methods from ImageBase class
378         {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"},
379         {NULL}
380 };
381 // attributes structure
382 static PyGetSetDef imageRenderGetSets[] =
383
384         {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL},
385         // attribute from ImageViewport
386         {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL},
387         {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL},
388         {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL},
389         // attributes from ImageBase class
390         {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
391         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
392         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
393         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)",  NULL},
394         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
395         {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
396         {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL},
397         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
398         {NULL}
399 };
400
401
402 // define python type
403 PyTypeObject ImageRenderType = {
404         PyVarObject_HEAD_INIT(NULL, 0)
405         "VideoTexture.ImageRender",   /*tp_name*/
406         sizeof(PyImage),          /*tp_basicsize*/
407         0,                         /*tp_itemsize*/
408         (destructor)Image_dealloc, /*tp_dealloc*/
409         0,                         /*tp_print*/
410         0,                         /*tp_getattr*/
411         0,                         /*tp_setattr*/
412         0,                         /*tp_compare*/
413         0,                         /*tp_repr*/
414         0,                         /*tp_as_number*/
415         0,                         /*tp_as_sequence*/
416         0,                         /*tp_as_mapping*/
417         0,                         /*tp_hash */
418         0,                         /*tp_call*/
419         0,                         /*tp_str*/
420         0,                         /*tp_getattro*/
421         0,                         /*tp_setattro*/
422         &imageBufferProcs,         /*tp_as_buffer*/
423         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
424         "Image source from render",       /* tp_doc */
425         0,                             /* tp_traverse */
426         0,                             /* tp_clear */
427         0,                             /* tp_richcompare */
428         0,                             /* tp_weaklistoffset */
429         0,                             /* tp_iter */
430         0,                             /* tp_iternext */
431         imageRenderMethods,    /* tp_methods */
432         0,                   /* tp_members */
433         imageRenderGetSets,          /* tp_getset */
434         0,                         /* tp_base */
435         0,                         /* tp_dict */
436         0,                         /* tp_descr_get */
437         0,                         /* tp_descr_set */
438         0,                         /* tp_dictoffset */
439         (initproc)ImageRender_init,     /* tp_init */
440         0,                         /* tp_alloc */
441         Image_allocNew,           /* tp_new */
442 };
443
444 // object initialization
445 static int ImageMirror_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
446 {
447         // parameters - scene object
448         PyObject *scene;
449         // reference object for mirror
450         PyObject *observer;
451         // object holding the mirror
452         PyObject *mirror;
453         // material of the mirror
454         short materialID = 0;
455         // parameter keywords
456         static const char *kwlist[] = {"scene", "observer", "mirror", "material", NULL};
457         // get parameters
458         if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h",
459                                          const_cast<char**>(kwlist), &scene, &observer, &mirror, &materialID))
460                 return -1;
461         try
462         {
463                 // get scene pointer
464                 KX_Scene * scenePtr (NULL);
465                 if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type))
466                         scenePtr = static_cast<KX_Scene*>BGE_PROXY_REF(scene);
467                 else
468                         THRWEXCP(SceneInvalid, S_OK);
469                 
470                 if (scenePtr==NULL) /* in case the python proxy reference is invalid */
471                         THRWEXCP(SceneInvalid, S_OK);
472                 
473                 // get observer pointer
474                 KX_GameObject * observerPtr (NULL);
475                 if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type))
476                         observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer);
477                 else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type))
478                         observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer);
479                 else
480                         THRWEXCP(ObserverInvalid, S_OK);
481                 
482                 if (observerPtr==NULL) /* in case the python proxy reference is invalid */
483                         THRWEXCP(ObserverInvalid, S_OK);
484
485                 // get mirror pointer
486                 KX_GameObject * mirrorPtr (NULL);
487                 if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type))
488                         mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror);
489                 else
490                         THRWEXCP(MirrorInvalid, S_OK);
491                 
492                 if (mirrorPtr==NULL) /* in case the python proxy reference is invalid */
493                         THRWEXCP(MirrorInvalid, S_OK);
494
495                 // locate the material in the mirror
496                 RAS_IPolyMaterial * material = getMaterial(mirror, materialID);
497                 if (material == NULL)
498                         THRWEXCP(MaterialNotAvail, S_OK);
499
500                 // get pointer to image structure
501                 PyImage *self = reinterpret_cast<PyImage*>(pySelf);
502
503                 // create source object
504                 if (self->m_image != NULL)
505                 {
506                         delete self->m_image;
507                         self->m_image = NULL;
508                 }
509                 self->m_image = new ImageRender(scenePtr, observerPtr, mirrorPtr, material);
510         }
511         catch (Exception & exp)
512         {
513                 exp.report();
514                 return -1;
515         }
516         // initialization succeded
517         return 0;
518 }
519
520 // get background color
521 static PyObject *getClip (PyImage *self, void *closure)
522 {
523         return PyFloat_FromDouble(getImageRender(self)->getClip());
524 }
525
526 // set clip
527 static int setClip(PyImage *self, PyObject *value, void *closure)
528 {
529         // check validity of parameter
530         double clip;
531         if (value == NULL || !PyFloat_Check(value) || (clip = PyFloat_AsDouble(value)) < 0.01 || clip > 5000.0)
532         {
533                 PyErr_SetString(PyExc_TypeError, "The value must be an float between 0.01 and 5000");
534                 return -1;
535         }
536         // set background color
537         getImageRender(self)->setClip(float(clip));
538         // success
539         return 0;
540 }
541
542 // attributes structure
543 static PyGetSetDef imageMirrorGetSets[] =
544
545         {(char*)"clip", (getter)getClip, (setter)setClip, (char*)"clipping distance", NULL},
546         // attribute from ImageRender
547         {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL},
548         // attribute from ImageViewport
549         {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL},
550         {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL},
551         {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL},
552         // attributes from ImageBase class
553         {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
554         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
555         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
556         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbor)",  NULL},
557         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
558         {(char*)"zbuff", (getter)Image_getZbuff, (setter)Image_setZbuff, (char*)"use depth buffer as texture", NULL},
559         {(char*)"depth", (getter)Image_getDepth, (setter)Image_setDepth, (char*)"get depth information from z-buffer using unsigned int precision", NULL},
560         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
561         {NULL}
562 };
563
564
565 // constructor
566 ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObject *mirror, RAS_IPolyMaterial *mat) :
567     ImageViewport(),
568     m_render(false),
569     m_scene(scene),
570     m_observer(observer),
571     m_mirror(mirror),
572     m_clip(100.f)
573 {
574         // this constructor is used for automatic planar mirror
575         // create a camera, take all data by default, in any case we will recompute the frustrum on each frame
576         RAS_CameraData camdata;
577         vector<RAS_TexVert*> mirrorVerts;
578         vector<RAS_TexVert*>::iterator it;
579         float mirrorArea = 0.f;
580         float mirrorNormal[3] = {0.f, 0.f, 0.f};
581         float mirrorUp[3];
582         float dist, vec[3], axis[3];
583         float zaxis[3] = {0.f, 0.f, 1.f};
584         float yaxis[3] = {0.f, 1.f, 0.f};
585         float mirrorMat[3][3];
586         float left, right, top, bottom, back;
587         // make sure this camera will delete its node
588         m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true, true);
589         m_camera->SetName("__mirror__cam__");
590         // don't add the camera to the scene object list, it doesn't need to be accessible
591         m_owncamera = true;
592         // retrieve rendering objects
593         m_engine = KX_GetActiveEngine();
594         m_rasterizer = m_engine->GetRasterizer();
595         m_canvas = m_engine->GetCanvas();
596         m_rendertools = m_engine->GetRenderTools();
597         // locate the vertex assigned to mat and do following calculation in mesh coordinates
598         for (int meshIndex = 0; meshIndex < mirror->GetMeshCount(); meshIndex++)
599         {
600                 RAS_MeshObject* mesh = mirror->GetMesh(meshIndex);
601                 int numPolygons = mesh->NumPolygons();
602                 for (int polygonIndex=0; polygonIndex < numPolygons; polygonIndex++)
603                 {
604                         RAS_Polygon* polygon = mesh->GetPolygon(polygonIndex);
605                         if (polygon->GetMaterial()->GetPolyMaterial() == mat)
606                         {
607                                 RAS_TexVert *v1, *v2, *v3, *v4;
608                                 float normal[3];
609                                 float area;
610                                 // this polygon is part of the mirror,
611                                 v1 = polygon->GetVertex(0);
612                                 v2 = polygon->GetVertex(1);
613                                 v3 = polygon->GetVertex(2);
614                                 mirrorVerts.push_back(v1);
615                                 mirrorVerts.push_back(v2);
616                                 mirrorVerts.push_back(v3);
617                                 if (polygon->VertexCount() == 4) {
618                                         v4 = polygon->GetVertex(3);
619                                         mirrorVerts.push_back(v4);
620                                         area = normal_quad_v3(normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ());
621                                 }
622                                 else {
623                                         area = normal_tri_v3(normal,(float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ());
624                                 }
625                                 area = fabs(area);
626                                 mirrorArea += area;
627                                 mul_v3_fl(normal, area);
628                                 add_v3_v3v3(mirrorNormal, mirrorNormal, normal);
629                         }
630                 }
631         }
632         if (mirrorVerts.size() == 0 || mirrorArea < FLT_EPSILON)
633         {
634                 // no vertex or zero size mirror
635                 THRWEXCP(MirrorSizeInvalid, S_OK);
636         }
637         // compute average normal of mirror faces
638         mul_v3_fl(mirrorNormal, 1.0f/mirrorArea);
639         if (normalize_v3(mirrorNormal) == 0.f)
640         {
641                 // no normal
642                 THRWEXCP(MirrorNormalInvalid, S_OK);
643         }
644         // the mirror plane has an equation of the type ax+by+cz = d where (a,b,c) is the normal vector
645         // if the mirror is more vertical then horizontal, the Z axis is the up direction.
646         // otherwise the Y axis is the up direction.
647         // If the mirror is not perfectly vertical(horizontal), the Z(Y) axis projection on the mirror
648         // plan by the normal will be the up direction.
649         if (fabsf(mirrorNormal[2]) > fabsf(mirrorNormal[1]) &&
650             fabsf(mirrorNormal[2]) > fabsf(mirrorNormal[0]))
651         {
652                 // the mirror is more horizontal than vertical
653                 copy_v3_v3(axis, yaxis);
654         }
655         else
656         {
657                 // the mirror is more vertical than horizontal
658                 copy_v3_v3(axis, zaxis);
659         }
660         dist = dot_v3v3(mirrorNormal, axis);
661         if (fabsf(dist) < FLT_EPSILON)
662         {
663                 // the mirror is already fully aligned with up axis
664                 copy_v3_v3(mirrorUp, axis);
665         }
666         else
667         {
668                 // projection of axis to mirror plane through normal
669                 copy_v3_v3(vec, mirrorNormal);
670                 mul_v3_fl(vec, dist);
671                 sub_v3_v3v3(mirrorUp, axis, vec);
672                 if (normalize_v3(mirrorUp) == 0.f)
673                 {
674                         // should not happen
675                         THRWEXCP(MirrorHorizontal, S_OK);
676                         return;
677                 }
678         }
679         // compute rotation matrix between local coord and mirror coord
680         // to match camera orientation, we select mirror z = -normal, y = up, x = y x z
681         negate_v3_v3(mirrorMat[2], mirrorNormal);
682         copy_v3_v3(mirrorMat[1], mirrorUp);
683         cross_v3_v3v3(mirrorMat[0], mirrorMat[1], mirrorMat[2]);
684         // transpose to make it a orientation matrix from local space to mirror space
685         transpose_m3(mirrorMat);
686         // transform all vertex to plane coordinates and determine mirror position
687         left = FLT_MAX;
688         right = -FLT_MAX;
689         bottom = FLT_MAX;
690         top = -FLT_MAX;
691         back = -FLT_MAX; // most backward vertex (=highest Z coord in mirror space)
692         for (it = mirrorVerts.begin(); it != mirrorVerts.end(); it++)
693         {
694                 copy_v3_v3(vec, (float*)(*it)->getXYZ());
695                 mul_m3_v3(mirrorMat, vec);
696                 if (vec[0] < left)
697                         left = vec[0];
698                 if (vec[0] > right)
699                         right = vec[0];
700                 if (vec[1] < bottom)
701                         bottom = vec[1];
702                 if (vec[1] > top)
703                         top = vec[1];
704                 if (vec[2] > back)
705                         back = vec[2];
706         }
707         // now store this information in the object for later rendering
708         m_mirrorHalfWidth = (right-left)*0.5f;
709         m_mirrorHalfHeight = (top-bottom)*0.5f;
710         if (m_mirrorHalfWidth < 0.01f || m_mirrorHalfHeight < 0.01f)
711         {
712                 // mirror too small
713                 THRWEXCP(MirrorTooSmall, S_OK);
714         }
715         // mirror position in mirror coord
716         vec[0] = (left+right)*0.5f;
717         vec[1] = (top+bottom)*0.5f;
718         vec[2] = back;
719         // convert it in local space: transpose again the matrix to get back to mirror to local transform
720         transpose_m3(mirrorMat);
721         mul_m3_v3(mirrorMat, vec);
722         // mirror position in local space
723         m_mirrorPos.setValue(vec[0], vec[1], vec[2]);
724         // mirror normal vector (pointed towards the back of the mirror) in local space
725         m_mirrorZ.setValue(-mirrorNormal[0], -mirrorNormal[1], -mirrorNormal[2]);
726         m_mirrorY.setValue(mirrorUp[0], mirrorUp[1], mirrorUp[2]);
727         m_mirrorX = m_mirrorY.cross(m_mirrorZ);
728         m_render = true;
729
730         setBackground(0, 0, 255, 255);
731 }
732
733
734
735
736 // define python type
737 PyTypeObject ImageMirrorType = {
738         PyVarObject_HEAD_INIT(NULL, 0)
739         "VideoTexture.ImageMirror",   /*tp_name*/
740         sizeof(PyImage),          /*tp_basicsize*/
741         0,                         /*tp_itemsize*/
742         (destructor)Image_dealloc, /*tp_dealloc*/
743         0,                         /*tp_print*/
744         0,                         /*tp_getattr*/
745         0,                         /*tp_setattr*/
746         0,                         /*tp_compare*/
747         0,                         /*tp_repr*/
748         0,                         /*tp_as_number*/
749         0,                         /*tp_as_sequence*/
750         0,                         /*tp_as_mapping*/
751         0,                         /*tp_hash */
752         0,                         /*tp_call*/
753         0,                         /*tp_str*/
754         0,                         /*tp_getattro*/
755         0,                         /*tp_setattro*/
756         &imageBufferProcs,         /*tp_as_buffer*/
757         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
758         "Image source from mirror",       /* tp_doc */
759         0,                             /* tp_traverse */
760         0,                             /* tp_clear */
761         0,                             /* tp_richcompare */
762         0,                             /* tp_weaklistoffset */
763         0,                             /* tp_iter */
764         0,                             /* tp_iternext */
765         imageRenderMethods,    /* tp_methods */
766         0,                   /* tp_members */
767         imageMirrorGetSets,          /* tp_getset */
768         0,                         /* tp_base */
769         0,                         /* tp_dict */
770         0,                         /* tp_descr_get */
771         0,                         /* tp_descr_set */
772         0,                         /* tp_dictoffset */
773         (initproc)ImageMirror_init,     /* tp_init */
774         0,                         /* tp_alloc */
775         Image_allocNew,           /* tp_new */
776 };
777
778