removing files that should not be in blender2.5, added (by mistake?) r19226
[blender.git] / source / gameengine / Ketsji / KX_Camera.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Camera in the gameengine. Cameras are also used for views.
29  */
30  
31 #include "GL/glew.h"
32 #include "KX_Camera.h"
33 #include "KX_Scene.h"
34 #include "KX_PythonInit.h"
35 #include "KX_Python.h"
36 #include "KX_PyMath.h"
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 KX_Camera::KX_Camera(void* sgReplicationInfo,
42                                          SG_Callbacks callbacks,
43                                          const RAS_CameraData& camdata,
44                                          bool frustum_culling,
45                                          bool delete_node,
46                                          PyTypeObject *T)
47                                         :
48                                         KX_GameObject(sgReplicationInfo,callbacks,T),
49                                         m_camdata(camdata),
50                                         m_dirty(true),
51                                         m_normalized(false),
52                                         m_frustum_culling(frustum_culling),
53                                         m_set_projection_matrix(false),
54                                         m_set_frustum_center(false),
55                                         m_delete_node(delete_node)
56 {
57         // setting a name would be nice...
58         m_name = "cam";
59         m_projection_matrix.setIdentity();
60         m_modelview_matrix.setIdentity();
61         CValue* val = new CIntValue(1);
62         SetProperty("camera",val);
63         val->Release();
64 }
65
66
67 KX_Camera::~KX_Camera()
68 {
69         if (m_delete_node && m_pSGNode)
70         {
71                 // for shadow camera, avoids memleak
72                 delete m_pSGNode;
73                 m_pSGNode = NULL;
74         }
75 }       
76
77
78 CValue* KX_Camera::GetReplica()
79 {
80         KX_Camera* replica = new KX_Camera(*this);
81         
82         // this will copy properties and so on...
83         replica->ProcessReplica();
84         
85         return replica;
86 }
87
88 void KX_Camera::ProcessReplica()
89 {
90         KX_GameObject::ProcessReplica();
91         // replicated camera are always registered in the scene
92         m_delete_node = false;
93 }
94
95 MT_Transform KX_Camera::GetWorldToCamera() const
96
97         MT_Transform camtrans;
98         camtrans.invert(MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation()));
99         
100         return camtrans;
101 }
102
103
104          
105 MT_Transform KX_Camera::GetCameraToWorld() const
106 {
107         return MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation());
108 }
109
110
111
112 void KX_Camera::CorrectLookUp(MT_Scalar speed)
113 {
114 }
115
116
117
118 const MT_Point3 KX_Camera::GetCameraLocation() const
119 {
120         /* this is the camera locatio in cam coords... */
121         //return m_trans1.getOrigin();
122         //return MT_Point3(0,0,0);   <-----
123         /* .... I want it in world coords */
124         //MT_Transform trans;
125         //trans.setBasis(NodeGetWorldOrientation());
126         
127         return NodeGetWorldPosition();          
128 }
129
130
131
132 /* I want the camera orientation as well. */
133 const MT_Quaternion KX_Camera::GetCameraOrientation() const
134 {
135         return NodeGetWorldOrientation().getRotation();
136 }
137
138
139
140 /**
141 * Sets the projection matrix that is used by the rasterizer.
142 */
143 void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat)
144 {
145         m_projection_matrix = mat;
146         m_dirty = true;
147         m_set_projection_matrix = true;
148         m_set_frustum_center = false;
149 }
150
151
152
153 /**
154 * Sets the modelview matrix that is used by the rasterizer.
155 */
156 void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat)
157 {
158         m_modelview_matrix = mat;
159         m_dirty = true;
160         m_set_frustum_center = false;
161 }
162
163
164
165 /**
166 * Gets the projection matrix that is used by the rasterizer.
167 */
168 const MT_Matrix4x4& KX_Camera::GetProjectionMatrix() const
169 {
170         return m_projection_matrix;
171 }
172
173
174
175 /**
176 * Gets the modelview matrix that is used by the rasterizer.
177 */
178 const MT_Matrix4x4& KX_Camera::GetModelviewMatrix() const
179 {
180         return m_modelview_matrix;
181 }
182
183
184 bool KX_Camera::hasValidProjectionMatrix() const
185 {
186         return m_set_projection_matrix;
187 }
188
189 void KX_Camera::InvalidateProjectionMatrix(bool valid)
190 {
191         m_set_projection_matrix = valid;
192 }
193
194
195 /*
196 * These getters retrieve the clip data and the focal length
197 */
198 float KX_Camera::GetLens() const
199 {
200         return m_camdata.m_lens;
201 }
202
203 float KX_Camera::GetScale() const
204 {
205         return m_camdata.m_scale;
206 }
207
208
209
210 float KX_Camera::GetCameraNear() const
211 {
212         return m_camdata.m_clipstart;
213 }
214
215
216
217 float KX_Camera::GetCameraFar() const
218 {
219         return m_camdata.m_clipend;
220 }
221
222 float KX_Camera::GetFocalLength() const
223 {
224         return m_camdata.m_focallength;
225 }
226
227
228
229 RAS_CameraData* KX_Camera::GetCameraData()
230 {
231         return &m_camdata; 
232 }
233
234 void KX_Camera::ExtractClipPlanes()
235 {
236         if (!m_dirty)
237                 return;
238
239         MT_Matrix4x4 m = m_projection_matrix * m_modelview_matrix;
240         // Left clip plane
241         m_planes[0] = m[3] + m[0];
242         // Right clip plane
243         m_planes[1] = m[3] - m[0];
244         // Top clip plane
245         m_planes[2] = m[3] - m[1];
246         // Bottom clip plane
247         m_planes[3] = m[3] + m[1];
248         // Near clip plane
249         m_planes[4] = m[3] + m[2];
250         // Far clip plane
251         m_planes[5] = m[3] - m[2];
252         
253         m_dirty = false;
254         m_normalized = false;
255 }
256
257 void KX_Camera::NormalizeClipPlanes()
258 {
259         if (m_normalized)
260                 return;
261         
262         for (unsigned int p = 0; p < 6; p++)
263         {
264                 MT_Scalar factor = sqrt(m_planes[p][0]*m_planes[p][0] + m_planes[p][1]*m_planes[p][1] + m_planes[p][2]*m_planes[p][2]);
265                 if (!MT_fuzzyZero(factor))
266                         m_planes[p] /= factor;
267         }
268         
269         m_normalized = true;
270 }
271
272 void KX_Camera::ExtractFrustumSphere()
273 {
274         if (m_set_frustum_center)
275                 return;
276
277     // compute sphere for the general case and not only symmetric frustum:
278     // the mirror code in ImageRender can use very asymmetric frustum.
279     // We will put the sphere center on the line that goes from origin to the center of the far clipping plane
280     // This is the optimal position if the frustum is symmetric or very asymmetric and probably close
281     // to optimal for the general case. The sphere center position is computed so that the distance to 
282     // the near and far extreme frustum points are equal.
283
284     // get the transformation matrix from device coordinate to camera coordinate
285         MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix;
286         clip_camcs_matrix.invert();
287
288         if (m_projection_matrix[3][3] == MT_Scalar(0.0)) 
289         {
290                 // frustrum projection
291                 // detect which of the corner of the far clipping plane is the farthest to the origin
292                 MT_Vector4 nfar;    // far point in device normalized coordinate
293                 MT_Point3 farpoint; // most extreme far point in camera coordinate
294                 MT_Point3 nearpoint;// most extreme near point in camera coordinate
295                 MT_Point3 farcenter(0.,0.,0.);// center of far cliping plane in camera coordinate
296                 MT_Scalar F=-1.0, N; // square distance of far and near point to origin
297                 MT_Scalar f, n;     // distance of far and near point to z axis. f is always > 0 but n can be < 0
298                 MT_Scalar e, s;     // far and near clipping distance (<0)
299                 MT_Scalar c;        // slope of center line = distance of far clipping center to z axis / far clipping distance
300                 MT_Scalar z;        // projection of sphere center on z axis (<0)
301                 // tmp value
302                 MT_Vector4 npoint(1., 1., 1., 1.);
303                 MT_Vector4 hpoint;
304                 MT_Point3 point;
305                 MT_Scalar len;
306                 for (int i=0; i<4; i++)
307                 {
308                 hpoint = clip_camcs_matrix*npoint;
309                         point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]);
310                         len = point.dot(point);
311                         if (len > F)
312                         {
313                                 nfar = npoint;
314                                 farpoint = point;
315                                 F = len;
316                         }
317                         // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane
318                         len = npoint[0];
319                         npoint[0] = -npoint[1];
320                         npoint[1] = len;
321                         farcenter += point;
322                 }
323                 // the far center is the average of the far clipping points
324                 farcenter *= 0.25;
325                 // the extreme near point is the opposite point on the near clipping plane
326                 nfar.setValue(-nfar[0], -nfar[1], -1., 1.);
327                 nfar = clip_camcs_matrix*nfar;
328                 nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]);
329                 // this is a frustrum projection
330                 N = nearpoint.dot(nearpoint);
331                 e = farpoint[2];
332                 s = nearpoint[2];
333                 // projection on XY plane for distance to axis computation
334                 MT_Point2 farxy(farpoint[0], farpoint[1]);
335                 // f is forced positive by construction
336                 f = farxy.length();
337                 // get corresponding point on the near plane
338                 farxy *= s/e;
339                 // this formula preserve the sign of n
340                 n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length();
341                 c = MT_Point2(farcenter[0], farcenter[1]).length()/e;
342                 // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case
343                 z = (F-N)/(2.0*(e-s+c*(f-n)));
344                 m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z);
345                 m_frustum_radius = m_frustum_center.distance(farpoint);
346         } 
347         else
348         {
349                 // orthographic projection
350                 // The most extreme points on the near and far plane. (normalized device coords)
351                 MT_Vector4 hnear(1., 1., 1., 1.), hfar(-1., -1., -1., 1.);
352                 
353                 // Transform to hom camera local space
354                 hnear = clip_camcs_matrix*hnear;
355                 hfar = clip_camcs_matrix*hfar;
356                 
357                 // Tranform to 3d camera local space.
358                 MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]);
359                 MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]);
360                 
361                 // just use mediant point
362                 m_frustum_center = (farpoint + nearpoint)*0.5;
363                 m_frustum_radius = m_frustum_center.distance(farpoint);
364         }
365         // Transform to world space.
366         m_frustum_center = GetCameraToWorld()(m_frustum_center);
367         m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
368         
369         m_set_frustum_center = true;
370 }
371
372 bool KX_Camera::PointInsideFrustum(const MT_Point3& x)
373 {
374         ExtractClipPlanes();
375         
376         for( unsigned int i = 0; i < 6 ; i++ )
377         {
378                 if (m_planes[i][0]*x[0] + m_planes[i][1]*x[1] + m_planes[i][2]*x[2] + m_planes[i][3] < 0.)
379                         return false;
380         }
381         return true;
382 }
383
384 int KX_Camera::BoxInsideFrustum(const MT_Point3 *box)
385 {
386         ExtractClipPlanes();
387         
388         unsigned int insideCount = 0;
389         // 6 view frustum planes
390         for( unsigned int p = 0; p < 6 ; p++ )
391         {
392                 unsigned int behindCount = 0;
393                 // 8 box verticies.
394                 for (unsigned int v = 0; v < 8 ; v++)
395                 {
396                         if (m_planes[p][0]*box[v][0] + m_planes[p][1]*box[v][1] + m_planes[p][2]*box[v][2] + m_planes[p][3] < 0.)
397                                 behindCount++;
398                 }
399                 
400                 // 8 points behind this plane
401                 if (behindCount == 8)
402                         return OUTSIDE;
403
404                 // Every box vertex is on the front side of this plane
405                 if (!behindCount)
406                         insideCount++;
407         }
408         
409         // All box verticies are on the front side of all frustum planes.
410         if (insideCount == 6)
411                 return INSIDE;
412         
413         return INTERSECT;
414 }
415
416 int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius)
417 {
418         ExtractFrustumSphere();
419         if (center.distance2(m_frustum_center) > (radius + m_frustum_radius)*(radius + m_frustum_radius))
420                 return OUTSIDE;
421
422         unsigned int p;
423         ExtractClipPlanes();
424         NormalizeClipPlanes();
425                 
426         MT_Scalar distance;
427         int intersect = INSIDE;
428         // distance:  <-------- OUTSIDE -----|----- INTERSECT -----0----- INTERSECT -----|----- INSIDE -------->
429         //                                -radius                                      radius
430         for (p = 0; p < 6; p++)
431         {
432                 distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3];
433                 if (fabs(distance) <= radius)
434                         intersect = INTERSECT;
435                 else if (distance < -radius)
436                         return OUTSIDE;
437         }
438         
439         return intersect;
440 }
441
442 bool KX_Camera::GetFrustumCulling() const
443 {
444         return m_frustum_culling;
445 }
446  
447 void KX_Camera::EnableViewport(bool viewport)
448 {
449         m_camdata.m_viewport = viewport;
450 }
451
452 void KX_Camera::SetViewport(int left, int bottom, int right, int top)
453 {
454         m_camdata.m_viewportleft = left;
455         m_camdata.m_viewportbottom = bottom;
456         m_camdata.m_viewportright = right;
457         m_camdata.m_viewporttop = top;
458 }
459
460 bool KX_Camera::GetViewport() const
461 {
462         return m_camdata.m_viewport;
463 }
464
465 int KX_Camera::GetViewportLeft() const
466 {
467         return m_camdata.m_viewportleft;
468 }
469
470 int KX_Camera::GetViewportBottom() const
471 {
472         return m_camdata.m_viewportbottom;
473 }
474
475 int KX_Camera::GetViewportRight() const
476 {
477         return m_camdata.m_viewportright;
478 }
479
480 int KX_Camera::GetViewportTop() const
481 {
482         return m_camdata.m_viewporttop;
483 }
484
485 //----------------------------------------------------------------------------
486 //Python
487
488
489 PyMethodDef KX_Camera::Methods[] = {
490         KX_PYMETHODTABLE(KX_Camera, sphereInsideFrustum),
491         KX_PYMETHODTABLE_O(KX_Camera, boxInsideFrustum),
492         KX_PYMETHODTABLE_O(KX_Camera, pointInsideFrustum),
493         KX_PYMETHODTABLE_NOARGS(KX_Camera, getCameraToWorld),
494         KX_PYMETHODTABLE_NOARGS(KX_Camera, getWorldToCamera),
495         KX_PYMETHODTABLE(KX_Camera, setViewport),
496         KX_PYMETHODTABLE_NOARGS(KX_Camera, setOnTop),
497         KX_PYMETHODTABLE_O(KX_Camera, getScreenPosition),
498         KX_PYMETHODTABLE(KX_Camera, getScreenVect),
499         KX_PYMETHODTABLE(KX_Camera, getScreenRay),
500
501         // DEPRECATED
502         KX_PYMETHODTABLE_O(KX_Camera, enableViewport),
503         KX_PYMETHODTABLE_NOARGS(KX_Camera, getProjectionMatrix),
504         KX_PYMETHODTABLE_O(KX_Camera, setProjectionMatrix),
505         
506         {NULL,NULL} //Sentinel
507 };
508
509 PyAttributeDef KX_Camera::Attributes[] = {
510         
511         KX_PYATTRIBUTE_BOOL_RW("frustum_culling", KX_Camera, m_frustum_culling),
512         KX_PYATTRIBUTE_RW_FUNCTION("perspective", KX_Camera, pyattr_get_perspective, pyattr_set_perspective),
513         
514         KX_PYATTRIBUTE_RW_FUNCTION("lens",      KX_Camera,      pyattr_get_lens, pyattr_set_lens),
515         KX_PYATTRIBUTE_RW_FUNCTION("near",      KX_Camera,      pyattr_get_near, pyattr_set_near),
516         KX_PYATTRIBUTE_RW_FUNCTION("far",       KX_Camera,      pyattr_get_far,  pyattr_set_far),
517         
518         KX_PYATTRIBUTE_RW_FUNCTION("useViewport",       KX_Camera,      pyattr_get_use_viewport,  pyattr_set_use_viewport),
519         
520         KX_PYATTRIBUTE_RW_FUNCTION("projection_matrix", KX_Camera,      pyattr_get_projection_matrix, pyattr_set_projection_matrix),
521         KX_PYATTRIBUTE_RO_FUNCTION("modelview_matrix",  KX_Camera,      pyattr_get_modelview_matrix),
522         KX_PYATTRIBUTE_RO_FUNCTION("camera_to_world",   KX_Camera,      pyattr_get_camera_to_world),
523         KX_PYATTRIBUTE_RO_FUNCTION("world_to_camera",   KX_Camera,      pyattr_get_world_to_camera),
524         
525         /* Grrr, functions for constants? */
526         KX_PYATTRIBUTE_RO_FUNCTION("INSIDE",    KX_Camera, pyattr_get_INSIDE),
527         KX_PYATTRIBUTE_RO_FUNCTION("OUTSIDE",   KX_Camera, pyattr_get_OUTSIDE),
528         KX_PYATTRIBUTE_RO_FUNCTION("INTERSECT", KX_Camera, pyattr_get_INTERSECT),
529         
530         { NULL }        //Sentinel
531 };
532
533 PyTypeObject KX_Camera::Type = {
534 #if (PY_VERSION_HEX >= 0x02060000)
535         PyVarObject_HEAD_INIT(NULL, 0)
536 #else
537         /* python 2.5 and below */
538         PyObject_HEAD_INIT( NULL )  /* required py macro */
539         0,                          /* ob_size */
540 #endif
541                 "KX_Camera",
542                 sizeof(PyObjectPlus_Proxy),
543                 0,
544                 py_base_dealloc,
545                 0,
546                 0,
547                 0,
548                 0,
549                 py_base_repr,
550                 0,
551                 &KX_GameObject::Sequence,
552                 &KX_GameObject::Mapping,
553                 0,0,0,
554                 py_base_getattro,
555                 py_base_setattro,
556                 0,
557                 Py_TPFLAGS_DEFAULT,
558                 0,0,0,0,0,0,0,
559                 Methods
560 };
561
562
563
564
565
566
567 PyParentObject KX_Camera::Parents[] = {
568         &KX_Camera::Type,
569         &KX_GameObject::Type,
570                 &SCA_IObject::Type,
571                 &CValue::Type,
572                 NULL
573 };
574
575 PyObject* KX_Camera::py_getattro(PyObject *attr)
576 {
577         py_getattro_up(KX_GameObject);
578 }
579
580 PyObject* KX_Camera::py_getattro_dict() {
581         py_getattro_dict_up(KX_GameObject);
582 }
583
584 int KX_Camera::py_setattro(PyObject *attr, PyObject *value)
585 {       
586         py_setattro_up(KX_GameObject);
587 }
588
589 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, sphereInsideFrustum,
590 "sphereInsideFrustum(center, radius) -> Integer\n"
591 "\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n"
592 "\tinside/outside/intersects this camera's viewing frustum.\n\n"
593 "\tcenter = the center of the sphere (in world coordinates.)\n"
594 "\tradius = the radius of the sphere\n\n"
595 "\tExample:\n"
596 "\timport GameLogic\n\n"
597 "\tco = GameLogic.getCurrentController()\n"
598 "\tcam = co.GetOwner()\n\n"
599 "\t# A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]\n"
600 "\tif (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):\n"
601 "\t\t# Sphere is inside frustum !\n"
602 "\t\t# Do something useful !\n"
603 "\telse:\n"
604 "\t\t# Sphere is outside frustum\n"
605 )
606 {
607         PyObject *pycenter;
608         float radius;
609         if (PyArg_ParseTuple(args, "Of:sphereInsideFrustum", &pycenter, &radius))
610         {
611                 MT_Point3 center;
612                 if (PyVecTo(pycenter, center))
613                 {
614                         return PyInt_FromLong(SphereInsideFrustum(center, radius)); /* new ref */
615                 }
616         }
617
618         PyErr_SetString(PyExc_TypeError, "camera.sphereInsideFrustum(center, radius): KX_Camera, expected arguments: (center, radius)");
619         
620         return NULL;
621 }
622
623 KX_PYMETHODDEF_DOC_O(KX_Camera, boxInsideFrustum,
624 "boxInsideFrustum(box) -> Integer\n"
625 "\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n"
626 "\tinside/outside/intersects this camera's viewing frustum.\n\n"
627 "\tbox = a list of the eight (8) corners of the box (in world coordinates.)\n\n"
628 "\tExample:\n"
629 "\timport GameLogic\n\n"
630 "\tco = GameLogic.getCurrentController()\n"
631 "\tcam = co.GetOwner()\n\n"
632 "\tbox = []\n"
633 "\tbox.append([-1.0, -1.0, -1.0])\n"
634 "\tbox.append([-1.0, -1.0,  1.0])\n"
635 "\tbox.append([-1.0,  1.0, -1.0])\n"
636 "\tbox.append([-1.0,  1.0,  1.0])\n"
637 "\tbox.append([ 1.0, -1.0, -1.0])\n"
638 "\tbox.append([ 1.0, -1.0,  1.0])\n"
639 "\tbox.append([ 1.0,  1.0, -1.0])\n"
640 "\tbox.append([ 1.0,  1.0,  1.0])\n\n"
641 "\tif (cam.boxInsideFrustum(box) != cam.OUTSIDE):\n"
642 "\t\t# Box is inside/intersects frustum !\n"
643 "\t\t# Do something useful !\n"
644 "\telse:\n"
645 "\t\t# Box is outside the frustum !\n"
646 )
647 {
648         unsigned int num_points = PySequence_Size(value);
649         if (num_points != 8)
650         {
651                 PyErr_Format(PyExc_TypeError, "camera.boxInsideFrustum(box): KX_Camera, expected eight (8) points, got %d", num_points);
652                 return NULL;
653         }
654         
655         MT_Point3 box[8];
656         for (unsigned int p = 0; p < 8 ; p++)
657         {
658                 PyObject *item = PySequence_GetItem(value, p); /* new ref */
659                 bool error = !PyVecTo(item, box[p]);
660                 Py_DECREF(item);
661                 if (error)
662                         return NULL;
663         }
664         
665         return PyInt_FromLong(BoxInsideFrustum(box)); /* new ref */
666 }
667
668 KX_PYMETHODDEF_DOC_O(KX_Camera, pointInsideFrustum,
669 "pointInsideFrustum(point) -> Bool\n"
670 "\treturns 1 if the given point is inside this camera's viewing frustum.\n\n"
671 "\tpoint = The point to test (in world coordinates.)\n\n"
672 "\tExample:\n"
673 "\timport GameLogic\n\n"
674 "\tco = GameLogic.getCurrentController()\n"
675 "\tcam = co.GetOwner()\n\n"
676 "\t# Test point [0.0, 0.0, 0.0]"
677 "\tif (cam.pointInsideFrustum([0.0, 0.0, 0.0])):\n"
678 "\t\t# Point is inside frustum !\n"
679 "\t\t# Do something useful !\n"
680 "\telse:\n"
681 "\t\t# Box is outside the frustum !\n"
682 )
683 {
684         MT_Point3 point;
685         if (PyVecTo(value, point))
686         {
687                 return PyInt_FromLong(PointInsideFrustum(point)); /* new ref */
688         }
689         
690         PyErr_SetString(PyExc_TypeError, "camera.pointInsideFrustum(point): KX_Camera, expected point argument.");
691         return NULL;
692 }
693
694 KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getCameraToWorld,
695 "getCameraToWorld() -> Matrix4x4\n"
696 "\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n"
697 "\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n"
698 )
699 {
700         return PyObjectFrom(GetCameraToWorld()); /* new ref */
701 }
702
703 KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getWorldToCamera,
704 "getWorldToCamera() -> Matrix4x4\n"
705 "\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n"
706 "\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n"
707 )
708 {
709         return PyObjectFrom(GetWorldToCamera()); /* new ref */
710 }
711
712 KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getProjectionMatrix,
713 "getProjectionMatrix() -> Matrix4x4\n"
714 "\treturns this camera's projection matrix, as a list of four lists of four values.\n\n"
715 "\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n"
716 )
717 {
718         ShowDeprecationWarning("getProjectionMatrix()", "the projection_matrix property");
719         return PyObjectFrom(GetProjectionMatrix()); /* new ref */
720 }
721
722 KX_PYMETHODDEF_DOC_O(KX_Camera, setProjectionMatrix,
723 "setProjectionMatrix(MT_Matrix4x4 m) -> None\n"
724 "\tSets this camera's projection matrix\n"
725 "\n"
726 "\tExample:\n"
727 "\timport GameLogic\n"
728 "\t# Set a perspective projection matrix\n"
729 "\tdef Perspective(left, right, bottom, top, near, far):\n"
730 "\t\tm = MT_Matrix4x4()\n"
731 "\t\tm[0][0] = m[0][2] = right - left\n"
732 "\t\tm[1][1] = m[1][2] = top - bottom\n"
733 "\t\tm[2][2] = m[2][3] = -far - near\n"
734 "\t\tm[3][2] = -1\n"
735 "\t\tm[3][3] = 0\n"
736 "\t\treturn m\n"
737 "\n"
738 "\t# Set an orthographic projection matrix\n"
739 "\tdef Orthographic(left, right, bottom, top, near, far):\n"
740 "\t\tm = MT_Matrix4x4()\n"
741 "\t\tm[0][0] = right - left\n"
742 "\t\tm[0][3] = -right - left\n"
743 "\t\tm[1][1] = top - bottom\n"
744 "\t\tm[1][3] = -top - bottom\n"
745 "\t\tm[2][2] = far - near\n"
746 "\t\tm[2][3] = -far - near\n"
747 "\t\tm[3][3] = 1\n"
748 "\t\treturn m\n"
749 "\n"
750 "\t# Set an isometric projection matrix\n"
751 "\tdef Isometric(left, right, bottom, top, near, far):\n"
752 "\t\tm = MT_Matrix4x4()\n"
753 "\t\tm[0][0] = m[0][2] = m[1][1] = 0.8660254037844386\n"
754 "\t\tm[1][0] = 0.25\n"
755 "\t\tm[1][2] = -0.25\n"
756 "\t\tm[3][3] = 1\n"
757 "\t\treturn m\n"
758 "\n"
759 "\t"
760 "\tco = GameLogic.getCurrentController()\n"
761 "\tcam = co.getOwner()\n"
762 "\tcam.setProjectionMatrix(Perspective(-1.0, 1.0, -1.0, 1.0, 0.1, 1))\n")
763 {
764         ShowDeprecationWarning("setProjectionMatrix(mat)", "the projection_matrix property");
765         
766         MT_Matrix4x4 mat;
767         if (!PyMatTo(value, mat))
768         {
769                 PyErr_SetString(PyExc_TypeError, "camera.setProjectionMatrix(matrix): KX_Camera, expected 4x4 list as matrix argument.");
770                 return NULL;
771         }
772         
773         SetProjectionMatrix(mat);
774         Py_RETURN_NONE;
775 }
776
777 KX_PYMETHODDEF_DOC_O(KX_Camera, enableViewport,
778 "enableViewport(viewport)\n"
779 "Sets this camera's viewport status\n"
780 )
781 {
782         ShowDeprecationWarning("enableViewport(bool)", "the useViewport property");
783         
784         int viewport = PyObject_IsTrue(value);
785         if (viewport == -1) {
786                 PyErr_SetString(PyExc_ValueError, "camera.enableViewport(bool): KX_Camera, expected True/False or 0/1");
787                 return NULL;
788         }
789         
790         if(viewport)
791                 EnableViewport(true);
792         else
793                 EnableViewport(false);
794         
795         Py_RETURN_NONE;
796 }
797
798 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, setViewport,
799 "setViewport(left, bottom, right, top)\n"
800 "Sets this camera's viewport\n")
801 {
802         int left, bottom, right, top;
803         if (!PyArg_ParseTuple(args,"iiii:setViewport",&left, &bottom, &right, &top))
804                 return NULL;
805         
806         SetViewport(left, bottom, right, top);
807         Py_RETURN_NONE;
808 }
809
810 KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, setOnTop,
811 "setOnTop()\n"
812 "Sets this camera's viewport on top\n")
813 {
814         class KX_Scene* scene = KX_GetActiveScene();
815         scene->SetCameraOnTop(this);
816         Py_RETURN_NONE;
817 }
818
819 PyObject* KX_Camera::pyattr_get_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
820 {
821         KX_Camera* self= static_cast<KX_Camera*>(self_v);
822         return PyBool_FromLong(self->m_camdata.m_perspective);
823 }
824
825 int KX_Camera::pyattr_set_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
826 {
827         KX_Camera* self= static_cast<KX_Camera*>(self_v);
828         int param = PyObject_IsTrue( value );
829         if (param == -1) {
830                 PyErr_SetString(PyExc_AttributeError, "camera.perspective = bool: KX_Camera, expected True/False or 0/1");
831                 return PY_SET_ATTR_FAIL;
832         }
833         
834         self->m_camdata.m_perspective= param;
835         return PY_SET_ATTR_SUCCESS;
836 }
837
838 PyObject* KX_Camera::pyattr_get_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
839 {
840         KX_Camera* self= static_cast<KX_Camera*>(self_v);
841         return PyFloat_FromDouble(self->m_camdata.m_lens);
842 }
843
844 int KX_Camera::pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
845 {
846         KX_Camera* self= static_cast<KX_Camera*>(self_v);
847         float param = PyFloat_AsDouble(value);
848         if (param == -1) {
849                 PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater then zero");
850                 return PY_SET_ATTR_FAIL;
851         }
852         
853         self->m_camdata.m_lens= param;
854         self->m_set_projection_matrix = false;
855         return PY_SET_ATTR_SUCCESS;
856 }
857
858 PyObject* KX_Camera::pyattr_get_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
859 {
860         KX_Camera* self= static_cast<KX_Camera*>(self_v);
861         return PyFloat_FromDouble(self->m_camdata.m_clipstart);
862 }
863
864 int KX_Camera::pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
865 {
866         KX_Camera* self= static_cast<KX_Camera*>(self_v);
867         float param = PyFloat_AsDouble(value);
868         if (param == -1) {
869                 PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater then zero");
870                 return PY_SET_ATTR_FAIL;
871         }
872         
873         self->m_camdata.m_clipstart= param;
874         self->m_set_projection_matrix = false;
875         return PY_SET_ATTR_SUCCESS;
876 }
877
878 PyObject* KX_Camera::pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
879 {
880         KX_Camera* self= static_cast<KX_Camera*>(self_v);
881         return PyFloat_FromDouble(self->m_camdata.m_clipend);
882 }
883
884 int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
885 {
886         KX_Camera* self= static_cast<KX_Camera*>(self_v);
887         float param = PyFloat_AsDouble(value);
888         if (param == -1) {
889                 PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater then zero");
890                 return PY_SET_ATTR_FAIL;
891         }
892         
893         self->m_camdata.m_clipend= param;
894         self->m_set_projection_matrix = false;
895         return PY_SET_ATTR_SUCCESS;
896 }
897
898
899 PyObject* KX_Camera::pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
900 {
901         KX_Camera* self= static_cast<KX_Camera*>(self_v);
902         return PyBool_FromLong(self->GetViewport());
903 }
904
905 int KX_Camera::pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
906 {
907         KX_Camera* self= static_cast<KX_Camera*>(self_v);
908         int param = PyObject_IsTrue( value );
909         if (param == -1) {
910                 PyErr_SetString(PyExc_AttributeError, "camera.useViewport = bool: KX_Camera, expected True or False");
911                 return PY_SET_ATTR_FAIL;
912         }
913         self->EnableViewport((bool)param);
914         return PY_SET_ATTR_SUCCESS;
915 }
916
917
918 PyObject* KX_Camera::pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
919 {
920         KX_Camera* self= static_cast<KX_Camera*>(self_v);
921         return PyObjectFrom(self->GetProjectionMatrix()); 
922 }
923
924 int KX_Camera::pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
925 {
926         KX_Camera* self= static_cast<KX_Camera*>(self_v);
927         MT_Matrix4x4 mat;
928         if (!PyMatTo(value, mat)) 
929                 return PY_SET_ATTR_FAIL;
930         
931         self->SetProjectionMatrix(mat);
932         return PY_SET_ATTR_SUCCESS;
933 }
934
935 PyObject* KX_Camera::pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
936 {
937         KX_Camera* self= static_cast<KX_Camera*>(self_v);
938         return PyObjectFrom(self->GetModelviewMatrix()); 
939 }
940
941 PyObject* KX_Camera::pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
942 {
943         KX_Camera* self= static_cast<KX_Camera*>(self_v);
944         return PyObjectFrom(self->GetCameraToWorld());
945 }
946
947 PyObject* KX_Camera::pyattr_get_world_to_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
948 {
949         KX_Camera* self= static_cast<KX_Camera*>(self_v);
950         return PyObjectFrom(self->GetWorldToCamera()); 
951 }
952
953
954 PyObject* KX_Camera::pyattr_get_INSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
955 {       return PyInt_FromLong(INSIDE); }
956 PyObject* KX_Camera::pyattr_get_OUTSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
957 {       return PyInt_FromLong(OUTSIDE); }
958 PyObject* KX_Camera::pyattr_get_INTERSECT(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
959 {       return PyInt_FromLong(INTERSECT); }
960
961
962 bool ConvertPythonToCamera(PyObject * value, KX_Camera **object, bool py_none_ok, const char *error_prefix)
963 {
964         if (value==NULL) {
965                 PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix);
966                 *object = NULL;
967                 return false;
968         }
969                 
970         if (value==Py_None) {
971                 *object = NULL;
972                 
973                 if (py_none_ok) {
974                         return true;
975                 } else {
976                         PyErr_Format(PyExc_TypeError, "%s, expected KX_Camera or a KX_Camera name, None is invalid", error_prefix);
977                         return false;
978                 }
979         }
980         
981         if (PyString_Check(value)) {
982                 STR_String value_str = PyString_AsString(value);
983                 *object = KX_GetActiveScene()->FindCamera(value_str);
984                 
985                 if (*object) {
986                         return true;
987                 } else {
988                         PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_Camera in this scene", error_prefix, PyString_AsString(value));
989                         return false;
990                 }
991         }
992         
993         if (PyObject_TypeCheck(value, &KX_Camera::Type)) {
994                 *object = static_cast<KX_Camera*>BGE_PROXY_REF(value);
995                 
996                 /* sets the error */
997                 if (*object==NULL) {
998                         PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix);
999                         return false;
1000                 }
1001                 
1002                 return true;
1003         }
1004         
1005         *object = NULL;
1006         
1007         if (py_none_ok) {
1008                 PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera, a string or None", error_prefix);
1009         } else {
1010                 PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera or a string", error_prefix);
1011         }
1012         
1013         return false;
1014 }
1015
1016 KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition,
1017 "getScreenPosition()\n"
1018 )
1019
1020 {
1021         MT_Vector3 vect;
1022         KX_GameObject *obj = NULL;
1023
1024         if (!PyVecTo(value, vect))
1025         {
1026                 if(ConvertPythonToGameObject(value, &obj, true, ""))
1027                 {
1028                         PyErr_Clear();
1029                         vect = MT_Vector3(obj->NodeGetWorldPosition());
1030                 }
1031                 else
1032                 {
1033                         PyErr_SetString(PyExc_TypeError, "Error in getScreenPosition. Expected a Vector3 or a KX_GameObject or a string for a name of a KX_GameObject");
1034                         return NULL;
1035                 }
1036         }
1037
1038         GLint viewport[4];
1039         GLdouble win[3];
1040         GLdouble modelmatrix[16];
1041         GLdouble projmatrix[16];
1042
1043         MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix();
1044         MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
1045
1046         m_modelmatrix.getValue(modelmatrix);
1047         m_projmatrix.getValue(projmatrix);
1048
1049         glGetIntegerv(GL_VIEWPORT, viewport);
1050
1051         gluProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]);
1052
1053         vect[0] =  (win[0] - viewport[0]) / viewport[2];
1054         vect[1] =  (win[1] - viewport[1]) / viewport[3];
1055
1056         vect[1] = 1.0 - vect[1]; //to follow Blender window coordinate system (Top-Down)
1057
1058         PyObject* ret = PyTuple_New(2);
1059         if(ret){
1060                 PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(vect[0]));
1061                 PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(vect[1]));
1062                 return ret;
1063         }
1064
1065         return NULL;
1066 }
1067
1068 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect,
1069 "getScreenVect()\n"
1070 )
1071 {
1072         double x,y;
1073         if (!PyArg_ParseTuple(args,"dd:getScreenVect",&x,&y))
1074                 return NULL;
1075
1076         y = 1.0 - y; //to follow Blender window coordinate system (Top-Down)
1077
1078         MT_Vector3 vect;
1079         MT_Point3 campos, screenpos;
1080
1081         GLint viewport[4];
1082         GLdouble win[3];
1083         GLdouble modelmatrix[16];
1084         GLdouble projmatrix[16];
1085
1086         MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix();
1087         MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
1088
1089         m_modelmatrix.getValue(modelmatrix);
1090         m_projmatrix.getValue(projmatrix);
1091
1092         glGetIntegerv(GL_VIEWPORT, viewport);
1093
1094         vect[0] = x * viewport[2];
1095         vect[1] = y * viewport[3];
1096
1097         vect[0] += viewport[0];
1098         vect[1] += viewport[1];
1099
1100         glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &vect[2]);
1101         gluUnProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]);
1102
1103         campos = this->GetCameraLocation();
1104         screenpos = MT_Point3(win[0], win[1], win[2]);
1105         vect = campos-screenpos;
1106
1107         vect.normalize();
1108         return PyObjectFrom(vect);
1109 }
1110
1111 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenRay,
1112 "getScreenRay()\n"
1113 )
1114 {
1115         MT_Vector3 vect;
1116         double x,y,dist;
1117         char *propName = NULL;
1118
1119         if (!PyArg_ParseTuple(args,"ddd|s:getScreenRay",&x,&y,&dist,&propName))
1120                 return NULL;
1121
1122         PyObject* argValue = PyTuple_New(2);
1123         if (argValue) {
1124                 PyTuple_SET_ITEM(argValue, 0, PyFloat_FromDouble(x));
1125                 PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(y));
1126         }
1127
1128         if(!PyVecTo(PygetScreenVect(argValue), vect))
1129         {
1130                 Py_DECREF(argValue);
1131                 PyErr_SetString(PyExc_TypeError,
1132                         "Error in getScreenRay. Invalid 2D coordinate. Expected a normalized 2D screen coordinate, a distance and an optional property argument");
1133                 return NULL;
1134         }
1135         Py_DECREF(argValue);
1136
1137         dist = -dist;
1138         vect += this->GetCameraLocation();
1139
1140         argValue = (propName?PyTuple_New(3):PyTuple_New(2));
1141         if (argValue) {
1142                 PyTuple_SET_ITEM(argValue, 0, PyObjectFrom(vect));
1143                 PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(dist));
1144                 if (propName)
1145                         PyTuple_SET_ITEM(argValue, 2, PyString_FromString(propName));
1146
1147                 PyObject* ret= this->PyrayCastTo(argValue,NULL);
1148                 Py_DECREF(argValue);
1149                 return ret;
1150         }
1151
1152         return NULL;
1153 }
1154