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