Blender V2.61 - r43446

KX_RaySensor.cpp

Go to the documentation of this file.
00001 /*
00002  * Cast a ray and feel for objects
00003  *
00004  *
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00022  * All rights reserved.
00023  *
00024  * The Original Code is: all of this file.
00025  *
00026  * Contributor(s): none yet.
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00036 #include "KX_RaySensor.h"
00037 #include "SCA_EventManager.h"
00038 #include "SCA_RandomEventManager.h"
00039 #include "SCA_LogicManager.h"
00040 #include "SCA_IObject.h"
00041 #include "KX_ClientObjectInfo.h"
00042 #include "KX_GameObject.h"
00043 #include "KX_Scene.h"
00044 #include "KX_RayCast.h"
00045 #include "KX_PyMath.h"
00046 #include "PHY_IPhysicsEnvironment.h"
00047 #include "KX_IPhysicsController.h"
00048 #include "PHY_IPhysicsController.h"
00049 #include "DNA_sensor_types.h"
00050 
00051 #include <stdio.h>
00052 
00053 
00054 KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr,
00055                     SCA_IObject* gameobj,
00056                     const STR_String& propname,
00057                     bool bFindMaterial,
00058                     bool bXRay,
00059                     double distance,
00060                     int axis,
00061                     KX_Scene* ketsjiScene)
00062             : SCA_ISensor(gameobj,eventmgr),
00063                     m_propertyname(propname),
00064                     m_bFindMaterial(bFindMaterial),
00065                     m_bXRay(bXRay),
00066                     m_distance(distance),
00067                     m_scene(ketsjiScene),
00068                     m_axis(axis)
00069 
00070                 
00071 {
00072     Init();
00073 }
00074 
00075 void KX_RaySensor::Init()
00076 {
00077     m_bTriggered = (m_invert)?true:false;
00078     m_rayHit = false;
00079     m_hitObject = NULL;
00080     m_reset = true;
00081 }
00082 
00083 KX_RaySensor::~KX_RaySensor() 
00084 {
00085     /* Nothing to be done here. */
00086 }
00087 
00088 
00089 
00090 CValue* KX_RaySensor::GetReplica()
00091 {
00092     KX_RaySensor* replica = new KX_RaySensor(*this);
00093     replica->ProcessReplica();
00094     replica->Init();
00095 
00096     return replica;
00097 }
00098 
00099 
00100 
00101 bool KX_RaySensor::IsPositiveTrigger()
00102 {
00103     bool result = m_rayHit;
00104 
00105     if (m_invert)
00106         result = !result;
00107     
00108     return result;
00109 }
00110 
00111 bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
00112 {
00113 
00114     KX_GameObject* hitKXObj = client->m_gameobject;
00115     bool bFound = false;
00116 
00117     if (m_propertyname.Length() == 0)
00118     {
00119         bFound = true;
00120     }
00121     else
00122     {
00123         if (m_bFindMaterial)
00124         {
00125             if (client->m_auxilary_info)
00126             {
00127                 bFound = (m_propertyname== ((char*)client->m_auxilary_info));
00128             }
00129         }
00130         else
00131         {
00132             bFound = hitKXObj->GetProperty(m_propertyname) != NULL;
00133         }
00134     }
00135 
00136     if (bFound)
00137     {
00138         m_rayHit = true;
00139         m_hitObject = hitKXObj;
00140         m_hitPosition[0] = result->m_hitPoint[0];
00141         m_hitPosition[1] = result->m_hitPoint[1];
00142         m_hitPosition[2] = result->m_hitPoint[2];
00143 
00144         m_hitNormal[0] = result->m_hitNormal[0];
00145         m_hitNormal[1] = result->m_hitNormal[1];
00146         m_hitNormal[2] = result->m_hitNormal[2];
00147             
00148     }
00149     // no multi-hit search yet
00150     return true;
00151 }
00152 
00153 /* this function is used to pre-filter the object before casting the ray on them.
00154    This is useful for "X-Ray" option when we want to see "through" unwanted object.
00155  */
00156 bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo* client)
00157 {
00158     if (client->m_type > KX_ClientObjectInfo::ACTOR)
00159     {
00160         // Unknown type of object, skip it.
00161         // Should not occur as the sensor objects are filtered in RayTest()
00162         printf("Invalid client type %d found ray casting\n", client->m_type);
00163         return false;
00164     }
00165     if (m_bXRay && m_propertyname.Length() != 0)
00166     {
00167         if (m_bFindMaterial)
00168         {
00169             // not quite correct: an object may have multiple material
00170             // should check all the material and not only the first one
00171             if (!client->m_auxilary_info || (m_propertyname != ((char*)client->m_auxilary_info)))
00172                 return false;
00173         }
00174         else
00175         {
00176             if (client->m_gameobject->GetProperty(m_propertyname) == NULL)
00177                 return false;
00178         }
00179     }
00180     return true;
00181 }
00182 
00183 bool KX_RaySensor::Evaluate()
00184 {
00185     bool result = false;
00186     bool reset = m_reset && m_level;
00187     m_rayHit = false; 
00188     m_hitObject = NULL;
00189     m_hitPosition[0] = 0;
00190     m_hitPosition[1] = 0;
00191     m_hitPosition[2] = 0;
00192 
00193     m_hitNormal[0] = 1;
00194     m_hitNormal[1] = 0;
00195     m_hitNormal[2] = 0;
00196     
00197     KX_GameObject* obj = (KX_GameObject*)GetParent();
00198     MT_Point3 frompoint = obj->NodeGetWorldPosition();
00199     MT_Matrix3x3 matje = obj->NodeGetWorldOrientation();
00200     MT_Matrix3x3 invmat = matje.inverse();
00201     
00202     MT_Vector3 todir;
00203     m_reset = false;
00204     switch (m_axis)
00205     {
00206     case SENS_RAY_X_AXIS: // X
00207         {
00208             todir[0] = invmat[0][0];
00209             todir[1] = invmat[0][1];
00210             todir[2] = invmat[0][2];
00211             break;
00212         }
00213     case SENS_RAY_Y_AXIS: // Y
00214         {
00215             todir[0] = invmat[1][0];
00216             todir[1] = invmat[1][1];
00217             todir[2] = invmat[1][2];
00218             break;
00219         }
00220     case SENS_RAY_Z_AXIS: // Z
00221         {
00222             todir[0] = invmat[2][0];
00223             todir[1] = invmat[2][1];
00224             todir[2] = invmat[2][2];
00225             break;
00226         }
00227     case SENS_RAY_NEG_X_AXIS: // -X
00228         {
00229             todir[0] = -invmat[0][0];
00230             todir[1] = -invmat[0][1];
00231             todir[2] = -invmat[0][2];
00232             break;
00233         }
00234     case SENS_RAY_NEG_Y_AXIS: // -Y
00235         {
00236             todir[0] = -invmat[1][0];
00237             todir[1] = -invmat[1][1];
00238             todir[2] = -invmat[1][2];
00239             break;
00240         }
00241     case SENS_RAY_NEG_Z_AXIS: // -Z
00242         {
00243             todir[0] = -invmat[2][0];
00244             todir[1] = -invmat[2][1];
00245             todir[2] = -invmat[2][2];
00246             break;
00247         }
00248     }
00249     todir.normalize();
00250     m_rayDirection[0] = todir[0];
00251     m_rayDirection[1] = todir[1];
00252     m_rayDirection[2] = todir[2];
00253 
00254     MT_Point3 topoint = frompoint + (m_distance) * todir;
00255     PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment();
00256 
00257     if (!pe)
00258     {
00259         std::cout << "WARNING: Ray sensor " << GetName() << ":  There is no physics environment!" << std::endl;
00260         std::cout << "         Check universe for malfunction." << std::endl;
00261         return false;
00262     } 
00263 
00264     KX_IPhysicsController *spc = obj->GetPhysicsController();
00265     KX_GameObject *parent = obj->GetParent();
00266     if (!spc && parent)
00267         spc = parent->GetPhysicsController();
00268     
00269     if (parent)
00270         parent->Release();
00271     
00272 
00273     PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment();
00274     
00275 
00276     KX_RayCast::Callback<KX_RaySensor> callback(this, spc);
00277     KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback);
00278 
00279     /* now pass this result to some controller */
00280 
00281     if (m_rayHit)
00282     {
00283         if (!m_bTriggered)
00284         {
00285             // notify logicsystem that ray is now hitting
00286             result = true;
00287             m_bTriggered = true;
00288         }
00289         else
00290         {
00291             // notify logicsystem that ray is STILL hitting ...
00292             result = false;
00293 
00294         }
00295     }
00296     else
00297     {
00298         if (m_bTriggered)
00299         {
00300             m_bTriggered = false;
00301             // notify logicsystem that ray JUST left the Object
00302             result = true;
00303         }
00304         else
00305         {
00306             result = false;
00307         }
00308 
00309     }
00310     if (reset)
00311         // force an event
00312         result = true;
00313 
00314     return result;
00315 }
00316 
00317 #ifdef WITH_PYTHON
00318 
00319 /* ------------------------------------------------------------------------- */
00320 /* Python functions                                                          */
00321 /* ------------------------------------------------------------------------- */
00322 
00323 /* Integration hooks ------------------------------------------------------- */
00324 PyTypeObject KX_RaySensor::Type = {
00325     PyVarObject_HEAD_INIT(NULL, 0)
00326     "KX_RaySensor",
00327     sizeof(PyObjectPlus_Proxy),
00328     0,
00329     py_base_dealloc,
00330     0,
00331     0,
00332     0,
00333     0,
00334     py_base_repr,
00335     0,0,0,0,0,0,0,0,0,
00336     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00337     0,0,0,0,0,0,0,
00338     Methods,
00339     0,
00340     0,
00341     &SCA_ISensor::Type,
00342     0,0,0,0,0,0,
00343     py_base_new
00344 
00345 };
00346 
00347 PyMethodDef KX_RaySensor::Methods[] = {
00348     {NULL,NULL} //Sentinel
00349 };
00350 
00351 PyAttributeDef KX_RaySensor::Attributes[] = {
00352     KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_RaySensor, m_bFindMaterial),
00353     KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_RaySensor, m_bXRay),
00354     KX_PYATTRIBUTE_FLOAT_RW("range", 0, 10000, KX_RaySensor, m_distance),
00355     KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_RaySensor, m_propertyname),
00356     KX_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RaySensor, m_axis),
00357     KX_PYATTRIBUTE_FLOAT_ARRAY_RO("hitPosition", KX_RaySensor, m_hitPosition, 3),
00358     KX_PYATTRIBUTE_FLOAT_ARRAY_RO("rayDirection", KX_RaySensor, m_rayDirection, 3),
00359     KX_PYATTRIBUTE_FLOAT_ARRAY_RO("hitNormal", KX_RaySensor, m_hitNormal, 3),
00360     KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_RaySensor, pyattr_get_hitobject),
00361     { NULL }    //Sentinel
00362 };
00363 
00364 PyObject* KX_RaySensor::pyattr_get_hitobject(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00365 {
00366     KX_RaySensor* self = static_cast<KX_RaySensor*>(self_v);
00367     if (self->m_hitObject)
00368         return self->m_hitObject->GetProxy();
00369 
00370     Py_RETURN_NONE;
00371 }
00372 
00373 #endif // WITH_PYTHON