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