Fixes for MouseFocusSensor: (bug 1165)
authorKester Maddock <Christopher.Maddock.1@uni.massey.ac.nz>
Sat, 24 Apr 2004 06:36:55 +0000 (06:36 +0000)
committerKester Maddock <Christopher.Maddock.1@uni.massey.ac.nz>
Sat, 24 Apr 2004 06:36:55 +0000 (06:36 +0000)
1. Do the ray cast properly (from the near plane to the far clip plane)
2. Loop over invisible objects (sensors)

source/gameengine/Ketsji/KX_MouseFocusSensor.cpp

index 4e2a731c421c6d1ceeb53fb3c6e7124fef3a1410..6f6f86bd7820d47ac3ad0da58fcdc633abb2e1d9 100644 (file)
@@ -55,6 +55,7 @@
 #include "SM_Object.h"
 #include "SM_Scene.h"
 #include "SumoPhysicsEnvironment.h"
+#include "KX_SumoPhysicsController.h"
 
 /* ------------------------------------------------------------------------- */
 /* Native functions                                                          */
@@ -183,8 +184,8 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
         * _should_ be wrong! */
 
        /* old: */
-    float nearclip = 0.0;
-    float farclip = -1.0;
+       float nearclip = 0.0;
+       float farclip = 1.0;
 
        /*      build the from and to point in normalised device coordinates 
         *      Looks like normailized device coordinates are [-1,1] in x [-1,1] in y
@@ -193,17 +194,16 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
         *      The actual z coordinates used don't have to be exact just infront and 
         *      behind of the near and far clip planes.
         */ 
-       
        MT_Vector4 frompoint = MT_Vector4( 
                (2 * (m_x-x_lb) / width) - 1.0,
                1.0 - (2 * (m_y - y_lb) / height),
-               (nearclip + 3 * farclip) / (farclip - nearclip),
+               nearclip,
                1.0
        );
        MT_Vector4 topoint = MT_Vector4( 
                (2 * (m_x-x_lb) / width) - 1.0,
                1.0 - (2 * (m_y-y_lb) / height),
-               (3 * nearclip + farclip) / (farclip - nearclip),
+               farclip,
                1.0
        );
 
@@ -240,37 +240,83 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
        
        SumoPhysicsEnvironment *spe = dynamic_cast<SumoPhysicsEnvironment* > (m_kxscene->GetPhysicsEnvironment());
        SM_Scene *sumoScene = spe->GetSumoScene();
-
-       SM_Object* hitSMObj = sumoScene->rayTest(NULL, 
-                                               frompoint3,
-                                               topoint3,
-                                               resultpoint, 
-                                               resultnormal);
-       
-       /* all this casting makes me nervous... */
-       KX_ClientObjectInfo* client_info 
-               = ( hitSMObj ?
-                       (KX_ClientObjectInfo*) ((SM_Object*)hitSMObj)->getClientObject() :
-                       NULL);
-       KX_GameObject* hitKXObj = ( client_info ? 
-                                                               (KX_GameObject*)client_info->m_clientobject : 
-                                                               NULL);
+       KX_SumoPhysicsController *spc = dynamic_cast<KX_SumoPhysicsController*> (cam->GetPhysicsController());
+       SM_Object *sumoCam = spc?spc->GetSumoObject():NULL;
+       MT_Vector3 todir = topoint3 - frompoint3;
+       if (todir.dot(todir) < MT_EPSILON)
+               return false;
+       todir.normalize();
+
+       while (true)
+       {       
+               SM_Object* hitSMObj = sumoScene->rayTest(sumoCam, 
+                                                       frompoint3,
+                                                       topoint3,
+                                                       resultpoint, 
+                                                       resultnormal);
+               
+               if (!hitSMObj)
+                       return false;
+                       
+               /* all this casting makes me nervous... */
+               KX_ClientObjectInfo* client_info 
+                       = ( hitSMObj ?
+                               (KX_ClientObjectInfo*) hitSMObj->getClientObject() :
+                               NULL);
                
+               if (!client_info)
+               {
+                       std::cout<< "WARNING:  MouseOver sensor " << GetName() << " cannot sense SM_Object " << hitSMObj << " - no client info.\n" << std::endl;
+                       return false;
+               } 
        
-       /* Is this me? In the ray test, there are a lot of extra checks
-        * for aliasing artefacts from self-hits. That doesn't happen
-        * here, so a simple test suffices. Or does the camera also get
-        * self-hits? (No, and the raysensor shouldn't do it either, since
-        * self-hits are excluded by setting the correct ignore-object.)
-        * Hitspots now become valid. */
-       if (hitKXObj == thisObj)
-       {
-               m_hitPosition = resultpoint;
-               m_hitNormal = resultnormal;
-               res = true;
+               KX_GameObject* hitKXObj = (KX_GameObject*)client_info->m_clientobject;
+               
+               if (client_info->m_type > KX_ClientObjectInfo::ACTOR)
+               {
+                       // false hit
+                       KX_SumoPhysicsController *hitspc = dynamic_cast<KX_SumoPhysicsController *> (static_cast<KX_GameObject*> (hitKXObj) ->GetPhysicsController());
+                       if (hitspc)
+                       {
+                               /* We add 0.01 of fudge, so that if the margin && radius == 0., we don't endless loop. */
+                               MT_Scalar marg = 0.01 + hitspc->GetSumoObject()->getMargin();
+                               if (hitspc->GetSumoObject()->getShapeProps())
+                               {
+                                       marg += 2*hitspc->GetSumoObject()->getShapeProps()->m_radius;
+                               }
+                               
+                               /* Calculate the other side of this object */
+                               MT_Point3 hitObjPos;
+                               hitspc->GetWorldPosition(hitObjPos);
+                               MT_Vector3 hitvector = hitObjPos - resultpoint;
+                               if (hitvector.dot(hitvector) > MT_EPSILON)
+                               {
+                                       hitvector.normalize();
+                                       marg *= 2.*todir.dot(hitvector);
+                               }
+                               frompoint3 = resultpoint + marg * todir;
+                       } else {
+                               return false;
+                       }
+                       continue;
+               }
+               /* Is this me? In the ray test, there are a lot of extra checks
+               * for aliasing artefacts from self-hits. That doesn't happen
+               * here, so a simple test suffices. Or does the camera also get
+               * self-hits? (No, and the raysensor shouldn't do it either, since
+               * self-hits are excluded by setting the correct ignore-object.)
+               * Hitspots now become valid. */
+               if (hitKXObj == thisObj)
+               {
+                       m_hitPosition = resultpoint;
+                       m_hitNormal = resultnormal;
+                       return true;
+               }
+               
+               return false;
        }
 
-       return res;
+       return false;
 }
 
 /* ------------------------------------------------------------------------- */