Blender  V2.59
KX_Camera.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: KX_Camera.cpp 38273 2011-07-09 19:59:32Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  * Camera in the gameengine. Cameras are also used for views.
00029  */
00030 
00036 #include "GL/glew.h"
00037 #include "KX_Camera.h"
00038 #include "KX_Scene.h"
00039 #include "KX_PythonInit.h"
00040 #include "KX_Python.h"
00041 #include "KX_PyMath.h"
00042 KX_Camera::KX_Camera(void* sgReplicationInfo,
00043                                          SG_Callbacks callbacks,
00044                                          const RAS_CameraData& camdata,
00045                                          bool frustum_culling,
00046                                          bool delete_node)
00047                                         :
00048                                         KX_GameObject(sgReplicationInfo,callbacks),
00049                                         m_camdata(camdata),
00050                                         m_dirty(true),
00051                                         m_normalized(false),
00052                                         m_frustum_culling(frustum_culling),
00053                                         m_set_projection_matrix(false),
00054                                         m_set_frustum_center(false),
00055                                         m_delete_node(delete_node)
00056 {
00057         // setting a name would be nice...
00058         m_name = "cam";
00059         m_projection_matrix.setIdentity();
00060         m_modelview_matrix.setIdentity();
00061 }
00062 
00063 
00064 KX_Camera::~KX_Camera()
00065 {
00066         if (m_delete_node && m_pSGNode)
00067         {
00068                 // for shadow camera, avoids memleak
00069                 delete m_pSGNode;
00070                 m_pSGNode = NULL;
00071         }
00072 }       
00073 
00074 
00075 CValue* KX_Camera::GetReplica()
00076 {
00077         KX_Camera* replica = new KX_Camera(*this);
00078         
00079         // this will copy properties and so on...
00080         replica->ProcessReplica();
00081         
00082         return replica;
00083 }
00084 
00085 void KX_Camera::ProcessReplica()
00086 {
00087         KX_GameObject::ProcessReplica();
00088         // replicated camera are always registered in the scene
00089         m_delete_node = false;
00090 }
00091 
00092 MT_Transform KX_Camera::GetWorldToCamera() const
00093 { 
00094         MT_Transform camtrans;
00095         camtrans.invert(MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation()));
00096         
00097         return camtrans;
00098 }
00099 
00100 
00101          
00102 MT_Transform KX_Camera::GetCameraToWorld() const
00103 {
00104         return MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation());
00105 }
00106 
00107 
00108 
00109 void KX_Camera::CorrectLookUp(MT_Scalar speed)
00110 {
00111 }
00112 
00113 
00114 
00115 const MT_Point3 KX_Camera::GetCameraLocation() const
00116 {
00117         /* this is the camera locatio in cam coords... */
00118         //return m_trans1.getOrigin();
00119         //return MT_Point3(0,0,0);   <-----
00120         /* .... I want it in world coords */
00121         //MT_Transform trans;
00122         //trans.setBasis(NodeGetWorldOrientation());
00123         
00124         return NodeGetWorldPosition();          
00125 }
00126 
00127 
00128 
00129 /* I want the camera orientation as well. */
00130 const MT_Quaternion KX_Camera::GetCameraOrientation() const
00131 {
00132         return NodeGetWorldOrientation().getRotation();
00133 }
00134 
00135 
00136 
00140 void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat)
00141 {
00142         m_projection_matrix = mat;
00143         m_dirty = true;
00144         m_set_projection_matrix = true;
00145         m_set_frustum_center = false;
00146 }
00147 
00148 
00149 
00153 void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat)
00154 {
00155         m_modelview_matrix = mat;
00156         m_dirty = true;
00157         m_set_frustum_center = false;
00158 }
00159 
00160 
00161 
00165 const MT_Matrix4x4& KX_Camera::GetProjectionMatrix() const
00166 {
00167         return m_projection_matrix;
00168 }
00169 
00170 
00171 
00175 const MT_Matrix4x4& KX_Camera::GetModelviewMatrix() const
00176 {
00177         return m_modelview_matrix;
00178 }
00179 
00180 
00181 bool KX_Camera::hasValidProjectionMatrix() const
00182 {
00183         return m_set_projection_matrix;
00184 }
00185 
00186 void KX_Camera::InvalidateProjectionMatrix(bool valid)
00187 {
00188         m_set_projection_matrix = valid;
00189 }
00190 
00191 
00192 /*
00193 * These getters retrieve the clip data and the focal length
00194 */
00195 float KX_Camera::GetLens() const
00196 {
00197         return m_camdata.m_lens;
00198 }
00199 
00200 float KX_Camera::GetScale() const
00201 {
00202         return m_camdata.m_scale;
00203 }
00204 
00205 
00206 
00207 float KX_Camera::GetCameraNear() const
00208 {
00209         return m_camdata.m_clipstart;
00210 }
00211 
00212 
00213 
00214 float KX_Camera::GetCameraFar() const
00215 {
00216         return m_camdata.m_clipend;
00217 }
00218 
00219 float KX_Camera::GetFocalLength() const
00220 {
00221         return m_camdata.m_focallength;
00222 }
00223 
00224 
00225 
00226 RAS_CameraData* KX_Camera::GetCameraData()
00227 {
00228         return &m_camdata; 
00229 }
00230 
00231 void KX_Camera::ExtractClipPlanes()
00232 {
00233         if (!m_dirty)
00234                 return;
00235 
00236         MT_Matrix4x4 m = m_projection_matrix * m_modelview_matrix;
00237         // Left clip plane
00238         m_planes[0] = m[3] + m[0];
00239         // Right clip plane
00240         m_planes[1] = m[3] - m[0];
00241         // Top clip plane
00242         m_planes[2] = m[3] - m[1];
00243         // Bottom clip plane
00244         m_planes[3] = m[3] + m[1];
00245         // Near clip plane
00246         m_planes[4] = m[3] + m[2];
00247         // Far clip plane
00248         m_planes[5] = m[3] - m[2];
00249         
00250         m_dirty = false;
00251         m_normalized = false;
00252 }
00253 
00254 void KX_Camera::NormalizeClipPlanes()
00255 {
00256         if (m_normalized)
00257                 return;
00258         
00259         for (unsigned int p = 0; p < 6; p++)
00260         {
00261                 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]);
00262                 if (!MT_fuzzyZero(factor))
00263                         m_planes[p] /= factor;
00264         }
00265         
00266         m_normalized = true;
00267 }
00268 
00269 void KX_Camera::ExtractFrustumSphere()
00270 {
00271         if (m_set_frustum_center)
00272                 return;
00273 
00274     // compute sphere for the general case and not only symmetric frustum:
00275     // the mirror code in ImageRender can use very asymmetric frustum.
00276     // We will put the sphere center on the line that goes from origin to the center of the far clipping plane
00277     // This is the optimal position if the frustum is symmetric or very asymmetric and probably close
00278     // to optimal for the general case. The sphere center position is computed so that the distance to 
00279     // the near and far extreme frustum points are equal.
00280 
00281     // get the transformation matrix from device coordinate to camera coordinate
00282         MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix;
00283         clip_camcs_matrix.invert();
00284 
00285         if (m_projection_matrix[3][3] == MT_Scalar(0.0)) 
00286         {
00287                 // frustrum projection
00288                 // detect which of the corner of the far clipping plane is the farthest to the origin
00289                 MT_Vector4 nfar;    // far point in device normalized coordinate
00290                 MT_Point3 farpoint; // most extreme far point in camera coordinate
00291                 MT_Point3 nearpoint;// most extreme near point in camera coordinate
00292                 MT_Point3 farcenter(0.,0.,0.);// center of far cliping plane in camera coordinate
00293                 MT_Scalar F=-1.0, N; // square distance of far and near point to origin
00294                 MT_Scalar f, n;     // distance of far and near point to z axis. f is always > 0 but n can be < 0
00295                 MT_Scalar e, s;     // far and near clipping distance (<0)
00296                 MT_Scalar c;        // slope of center line = distance of far clipping center to z axis / far clipping distance
00297                 MT_Scalar z;        // projection of sphere center on z axis (<0)
00298                 // tmp value
00299                 MT_Vector4 npoint(1., 1., 1., 1.);
00300                 MT_Vector4 hpoint;
00301                 MT_Point3 point;
00302                 MT_Scalar len;
00303                 for (int i=0; i<4; i++)
00304                 {
00305                 hpoint = clip_camcs_matrix*npoint;
00306                         point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]);
00307                         len = point.dot(point);
00308                         if (len > F)
00309                         {
00310                                 nfar = npoint;
00311                                 farpoint = point;
00312                                 F = len;
00313                         }
00314                         // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane
00315                         len = npoint[0];
00316                         npoint[0] = -npoint[1];
00317                         npoint[1] = len;
00318                         farcenter += point;
00319                 }
00320                 // the far center is the average of the far clipping points
00321                 farcenter *= 0.25;
00322                 // the extreme near point is the opposite point on the near clipping plane
00323                 nfar.setValue(-nfar[0], -nfar[1], -1., 1.);
00324                 nfar = clip_camcs_matrix*nfar;
00325                 nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]);
00326                 // this is a frustrum projection
00327                 N = nearpoint.dot(nearpoint);
00328                 e = farpoint[2];
00329                 s = nearpoint[2];
00330                 // projection on XY plane for distance to axis computation
00331                 MT_Point2 farxy(farpoint[0], farpoint[1]);
00332                 // f is forced positive by construction
00333                 f = farxy.length();
00334                 // get corresponding point on the near plane
00335                 farxy *= s/e;
00336                 // this formula preserve the sign of n
00337                 n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length();
00338                 c = MT_Point2(farcenter[0], farcenter[1]).length()/e;
00339                 // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case
00340                 z = (F-N)/(2.0*(e-s+c*(f-n)));
00341                 m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z);
00342                 m_frustum_radius = m_frustum_center.distance(farpoint);
00343         } 
00344         else
00345         {
00346                 // orthographic projection
00347                 // The most extreme points on the near and far plane. (normalized device coords)
00348                 MT_Vector4 hnear(1., 1., 1., 1.), hfar(-1., -1., -1., 1.);
00349                 
00350                 // Transform to hom camera local space
00351                 hnear = clip_camcs_matrix*hnear;
00352                 hfar = clip_camcs_matrix*hfar;
00353                 
00354                 // Tranform to 3d camera local space.
00355                 MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]);
00356                 MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]);
00357                 
00358                 // just use mediant point
00359                 m_frustum_center = (farpoint + nearpoint)*0.5;
00360                 m_frustum_radius = m_frustum_center.distance(farpoint);
00361         }
00362         // Transform to world space.
00363         m_frustum_center = GetCameraToWorld()(m_frustum_center);
00364         m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
00365         
00366         m_set_frustum_center = true;
00367 }
00368 
00369 bool KX_Camera::PointInsideFrustum(const MT_Point3& x)
00370 {
00371         ExtractClipPlanes();
00372         
00373         for( unsigned int i = 0; i < 6 ; i++ )
00374         {
00375                 if (m_planes[i][0]*x[0] + m_planes[i][1]*x[1] + m_planes[i][2]*x[2] + m_planes[i][3] < 0.)
00376                         return false;
00377         }
00378         return true;
00379 }
00380 
00381 int KX_Camera::BoxInsideFrustum(const MT_Point3 *box)
00382 {
00383         ExtractClipPlanes();
00384         
00385         unsigned int insideCount = 0;
00386         // 6 view frustum planes
00387         for( unsigned int p = 0; p < 6 ; p++ )
00388         {
00389                 unsigned int behindCount = 0;
00390                 // 8 box vertices.
00391                 for (unsigned int v = 0; v < 8 ; v++)
00392                 {
00393                         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.)
00394                                 behindCount++;
00395                 }
00396                 
00397                 // 8 points behind this plane
00398                 if (behindCount == 8)
00399                         return OUTSIDE;
00400 
00401                 // Every box vertex is on the front side of this plane
00402                 if (!behindCount)
00403                         insideCount++;
00404         }
00405         
00406         // All box vertices are on the front side of all frustum planes.
00407         if (insideCount == 6)
00408                 return INSIDE;
00409         
00410         return INTERSECT;
00411 }
00412 
00413 int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius)
00414 {
00415         ExtractFrustumSphere();
00416         if (center.distance2(m_frustum_center) > (radius + m_frustum_radius)*(radius + m_frustum_radius))
00417                 return OUTSIDE;
00418 
00419         unsigned int p;
00420         ExtractClipPlanes();
00421         NormalizeClipPlanes();
00422                 
00423         MT_Scalar distance;
00424         int intersect = INSIDE;
00425         // distance:  <-------- OUTSIDE -----|----- INTERSECT -----0----- INTERSECT -----|----- INSIDE -------->
00426         //                                -radius                                      radius
00427         for (p = 0; p < 6; p++)
00428         {
00429                 distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3];
00430                 if (fabs(distance) <= radius)
00431                         intersect = INTERSECT;
00432                 else if (distance < -radius)
00433                         return OUTSIDE;
00434         }
00435         
00436         return intersect;
00437 }
00438 
00439 bool KX_Camera::GetFrustumCulling() const
00440 {
00441         return m_frustum_culling;
00442 }
00443  
00444 void KX_Camera::EnableViewport(bool viewport)
00445 {
00446         m_camdata.m_viewport = viewport;
00447 }
00448 
00449 void KX_Camera::SetViewport(int left, int bottom, int right, int top)
00450 {
00451         m_camdata.m_viewportleft = left;
00452         m_camdata.m_viewportbottom = bottom;
00453         m_camdata.m_viewportright = right;
00454         m_camdata.m_viewporttop = top;
00455 }
00456 
00457 bool KX_Camera::GetViewport() const
00458 {
00459         return m_camdata.m_viewport;
00460 }
00461 
00462 int KX_Camera::GetViewportLeft() const
00463 {
00464         return m_camdata.m_viewportleft;
00465 }
00466 
00467 int KX_Camera::GetViewportBottom() const
00468 {
00469         return m_camdata.m_viewportbottom;
00470 }
00471 
00472 int KX_Camera::GetViewportRight() const
00473 {
00474         return m_camdata.m_viewportright;
00475 }
00476 
00477 int KX_Camera::GetViewportTop() const
00478 {
00479         return m_camdata.m_viewporttop;
00480 }
00481 
00482 #ifdef WITH_PYTHON
00483 //----------------------------------------------------------------------------
00484 //Python
00485 
00486 
00487 PyMethodDef KX_Camera::Methods[] = {
00488         KX_PYMETHODTABLE(KX_Camera, sphereInsideFrustum),
00489         KX_PYMETHODTABLE_O(KX_Camera, boxInsideFrustum),
00490         KX_PYMETHODTABLE_O(KX_Camera, pointInsideFrustum),
00491         KX_PYMETHODTABLE_NOARGS(KX_Camera, getCameraToWorld),
00492         KX_PYMETHODTABLE_NOARGS(KX_Camera, getWorldToCamera),
00493         KX_PYMETHODTABLE(KX_Camera, setViewport),
00494         KX_PYMETHODTABLE_NOARGS(KX_Camera, setOnTop),
00495         KX_PYMETHODTABLE_O(KX_Camera, getScreenPosition),
00496         KX_PYMETHODTABLE(KX_Camera, getScreenVect),
00497         KX_PYMETHODTABLE(KX_Camera, getScreenRay),
00498         {NULL,NULL} //Sentinel
00499 };
00500 
00501 PyAttributeDef KX_Camera::Attributes[] = {
00502         
00503         KX_PYATTRIBUTE_BOOL_RW("frustum_culling", KX_Camera, m_frustum_culling),
00504         KX_PYATTRIBUTE_RW_FUNCTION("perspective", KX_Camera, pyattr_get_perspective, pyattr_set_perspective),
00505         
00506         KX_PYATTRIBUTE_RW_FUNCTION("lens",      KX_Camera,      pyattr_get_lens, pyattr_set_lens),
00507         KX_PYATTRIBUTE_RW_FUNCTION("ortho_scale",       KX_Camera,      pyattr_get_ortho_scale, pyattr_set_ortho_scale),
00508         KX_PYATTRIBUTE_RW_FUNCTION("near",      KX_Camera,      pyattr_get_near, pyattr_set_near),
00509         KX_PYATTRIBUTE_RW_FUNCTION("far",       KX_Camera,      pyattr_get_far,  pyattr_set_far),
00510         
00511         KX_PYATTRIBUTE_RW_FUNCTION("useViewport",       KX_Camera,      pyattr_get_use_viewport,  pyattr_set_use_viewport),
00512         
00513         KX_PYATTRIBUTE_RW_FUNCTION("projection_matrix", KX_Camera,      pyattr_get_projection_matrix, pyattr_set_projection_matrix),
00514         KX_PYATTRIBUTE_RO_FUNCTION("modelview_matrix",  KX_Camera,      pyattr_get_modelview_matrix),
00515         KX_PYATTRIBUTE_RO_FUNCTION("camera_to_world",   KX_Camera,      pyattr_get_camera_to_world),
00516         KX_PYATTRIBUTE_RO_FUNCTION("world_to_camera",   KX_Camera,      pyattr_get_world_to_camera),
00517         
00518         /* Grrr, functions for constants? */
00519         KX_PYATTRIBUTE_RO_FUNCTION("INSIDE",    KX_Camera, pyattr_get_INSIDE),
00520         KX_PYATTRIBUTE_RO_FUNCTION("OUTSIDE",   KX_Camera, pyattr_get_OUTSIDE),
00521         KX_PYATTRIBUTE_RO_FUNCTION("INTERSECT", KX_Camera, pyattr_get_INTERSECT),
00522         
00523         { NULL }        //Sentinel
00524 };
00525 
00526 PyTypeObject KX_Camera::Type = {
00527         PyVarObject_HEAD_INIT(NULL, 0)
00528         "KX_Camera",
00529         sizeof(PyObjectPlus_Proxy),
00530         0,
00531         py_base_dealloc,
00532         0,
00533         0,
00534         0,
00535         0,
00536         py_base_repr,
00537         0,
00538         &KX_GameObject::Sequence,
00539         &KX_GameObject::Mapping,
00540         0,0,0,
00541         NULL,
00542         NULL,
00543         0,
00544         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00545         0,0,0,0,0,0,0,
00546         Methods,
00547         0,
00548         0,
00549         &KX_GameObject::Type,
00550         0,0,0,0,0,0,
00551         py_base_new
00552 };
00553 
00554 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, sphereInsideFrustum,
00555 "sphereInsideFrustum(center, radius) -> Integer\n"
00556 "\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n"
00557 "\tinside/outside/intersects this camera's viewing frustum.\n\n"
00558 "\tcenter = the center of the sphere (in world coordinates.)\n"
00559 "\tradius = the radius of the sphere\n\n"
00560 "\tExample:\n"
00561 "\timport bge.logic\n\n"
00562 "\tco = bge.logic.getCurrentController()\n"
00563 "\tcam = co.GetOwner()\n\n"
00564 "\t# A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]\n"
00565 "\tif (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):\n"
00566 "\t\t# Sphere is inside frustum !\n"
00567 "\t\t# Do something useful !\n"
00568 "\telse:\n"
00569 "\t\t# Sphere is outside frustum\n"
00570 )
00571 {
00572         PyObject *pycenter;
00573         float radius;
00574         if (PyArg_ParseTuple(args, "Of:sphereInsideFrustum", &pycenter, &radius))
00575         {
00576                 MT_Point3 center;
00577                 if (PyVecTo(pycenter, center))
00578                 {
00579                         return PyLong_FromSsize_t(SphereInsideFrustum(center, radius)); /* new ref */
00580                 }
00581         }
00582 
00583         PyErr_SetString(PyExc_TypeError, "camera.sphereInsideFrustum(center, radius): KX_Camera, expected arguments: (center, radius)");
00584         
00585         return NULL;
00586 }
00587 
00588 KX_PYMETHODDEF_DOC_O(KX_Camera, boxInsideFrustum,
00589 "boxInsideFrustum(box) -> Integer\n"
00590 "\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n"
00591 "\tinside/outside/intersects this camera's viewing frustum.\n\n"
00592 "\tbox = a list of the eight (8) corners of the box (in world coordinates.)\n\n"
00593 "\tExample:\n"
00594 "\timport bge.logic\n\n"
00595 "\tco = bge.logic.getCurrentController()\n"
00596 "\tcam = co.GetOwner()\n\n"
00597 "\tbox = []\n"
00598 "\tbox.append([-1.0, -1.0, -1.0])\n"
00599 "\tbox.append([-1.0, -1.0,  1.0])\n"
00600 "\tbox.append([-1.0,  1.0, -1.0])\n"
00601 "\tbox.append([-1.0,  1.0,  1.0])\n"
00602 "\tbox.append([ 1.0, -1.0, -1.0])\n"
00603 "\tbox.append([ 1.0, -1.0,  1.0])\n"
00604 "\tbox.append([ 1.0,  1.0, -1.0])\n"
00605 "\tbox.append([ 1.0,  1.0,  1.0])\n\n"
00606 "\tif (cam.boxInsideFrustum(box) != cam.OUTSIDE):\n"
00607 "\t\t# Box is inside/intersects frustum !\n"
00608 "\t\t# Do something useful !\n"
00609 "\telse:\n"
00610 "\t\t# Box is outside the frustum !\n"
00611 )
00612 {
00613         unsigned int num_points = PySequence_Size(value);
00614         if (num_points != 8)
00615         {
00616                 PyErr_Format(PyExc_TypeError, "camera.boxInsideFrustum(box): KX_Camera, expected eight (8) points, got %d", num_points);
00617                 return NULL;
00618         }
00619         
00620         MT_Point3 box[8];
00621         for (unsigned int p = 0; p < 8 ; p++)
00622         {
00623                 PyObject *item = PySequence_GetItem(value, p); /* new ref */
00624                 bool error = !PyVecTo(item, box[p]);
00625                 Py_DECREF(item);
00626                 if (error)
00627                         return NULL;
00628         }
00629         
00630         return PyLong_FromSsize_t(BoxInsideFrustum(box)); /* new ref */
00631 }
00632 
00633 KX_PYMETHODDEF_DOC_O(KX_Camera, pointInsideFrustum,
00634 "pointInsideFrustum(point) -> Bool\n"
00635 "\treturns 1 if the given point is inside this camera's viewing frustum.\n\n"
00636 "\tpoint = The point to test (in world coordinates.)\n\n"
00637 "\tExample:\n"
00638 "\timport bge.logic\n\n"
00639 "\tco = bge.logic.getCurrentController()\n"
00640 "\tcam = co.GetOwner()\n\n"
00641 "\t# Test point [0.0, 0.0, 0.0]"
00642 "\tif (cam.pointInsideFrustum([0.0, 0.0, 0.0])):\n"
00643 "\t\t# Point is inside frustum !\n"
00644 "\t\t# Do something useful !\n"
00645 "\telse:\n"
00646 "\t\t# Box is outside the frustum !\n"
00647 )
00648 {
00649         MT_Point3 point;
00650         if (PyVecTo(value, point))
00651         {
00652                 return PyLong_FromSsize_t(PointInsideFrustum(point)); /* new ref */
00653         }
00654         
00655         PyErr_SetString(PyExc_TypeError, "camera.pointInsideFrustum(point): KX_Camera, expected point argument.");
00656         return NULL;
00657 }
00658 
00659 KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getCameraToWorld,
00660 "getCameraToWorld() -> Matrix4x4\n"
00661 "\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n"
00662 "\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"
00663 )
00664 {
00665         return PyObjectFrom(GetCameraToWorld()); /* new ref */
00666 }
00667 
00668 KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getWorldToCamera,
00669 "getWorldToCamera() -> Matrix4x4\n"
00670 "\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n"
00671 "\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"
00672 )
00673 {
00674         return PyObjectFrom(GetWorldToCamera()); /* new ref */
00675 }
00676 
00677 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, setViewport,
00678 "setViewport(left, bottom, right, top)\n"
00679 "Sets this camera's viewport\n")
00680 {
00681         int left, bottom, right, top;
00682         if (!PyArg_ParseTuple(args,"iiii:setViewport",&left, &bottom, &right, &top))
00683                 return NULL;
00684         
00685         SetViewport(left, bottom, right, top);
00686         Py_RETURN_NONE;
00687 }
00688 
00689 KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, setOnTop,
00690 "setOnTop()\n"
00691 "Sets this camera's viewport on top\n")
00692 {
00693         class KX_Scene* scene = KX_GetActiveScene();
00694         scene->SetCameraOnTop(this);
00695         Py_RETURN_NONE;
00696 }
00697 
00698 PyObject* KX_Camera::pyattr_get_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00699 {
00700         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00701         return PyBool_FromLong(self->m_camdata.m_perspective);
00702 }
00703 
00704 int KX_Camera::pyattr_set_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00705 {
00706         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00707         int param = PyObject_IsTrue( value );
00708         if (param == -1) {
00709                 PyErr_SetString(PyExc_AttributeError, "camera.perspective = bool: KX_Camera, expected True/False or 0/1");
00710                 return PY_SET_ATTR_FAIL;
00711         }
00712         
00713         self->m_camdata.m_perspective= param;
00714         self->InvalidateProjectionMatrix();
00715         return PY_SET_ATTR_SUCCESS;
00716 }
00717 
00718 PyObject* KX_Camera::pyattr_get_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00719 {
00720         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00721         return PyFloat_FromDouble(self->m_camdata.m_lens);
00722 }
00723 
00724 int KX_Camera::pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00725 {
00726         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00727         float param = PyFloat_AsDouble(value);
00728         if (param == -1) {
00729                 PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater then zero");
00730                 return PY_SET_ATTR_FAIL;
00731         }
00732         
00733         self->m_camdata.m_lens= param;
00734         self->m_set_projection_matrix = false;
00735         return PY_SET_ATTR_SUCCESS;
00736 }
00737 
00738 PyObject* KX_Camera::pyattr_get_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00739 {
00740         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00741         return PyFloat_FromDouble(self->m_camdata.m_scale);
00742 }
00743 
00744 int KX_Camera::pyattr_set_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00745 {
00746         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00747         float param = PyFloat_AsDouble(value);
00748         if (param == -1) {
00749                 PyErr_SetString(PyExc_AttributeError, "camera.ortho_scale = float: KX_Camera, expected a float greater then zero");
00750                 return PY_SET_ATTR_FAIL;
00751         }
00752         
00753         self->m_camdata.m_scale= param;
00754         self->m_set_projection_matrix = false;
00755         return PY_SET_ATTR_SUCCESS;
00756 }
00757 
00758 PyObject* KX_Camera::pyattr_get_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00759 {
00760         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00761         return PyFloat_FromDouble(self->m_camdata.m_clipstart);
00762 }
00763 
00764 int KX_Camera::pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00765 {
00766         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00767         float param = PyFloat_AsDouble(value);
00768         if (param == -1) {
00769                 PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater then zero");
00770                 return PY_SET_ATTR_FAIL;
00771         }
00772         
00773         self->m_camdata.m_clipstart= param;
00774         self->m_set_projection_matrix = false;
00775         return PY_SET_ATTR_SUCCESS;
00776 }
00777 
00778 PyObject* KX_Camera::pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00779 {
00780         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00781         return PyFloat_FromDouble(self->m_camdata.m_clipend);
00782 }
00783 
00784 int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00785 {
00786         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00787         float param = PyFloat_AsDouble(value);
00788         if (param == -1) {
00789                 PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater then zero");
00790                 return PY_SET_ATTR_FAIL;
00791         }
00792         
00793         self->m_camdata.m_clipend= param;
00794         self->m_set_projection_matrix = false;
00795         return PY_SET_ATTR_SUCCESS;
00796 }
00797 
00798 
00799 PyObject* KX_Camera::pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00800 {
00801         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00802         return PyBool_FromLong(self->GetViewport());
00803 }
00804 
00805 int KX_Camera::pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00806 {
00807         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00808         int param = PyObject_IsTrue( value );
00809         if (param == -1) {
00810                 PyErr_SetString(PyExc_AttributeError, "camera.useViewport = bool: KX_Camera, expected True or False");
00811                 return PY_SET_ATTR_FAIL;
00812         }
00813         self->EnableViewport((bool)param);
00814         return PY_SET_ATTR_SUCCESS;
00815 }
00816 
00817 
00818 PyObject* KX_Camera::pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00819 {
00820         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00821         return PyObjectFrom(self->GetProjectionMatrix()); 
00822 }
00823 
00824 int KX_Camera::pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00825 {
00826         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00827         MT_Matrix4x4 mat;
00828         if (!PyMatTo(value, mat)) 
00829                 return PY_SET_ATTR_FAIL;
00830         
00831         self->SetProjectionMatrix(mat);
00832         return PY_SET_ATTR_SUCCESS;
00833 }
00834 
00835 PyObject* KX_Camera::pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00836 {
00837         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00838         return PyObjectFrom(self->GetModelviewMatrix()); 
00839 }
00840 
00841 PyObject* KX_Camera::pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00842 {
00843         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00844         return PyObjectFrom(self->GetCameraToWorld());
00845 }
00846 
00847 PyObject* KX_Camera::pyattr_get_world_to_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00848 {
00849         KX_Camera* self= static_cast<KX_Camera*>(self_v);
00850         return PyObjectFrom(self->GetWorldToCamera()); 
00851 }
00852 
00853 
00854 PyObject* KX_Camera::pyattr_get_INSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00855 {       return PyLong_FromSsize_t(INSIDE); }
00856 PyObject* KX_Camera::pyattr_get_OUTSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00857 {       return PyLong_FromSsize_t(OUTSIDE); }
00858 PyObject* KX_Camera::pyattr_get_INTERSECT(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00859 {       return PyLong_FromSsize_t(INTERSECT); }
00860 
00861 
00862 bool ConvertPythonToCamera(PyObject * value, KX_Camera **object, bool py_none_ok, const char *error_prefix)
00863 {
00864         if (value==NULL) {
00865                 PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix);
00866                 *object = NULL;
00867                 return false;
00868         }
00869                 
00870         if (value==Py_None) {
00871                 *object = NULL;
00872                 
00873                 if (py_none_ok) {
00874                         return true;
00875                 } else {
00876                         PyErr_Format(PyExc_TypeError, "%s, expected KX_Camera or a KX_Camera name, None is invalid", error_prefix);
00877                         return false;
00878                 }
00879         }
00880         
00881         if (PyUnicode_Check(value)) {
00882                 STR_String value_str = _PyUnicode_AsString(value);
00883                 *object = KX_GetActiveScene()->FindCamera(value_str);
00884                 
00885                 if (*object) {
00886                         return true;
00887                 } else {
00888                         PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_Camera in this scene", error_prefix, _PyUnicode_AsString(value));
00889                         return false;
00890                 }
00891         }
00892         
00893         if (PyObject_TypeCheck(value, &KX_Camera::Type)) {
00894                 *object = static_cast<KX_Camera*>BGE_PROXY_REF(value);
00895                 
00896                 /* sets the error */
00897                 if (*object==NULL) {
00898                         PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix);
00899                         return false;
00900                 }
00901                 
00902                 return true;
00903         }
00904         
00905         *object = NULL;
00906         
00907         if (py_none_ok) {
00908                 PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera, a string or None", error_prefix);
00909         } else {
00910                 PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera or a string", error_prefix);
00911         }
00912         
00913         return false;
00914 }
00915 
00916 KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition,
00917 "getScreenPosition()\n"
00918 )
00919 
00920 {
00921         MT_Vector3 vect;
00922         KX_GameObject *obj = NULL;
00923 
00924         if (!PyVecTo(value, vect))
00925         {
00926                 PyErr_Clear();
00927 
00928                 if(ConvertPythonToGameObject(value, &obj, true, ""))
00929                 {
00930                         PyErr_Clear();
00931                         vect = MT_Vector3(obj->NodeGetWorldPosition());
00932                 }
00933                 else
00934                 {
00935                         PyErr_SetString(PyExc_TypeError, "Error in getScreenPosition. Expected a Vector3 or a KX_GameObject or a string for a name of a KX_GameObject");
00936                         return NULL;
00937                 }
00938         }
00939 
00940         GLint viewport[4];
00941         GLdouble win[3];
00942         GLdouble modelmatrix[16];
00943         GLdouble projmatrix[16];
00944 
00945         MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix();
00946         MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
00947 
00948         m_modelmatrix.getValue(modelmatrix);
00949         m_projmatrix.getValue(projmatrix);
00950 
00951         glGetIntegerv(GL_VIEWPORT, viewport);
00952 
00953         gluProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]);
00954 
00955         vect[0] =  (win[0] - viewport[0]) / viewport[2];
00956         vect[1] =  (win[1] - viewport[1]) / viewport[3];
00957 
00958         vect[1] = 1.0 - vect[1]; //to follow Blender window coordinate system (Top-Down)
00959 
00960         PyObject* ret = PyTuple_New(2);
00961         if(ret){
00962                 PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(vect[0]));
00963                 PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(vect[1]));
00964                 return ret;
00965         }
00966 
00967         return NULL;
00968 }
00969 
00970 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect,
00971 "getScreenVect()\n"
00972 )
00973 {
00974         double x,y;
00975         if (!PyArg_ParseTuple(args,"dd:getScreenVect",&x,&y))
00976                 return NULL;
00977 
00978         y = 1.0 - y; //to follow Blender window coordinate system (Top-Down)
00979 
00980         MT_Vector3 vect;
00981         MT_Point3 campos, screenpos;
00982 
00983         GLint viewport[4];
00984         GLdouble win[3];
00985         GLdouble modelmatrix[16];
00986         GLdouble projmatrix[16];
00987 
00988         MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix();
00989         MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix();
00990 
00991         m_modelmatrix.getValue(modelmatrix);
00992         m_projmatrix.getValue(projmatrix);
00993 
00994         glGetIntegerv(GL_VIEWPORT, viewport);
00995 
00996         vect[0] = x * viewport[2];
00997         vect[1] = y * viewport[3];
00998 
00999         vect[0] += viewport[0];
01000         vect[1] += viewport[1];
01001 
01002         glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &vect[2]);
01003         gluUnProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]);
01004 
01005         campos = this->GetCameraLocation();
01006         screenpos = MT_Point3(win[0], win[1], win[2]);
01007         vect = campos-screenpos;
01008 
01009         vect.normalize();
01010         return PyObjectFrom(vect);
01011 }
01012 
01013 KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenRay,
01014 "getScreenRay()\n"
01015 )
01016 {
01017         MT_Vector3 vect;
01018         double x,y,dist;
01019         char *propName = NULL;
01020 
01021         if (!PyArg_ParseTuple(args,"ddd|s:getScreenRay",&x,&y,&dist,&propName))
01022                 return NULL;
01023 
01024         PyObject* argValue = PyTuple_New(2);
01025         PyTuple_SET_ITEM(argValue, 0, PyFloat_FromDouble(x));
01026         PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(y));
01027 
01028         if(!PyVecTo(PygetScreenVect(argValue), vect))
01029         {
01030                 Py_DECREF(argValue);
01031                 PyErr_SetString(PyExc_TypeError,
01032                         "Error in getScreenRay. Invalid 2D coordinate. Expected a normalized 2D screen coordinate, a distance and an optional property argument");
01033                 return NULL;
01034         }
01035         Py_DECREF(argValue);
01036 
01037         dist = -dist;
01038         vect += this->GetCameraLocation();
01039 
01040         argValue = (propName?PyTuple_New(3):PyTuple_New(2));
01041         if (argValue) {
01042                 PyTuple_SET_ITEM(argValue, 0, PyObjectFrom(vect));
01043                 PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(dist));
01044                 if (propName)
01045                         PyTuple_SET_ITEM(argValue, 2, PyUnicode_FromString(propName));
01046 
01047                 PyObject* ret= this->PyrayCastTo(argValue,NULL);
01048                 Py_DECREF(argValue);
01049                 return ret;
01050         }
01051 
01052         return NULL;
01053 }
01054 #endif