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