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