Blender V2.61 - r43446

KX_Camera.cpp

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