patch 8235 8218 8211 added: various gameengine improvements, fixed windows project...
[blender.git] / source / gameengine / Ketsji / KX_Camera.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * Camera in the gameengine. Cameras are also used for views.
32  */
33  
34 #include "KX_Camera.h"
35 #include "KX_Scene.h"
36 #include "KX_PythonInit.h"
37 #include "KX_Python.h"
38 #include "KX_PyMath.h"
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 KX_Camera::KX_Camera(void* sgReplicationInfo,
44                                          SG_Callbacks callbacks,
45                                          const RAS_CameraData& camdata,
46                                          bool frustum_culling,
47                                          PyTypeObject *T)
48                                         :
49                                         KX_GameObject(sgReplicationInfo,callbacks,T),
50                                         m_camdata(camdata),
51                                         m_dirty(true),
52                                         m_normalized(false),
53                                         m_frustum_culling(frustum_culling && camdata.m_perspective),
54                                         m_set_projection_matrix(false),
55                                         m_set_frustum_center(false)
56 {
57         // setting a name would be nice...
58         m_name = "cam";
59         m_projection_matrix.setIdentity();
60         m_modelview_matrix.setIdentity();
61         SetProperty("camera",new CIntValue(1));
62 }
63
64
65 KX_Camera::~KX_Camera()
66 {
67 }       
68
69
70         
71 MT_Transform KX_Camera::GetWorldToCamera() const
72
73         MT_Transform camtrans;
74         camtrans.invert(MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation()));
75         
76         return camtrans;
77 }
78
79
80          
81 MT_Transform KX_Camera::GetCameraToWorld() const
82 {
83         return MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation());
84 }
85
86
87
88 void KX_Camera::CorrectLookUp(MT_Scalar speed)
89 {
90 }
91
92
93
94 const MT_Point3 KX_Camera::GetCameraLocation() const
95 {
96         /* this is the camera locatio in cam coords... */
97         //return m_trans1.getOrigin();
98         //return MT_Point3(0,0,0);   <-----
99         /* .... I want it in world coords */
100         //MT_Transform trans;
101         //trans.setBasis(NodeGetWorldOrientation());
102         
103         return NodeGetWorldPosition();          
104 }
105
106
107
108 /* I want the camera orientation as well. */
109 const MT_Quaternion KX_Camera::GetCameraOrientation() const
110 {
111         return NodeGetWorldOrientation().getRotation();
112 }
113
114
115
116 /**
117 * Sets the projection matrix that is used by the rasterizer.
118 */
119 void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat)
120 {
121         m_projection_matrix = mat;
122         m_dirty = true;
123         m_set_projection_matrix = true;
124         m_set_frustum_center = false;
125 }
126
127
128
129 /**
130 * Sets the modelview matrix that is used by the rasterizer.
131 */
132 void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat)
133 {
134         m_modelview_matrix = mat;
135         m_dirty = true;
136         m_set_frustum_center = false;
137 }
138
139
140
141 /**
142 * Gets the projection matrix that is used by the rasterizer.
143 */
144 const MT_Matrix4x4& KX_Camera::GetProjectionMatrix() const
145 {
146         return m_projection_matrix;
147 }
148
149
150
151 /**
152 * Gets the modelview matrix that is used by the rasterizer.
153 */
154 const MT_Matrix4x4& KX_Camera::GetModelviewMatrix() const
155 {
156         return m_modelview_matrix;
157 }
158
159
160 bool KX_Camera::hasValidProjectionMatrix() const
161 {
162         return m_set_projection_matrix;
163 }
164
165 void KX_Camera::InvalidateProjectionMatrix(bool valid)
166 {
167         m_set_projection_matrix = valid;
168 }
169
170
171 /*
172 * These getters retrieve the clip data and the focal length
173 */
174 float KX_Camera::GetLens() const
175 {
176         return m_camdata.m_lens;
177 }
178
179
180
181 float KX_Camera::GetCameraNear() const
182 {
183         return m_camdata.m_clipstart;
184 }
185
186
187
188 float KX_Camera::GetCameraFar() const
189 {
190         return m_camdata.m_clipend;
191 }
192
193
194
195 RAS_CameraData* KX_Camera::GetCameraData()
196 {
197         return &m_camdata; 
198 }
199
200 void KX_Camera::ExtractClipPlanes()
201 {
202         if (!m_dirty)
203                 return;
204
205         MT_Matrix4x4 m = m_projection_matrix * m_modelview_matrix;
206         // Left clip plane
207         m_planes[0] = m[3] + m[0];
208         // Right clip plane
209         m_planes[1] = m[3] - m[0];
210         // Top clip plane
211         m_planes[2] = m[3] - m[1];
212         // Bottom clip plane
213         m_planes[3] = m[3] + m[1];
214         // Near clip plane
215         m_planes[4] = m[3] + m[2];
216         // Far clip plane
217         m_planes[5] = m[3] - m[2];
218         
219         m_dirty = false;
220         m_normalized = false;
221 }
222
223 void KX_Camera::NormalizeClipPlanes()
224 {
225         if (m_normalized)
226                 return;
227         
228         for (unsigned int p = 0; p < 6; p++)
229         {
230                 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]);
231                 if (!MT_fuzzyZero(factor))
232                         m_planes[p] /= factor;
233         }
234         
235         m_normalized = true;
236 }
237
238 void KX_Camera::ExtractFrustumSphere()
239 {
240         if (m_set_frustum_center)
241                 return;
242
243         // The most extreme points on the near and far plane. (normalized device coords)
244         MT_Vector4 hnear(1., 1., 0., 1.), hfar(1., 1., 1., 1.);
245         MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix;
246         clip_camcs_matrix.invert();
247         
248         // Transform to hom camera local space
249         hnear = clip_camcs_matrix*hnear;
250         hfar = clip_camcs_matrix*hfar;
251         
252         // Tranform to 3d camera local space.
253         MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]);
254         MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]);
255         
256         // Compute center
257         m_frustum_center = MT_Point3(0., 0.,
258                 (nearpoint.dot(nearpoint) - farpoint.dot(farpoint))/(2.0*(m_camdata.m_clipend - m_camdata.m_clipstart)));
259         m_frustum_radius = m_frustum_center.distance(farpoint);
260         
261         // Transform to world space.
262         m_frustum_center = GetCameraToWorld()(m_frustum_center);
263         m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
264         
265         m_set_frustum_center = true;
266 }
267
268 bool KX_Camera::PointInsideFrustum(const MT_Point3& x)
269 {
270         ExtractClipPlanes();
271         
272         for( unsigned int i = 0; i < 6 ; i++ )
273         {
274                 if (m_planes[i][0]*x[0] + m_planes[i][1]*x[1] + m_planes[i][2]*x[2] + m_planes[i][3] < 0.)
275                         return false;
276         }
277         return true;
278 }
279
280 int KX_Camera::BoxInsideFrustum(const MT_Point3 *box)
281 {
282         ExtractClipPlanes();
283         
284         unsigned int insideCount = 0;
285         // 6 view frustum planes
286         for( unsigned int p = 0; p < 6 ; p++ )
287         {
288                 unsigned int behindCount = 0;
289                 // 8 box verticies.
290                 for (unsigned int v = 0; v < 8 ; v++)
291                 {
292                         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.)
293                                 behindCount++;
294                 }
295                 
296                 // 8 points behind this plane
297                 if (behindCount == 8)
298                         return OUTSIDE;
299
300                 // Every box vertex is on the front side of this plane
301                 if (!behindCount)
302                         insideCount++;
303         }
304         
305         // All box verticies are on the front side of all frustum planes.
306         if (insideCount == 6)
307                 return INSIDE;
308         
309         return INTERSECT;
310 }
311
312 int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius)
313 {
314         ExtractFrustumSphere();
315         if (center.distance2(m_frustum_center) > (radius + m_frustum_radius)*(radius + m_frustum_radius))
316                 return OUTSIDE;
317
318         unsigned int p;
319         ExtractClipPlanes();
320         NormalizeClipPlanes();
321                 
322         MT_Scalar distance;
323         int intersect = INSIDE;
324         // distance:  <-------- OUTSIDE -----|----- INTERSECT -----0----- INTERSECT -----|----- INSIDE -------->
325         //                                -radius                                      radius
326         for (p = 0; p < 6; p++)
327         {
328                 distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3];
329                 if (fabs(distance) <= radius)
330                         intersect = INTERSECT;
331                 else if (distance < -radius)
332                         return OUTSIDE;
333         }
334         
335         return intersect;
336 }
337
338 bool KX_Camera::GetFrustumCulling() const
339 {
340         return m_frustum_culling;
341 }
342  
343 void KX_Camera::EnableViewport(bool viewport)
344 {
345         m_camdata.m_viewport = viewport;
346 }
347
348 void KX_Camera::SetViewport(int left, int bottom, int right, int top)
349 {
350         m_camdata.m_viewportleft = left;
351         m_camdata.m_viewportbottom = bottom;
352         m_camdata.m_viewportright = right;
353         m_camdata.m_viewporttop = top;
354 }
355
356 bool KX_Camera::GetViewport() const
357 {
358         return m_camdata.m_viewport;
359 }
360
361 int KX_Camera::GetViewportLeft() const
362 {
363         return m_camdata.m_viewportleft;
364 }
365
366 int KX_Camera::GetViewportBottom() const
367 {
368         return m_camdata.m_viewportbottom;
369 }
370
371 int KX_Camera::GetViewportRight() const
372 {
373         return m_camdata.m_viewportright;
374 }
375
376 int KX_Camera::GetViewportTop() const
377 {
378         return m_camdata.m_viewporttop;
379 }
380
381 //----------------------------------------------------------------------------
382 //Python
383
384
385 PyMethodDef KX_Camera::Methods[] = {
386         KX_PYMETHODTABLE(KX_Camera, sphereInsideFrustum),
387         KX_PYMETHODTABLE(KX_Camera, boxInsideFrustum),
388         KX_PYMETHODTABLE(KX_Camera, pointInsideFrustum),
389         KX_PYMETHODTABLE(KX_Camera, getCameraToWorld),
390         KX_PYMETHODTABLE(KX_Camera, getWorldToCamera),
391         KX_PYMETHODTABLE(KX_Camera, getProjectionMatrix),
392         KX_PYMETHODTABLE(KX_Camera, setProjectionMatrix),
393         KX_PYMETHODTABLE(KX_Camera, enableViewport),
394         KX_PYMETHODTABLE(KX_Camera, setViewport),
395         KX_PYMETHODTABLE(KX_Camera, setOnTop),
396         
397         {NULL,NULL} //Sentinel
398 };
399
400 char KX_Camera::doc[] = "Module KX_Camera\n\n"
401 "Constants:\n"
402 "\tINSIDE\n"
403 "\tINTERSECT\n"
404 "\tOUTSIDE\n"
405 "Attributes:\n"
406 "\tlens -> float\n"
407 "\t\tThe camera's lens value\n"
408 "\tnear -> float\n"
409 "\t\tThe camera's near clip distance\n"
410 "\tfar -> float\n"
411 "\t\tThe camera's far clip distance\n"
412 "\tfrustum_culling -> bool\n"
413 "\t\tNon zero if this camera is frustum culling.\n"
414 "\tprojection_matrix -> [[float]]\n"
415 "\t\tThis camera's projection matrix.\n"
416 "\tmodelview_matrix -> [[float]] (read only)\n"
417 "\t\tThis camera's model view matrix.\n"
418 "\t\tRegenerated every frame from the camera's position and orientation.\n"
419 "\tcamera_to_world -> [[float]] (read only)\n"
420 "\t\tThis camera's camera to world transform.\n"
421 "\t\tRegenerated every frame from the camera's position and orientation.\n"
422 "\tworld_to_camera -> [[float]] (read only)\n"
423 "\t\tThis camera's world to camera transform.\n"
424 "\t\tRegenerated every frame from the camera's position and orientation.\n"
425 "\t\tThis is camera_to_world inverted.\n";
426
427 PyTypeObject KX_Camera::Type = {
428         PyObject_HEAD_INIT(&PyType_Type)
429                 0,
430                 "KX_Camera",
431                 sizeof(KX_Camera),
432                 0,
433                 PyDestructor,
434                 0,
435                 __getattr,
436                 __setattr,
437                 0, //&MyPyCompare,
438                 __repr,
439                 0, //&cvalue_as_number,
440                 0,
441                 0,
442                 0,
443                 0, 0, 0, 0, 0, 0,
444                 doc
445 };
446
447 PyParentObject KX_Camera::Parents[] = {
448         &KX_Camera::Type,
449         &KX_GameObject::Type,
450                 &SCA_IObject::Type,
451                 &CValue::Type,
452                 NULL
453 };
454
455 PyObject* KX_Camera::_getattr(const STR_String& attr)
456 {
457         if (attr == "INSIDE")
458                 return PyInt_FromLong(INSIDE); /* new ref */
459         if (attr == "OUTSIDE")
460                 return PyInt_FromLong(OUTSIDE); /* new ref */
461         if (attr == "INTERSECT")
462                 return PyInt_FromLong(INTERSECT); /* new ref */
463         
464         if (attr == "lens")
465                 return PyFloat_FromDouble(GetLens()); /* new ref */
466         if (attr == "near")
467                 return PyFloat_FromDouble(GetCameraNear()); /* new ref */
468         if (attr == "far")
469                 return PyFloat_FromDouble(GetCameraFar()); /* new ref */
470         if (attr == "frustum_culling")
471                 return PyInt_FromLong(m_frustum_culling); /* new ref */
472         if (attr == "perspective")
473                 return PyInt_FromLong(m_camdata.m_perspective); /* new ref */
474         if (attr == "projection_matrix")
475                 return PyObjectFrom(GetProjectionMatrix()); /* new ref */
476         if (attr == "modelview_matrix")
477                 return PyObjectFrom(GetModelviewMatrix()); /* new ref */
478         if (attr == "camera_to_world")
479                 return PyObjectFrom(GetCameraToWorld()); /* new ref */
480         if (attr == "world_to_camera")
481                 return PyObjectFrom(GetWorldToCamera()); /* new ref */
482         
483         _getattr_up(KX_GameObject);
484 }
485
486 int KX_Camera::_setattr(const STR_String &attr, PyObject *pyvalue)
487 {
488         if (PyInt_Check(pyvalue))
489         {
490                 if (attr == "frustum_culling")
491                 {
492                         m_frustum_culling = PyInt_AsLong(pyvalue);
493                         return 0;
494                 }
495                 
496                 if (attr == "perspective")
497                 {
498                         m_camdata.m_perspective = PyInt_AsLong(pyvalue);
499                         return 0;
500                 }
501         }
502         
503         if (PyFloat_Check(pyvalue))
504         {
505                 if (attr == "lens")
506                 {
507                         m_camdata.m_lens = PyFloat_AsDouble(pyvalue);
508                         m_set_projection_matrix = false;
509                         return 0;
510                 }
511                 if (attr == "near")
512                 {
513                         m_camdata.m_clipstart = PyFloat_AsDouble(pyvalue);
514                         m_set_projection_matrix = false;
515                         return 0;
516                 }
517                 if (attr == "far")
518                 {
519                         m_camdata.m_clipend = PyFloat_AsDouble(pyvalue);
520                         m_set_projection_matrix = false;
521                         return 0;
522                 }
523         }
524         
525         if (PyObject_IsMT_Matrix(pyvalue, 4))
526         {
527                 if (attr == "projection_matrix")
528                 {
529                         MT_Matrix4x4 mat;
530                         if (PyMatTo(pyvalue, mat))
531                         {
532                                 SetProjectionMatrix(mat);
533                                 return 0;
534                         }
535                         return 1;
536                 }
537         }
538         return KX_GameObject::_setattr(attr, pyvalue);
539 }
540
541 KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum,
542 "sphereInsideFrustum(center, radius) -> Integer\n"
543 "\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n"
544 "\tinside/outside/intersects this camera's viewing frustum.\n\n"
545 "\tcenter = the center of the sphere (in world coordinates.)\n"
546 "\tradius = the radius of the sphere\n\n"
547 "\tExample:\n"
548 "\timport GameLogic\n\n"
549 "\tco = GameLogic.getCurrentController()\n"
550 "\tcam = co.GetOwner()\n\n"
551 "\t# A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]\n"
552 "\tif (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):\n"
553 "\t\t# Sphere is inside frustum !\n"
554 "\t\t# Do something useful !\n"
555 "\telse:\n"
556 "\t\t# Sphere is outside frustum\n"
557 )
558 {
559         PyObject *pycenter;
560         float radius;
561         if (PyArg_ParseTuple(args, "Of", &pycenter, &radius))
562         {
563                 MT_Point3 center;
564                 if (PyVecTo(pycenter, center))
565                 {
566                         return PyInt_FromLong(SphereInsideFrustum(center, radius)); /* new ref */
567                 }
568         }
569
570         PyErr_SetString(PyExc_TypeError, "sphereInsideFrustum: Expected arguments: (center, radius)");
571         
572         Py_Return;
573 }
574
575 KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum,
576 "boxInsideFrustum(box) -> Integer\n"
577 "\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n"
578 "\tinside/outside/intersects this camera's viewing frustum.\n\n"
579 "\tbox = a list of the eight (8) corners of the box (in world coordinates.)\n\n"
580 "\tExample:\n"
581 "\timport GameLogic\n\n"
582 "\tco = GameLogic.getCurrentController()\n"
583 "\tcam = co.GetOwner()\n\n"
584 "\tbox = []\n"
585 "\tbox.append([-1.0, -1.0, -1.0])\n"
586 "\tbox.append([-1.0, -1.0,  1.0])\n"
587 "\tbox.append([-1.0,  1.0, -1.0])\n"
588 "\tbox.append([-1.0,  1.0,  1.0])\n"
589 "\tbox.append([ 1.0, -1.0, -1.0])\n"
590 "\tbox.append([ 1.0, -1.0,  1.0])\n"
591 "\tbox.append([ 1.0,  1.0, -1.0])\n"
592 "\tbox.append([ 1.0,  1.0,  1.0])\n\n"
593 "\tif (cam.boxInsideFrustum(box) != cam.OUTSIDE):\n"
594 "\t\t# Box is inside/intersects frustum !\n"
595 "\t\t# Do something useful !\n"
596 "\telse:\n"
597 "\t\t# Box is outside the frustum !\n"
598 )
599 {
600         PyObject *pybox;
601         if (PyArg_ParseTuple(args, "O", &pybox))
602         {
603                 unsigned int num_points = PySequence_Size(pybox);
604                 if (num_points != 8)
605                 {
606                         PyErr_Format(PyExc_TypeError, "boxInsideFrustum: Expected eight (8) points, got %d", num_points);
607                         return NULL;
608                 }
609                 
610                 MT_Point3 box[8];
611                 for (unsigned int p = 0; p < 8 ; p++)
612                 {
613                         PyObject *item = PySequence_GetItem(pybox, p); /* new ref */
614                         bool error = !PyVecTo(item, box[p]);
615                         Py_DECREF(item);
616                         if (error)
617                                 return NULL;
618                 }
619                 
620                 return PyInt_FromLong(BoxInsideFrustum(box)); /* new ref */
621         }
622         
623         PyErr_SetString(PyExc_TypeError, "boxInsideFrustum: Expected argument: list of points.");
624         return NULL;
625 }
626
627 KX_PYMETHODDEF_DOC(KX_Camera, pointInsideFrustum,
628 "pointInsideFrustum(point) -> Bool\n"
629 "\treturns 1 if the given point is inside this camera's viewing frustum.\n\n"
630 "\tpoint = The point to test (in world coordinates.)\n\n"
631 "\tExample:\n"
632 "\timport GameLogic\n\n"
633 "\tco = GameLogic.getCurrentController()\n"
634 "\tcam = co.GetOwner()\n\n"
635 "\t# Test point [0.0, 0.0, 0.0]"
636 "\tif (cam.pointInsideFrustum([0.0, 0.0, 0.0])):\n"
637 "\t\t# Point is inside frustum !\n"
638 "\t\t# Do something useful !\n"
639 "\telse:\n"
640 "\t\t# Box is outside the frustum !\n"
641 )
642 {
643         MT_Point3 point;
644         if (PyVecArgTo(args, point))
645         {
646                 return PyInt_FromLong(PointInsideFrustum(point)); /* new ref */
647         }
648         
649         PyErr_SetString(PyExc_TypeError, "pointInsideFrustum: Expected point argument.");
650         return NULL;
651 }
652
653 KX_PYMETHODDEF_DOC(KX_Camera, getCameraToWorld,
654 "getCameraToWorld() -> Matrix4x4\n"
655 "\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n"
656 "\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"
657 )
658 {
659         return PyObjectFrom(GetCameraToWorld()); /* new ref */
660 }
661
662 KX_PYMETHODDEF_DOC(KX_Camera, getWorldToCamera,
663 "getWorldToCamera() -> Matrix4x4\n"
664 "\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n"
665 "\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"
666 )
667 {
668         return PyObjectFrom(GetWorldToCamera()); /* new ref */
669 }
670
671 KX_PYMETHODDEF_DOC(KX_Camera, getProjectionMatrix,
672 "getProjectionMatrix() -> Matrix4x4\n"
673 "\treturns this camera's projection matrix, as a list of four lists of four values.\n\n"
674 "\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"
675 )
676 {
677         return PyObjectFrom(GetProjectionMatrix()); /* new ref */
678 }
679
680 KX_PYMETHODDEF_DOC(KX_Camera, setProjectionMatrix,
681 "setProjectionMatrix(MT_Matrix4x4 m) -> None\n"
682 "\tSets this camera's projection matrix\n"
683 "\n"
684 "\tExample:\n"
685 "\timport GameLogic\n"
686 "\t# Set a perspective projection matrix\n"
687 "\tdef Perspective(left, right, bottom, top, near, far):\n"
688 "\t\tm = MT_Matrix4x4()\n"
689 "\t\tm[0][0] = m[0][2] = right - left\n"
690 "\t\tm[1][1] = m[1][2] = top - bottom\n"
691 "\t\tm[2][2] = m[2][3] = -far - near\n"
692 "\t\tm[3][2] = -1\n"
693 "\t\tm[3][3] = 0\n"
694 "\t\treturn m\n"
695 "\n"
696 "\t# Set an orthographic projection matrix\n"
697 "\tdef Orthographic(left, right, bottom, top, near, far):\n"
698 "\t\tm = MT_Matrix4x4()\n"
699 "\t\tm[0][0] = right - left\n"
700 "\t\tm[0][3] = -right - left\n"
701 "\t\tm[1][1] = top - bottom\n"
702 "\t\tm[1][3] = -top - bottom\n"
703 "\t\tm[2][2] = far - near\n"
704 "\t\tm[2][3] = -far - near\n"
705 "\t\tm[3][3] = 1\n"
706 "\t\treturn m\n"
707 "\n"
708 "\t# Set an isometric projection matrix\n"
709 "\tdef Isometric(left, right, bottom, top, near, far):\n"
710 "\t\tm = MT_Matrix4x4()\n"
711 "\t\tm[0][0] = m[0][2] = m[1][1] = 0.8660254037844386\n"
712 "\t\tm[1][0] = 0.25\n"
713 "\t\tm[1][2] = -0.25\n"
714 "\t\tm[3][3] = 1\n"
715 "\t\treturn m\n"
716 "\n"
717 "\t"
718 "\tco = GameLogic.getCurrentController()\n"
719 "\tcam = co.getOwner()\n"
720 "\tcam.setProjectionMatrix(Perspective(-1.0, 1.0, -1.0, 1.0, 0.1, 1))\n")
721 {
722         PyObject *pymat;
723         if (PyArg_ParseTuple(args, "O", &pymat))
724         {
725                 MT_Matrix4x4 mat;
726                 if (PyMatTo(pymat, mat))
727                 {
728                         SetProjectionMatrix(mat);
729                         Py_Return;
730                 }
731         }
732
733         PyErr_SetString(PyExc_TypeError, "setProjectionMatrix: Expected 4x4 list as matrix argument.");
734         return NULL;
735 }
736
737 KX_PYMETHODDEF_DOC(KX_Camera, enableViewport,
738 "enableViewport(viewport)\n"
739 "Sets this camera's viewport status\n"
740 )
741 {
742         int viewport;
743         if (PyArg_ParseTuple(args,"i",&viewport))
744         {
745                 if(viewport)
746                         EnableViewport(true);
747                 else
748                         EnableViewport(false);
749         }
750         Py_Return;
751 }
752
753 KX_PYMETHODDEF_DOC(KX_Camera, setViewport,
754 "setViewport(left, bottom, right, top)\n"
755 "Sets this camera's viewport\n")
756 {
757         int left, bottom, right, top;
758         if (PyArg_ParseTuple(args,"iiii",&left, &bottom, &right, &top))
759         {
760                 SetViewport(left, bottom, right, top);
761         }
762         Py_Return;
763 }
764
765 KX_PYMETHODDEF_DOC(KX_Camera, setOnTop,
766 "setOnTop()\n"
767 "Sets this camera's viewport on top\n")
768 {
769         class KX_Scene* scene;
770         
771         scene = PHY_GetActiveScene();
772         MT_assert(scene);
773         scene->SetCameraOnTop(this);
774         Py_Return;
775 }