Blender  V2.59
KX_RayCast.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: KX_RayCast.cpp 35171 2011-02-25 13:35:59Z jesterking $
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  * KX_MouseFocusSensor determines mouse in/out/over events.
00029  */
00030 
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 
00039 #include "KX_RayCast.h"
00040 
00041 #include "MT_Point3.h"
00042 #include "MT_Vector3.h"
00043 
00044 #include "KX_IPhysicsController.h"
00045 #include "PHY_IPhysicsEnvironment.h"
00046 #include "PHY_IPhysicsController.h"
00047 
00048 KX_RayCast::KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal, bool faceUV)
00049         :PHY_IRayCastFilterCallback(dynamic_cast<PHY_IPhysicsController*>(ignoreController), faceNormal, faceUV) 
00050 {
00051 }
00052 
00053 void KX_RayCast::reportHit(PHY_RayCastResult* result)
00054 {
00055         m_hitFound = true;
00056         m_hitPoint.setValue((const float*)result->m_hitPoint);
00057         m_hitNormal.setValue((const float*)result->m_hitNormal);
00058         m_hitUVOK = result->m_hitUVOK;
00059         m_hitUV.setValue((const float*)result->m_hitUV);
00060         m_hitMesh = result->m_meshObject;
00061         m_hitPolygon = result->m_polygon;
00062 }
00063 
00064 bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback)
00065 {
00066         if(physics_environment==NULL) return false; /* prevents crashing in some cases */
00067         
00068         // Loops over all physics objects between frompoint and topoint,
00069         // calling callback.RayHit for each one.
00070         //
00071         // callback.RayHit should return true to stop looking, or false to continue.
00072         //
00073         // returns true if an object was found, false if not.
00074         
00075         MT_Point3 frompoint(_frompoint);
00076         const MT_Vector3 todir( (topoint - frompoint).safe_normalized() );
00077         MT_Point3 prevpoint(_frompoint+todir*(-1.f));
00078         
00079         PHY_IPhysicsController* hit_controller;
00080 
00081         while((hit_controller = physics_environment->rayTest(callback,
00082                         frompoint.x(),frompoint.y(),frompoint.z(),
00083                         topoint.x(),topoint.y(),topoint.z())) != NULL) 
00084         {
00085                 KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo());
00086                 
00087                 if (!info)
00088                 {
00089                         printf("no info!\n");
00090                         MT_assert(info && "Physics controller with no client object info");
00091                         break;
00092                 }
00093                 
00094                 // The biggest danger to endless loop, prevent this by checking that the
00095                 // hit point always progresses along the ray direction..
00096                 prevpoint -= callback.m_hitPoint;
00097                 if (prevpoint.length2() < MT_EPSILON)
00098                         break;
00099 
00100                 if (callback.RayHit(info))
00101                         // caller may decide to stop the loop and still cancel the hit
00102                         return callback.m_hitFound;
00103 
00104                 // Skip past the object and keep tracing.
00105                 // Note that retrieving in a single shot multiple hit points would be possible 
00106                 // but it would require some change in Bullet.
00107                 prevpoint = callback.m_hitPoint;
00108                 /* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */
00109                 MT_Scalar marg = 0.001 + hit_controller->GetMargin();
00110                 marg *= 2.f;
00111                 /* Calculate the other side of this object */
00112                 MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal));
00113                 if (h <= 0.01)
00114                         // the normal is almost orthogonal to the ray direction, cannot compute the other side
00115                         break;
00116                 marg /= h; 
00117                 frompoint = callback.m_hitPoint + marg * todir;
00118                 // verify that we are not passed the to point
00119                 if ((topoint - frompoint).dot(todir) < 0.f)
00120                         break;
00121         }
00122         return false;
00123 }
00124