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