Blender V2.61 - r43446
|
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