BGE : Collision mask support in raycast + and raycast cleanup.
authorPorteries Tristan <republicthunderbolt9@gmail.com>
Wed, 7 Oct 2015 20:14:43 +0000 (22:14 +0200)
committerPorteries Tristan <republicthunderbolt9@gmail.com>
Wed, 7 Oct 2015 20:14:43 +0000 (22:14 +0200)
I have removed the m_pHitObject, m_xray and m_testPropName and replace them by a temporary struct "RayCastData" which contains these datas and a collision mask. Finally i add a collision mask argument in the python function "rayCast" :
```
rayCast(to, from, dist, prop, face, xray, poly, mask)
```

It can be useful to hit only object which are on the right colision layer. for example if you have hitbox for a charater or vehicle you don't want to hit it with raycast.

test file : {F237337}
left mouse click on two planes and see console messages.

Somewhat more elaborate test file by @sybren: {F237779}
Look around and click on the cubes. One cube lamp responds, the other doesn't, based on their collision groups.

Reviewers: moguri, hg1, agoose77, campbellbarton, sybren

Reviewed By: agoose77, campbellbarton, sybren

Subscribers: campbellbarton, sergey, blueprintrandom, sybren

Projects: #game_engine, #game_physics

Differential Revision: https://developer.blender.org/D1239

12 files changed:
doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
source/gameengine/Ketsji/KX_ConstraintActuator.cpp
source/gameengine/Ketsji/KX_ConstraintActuator.h
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
source/gameengine/Ketsji/KX_MouseFocusSensor.h
source/gameengine/Ketsji/KX_RayCast.h
source/gameengine/Ketsji/KX_RaySensor.cpp
source/gameengine/Ketsji/KX_RaySensor.h
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h

index 74df50ddb586f28a75d21dd7037d33f96bf36c2b..d8cc5e45e8305bb232dce7f6a4475d109bd379ce 100644 (file)
@@ -799,7 +799,7 @@ base class --- :class:`SCA_IObject`
       :return: the first object hit or None if no object or object does not match prop
       :rtype: :class:`KX_GameObject`
 
-   .. method:: rayCast(objto, objfrom, dist, prop, face, xray, poly)
+   .. method:: rayCast(objto, objfrom, dist, prop, face, xray, poly, mask)
 
       Look from a point/object to another point/object and find first object hit within dist that matches prop.
       if poly is 0, returns a 3-tuple with object reference, hit point and hit normal or (None, None, None) if no hit.
@@ -851,6 +851,8 @@ base class --- :class:`SCA_IObject`
          * 2: return value is a 5-tuple and the 5th element is a 2-tuple (u, v) with the UV mapping of the hit point or None if no hit, or the object doesn't use a mesh collision shape, or doesn't have a UV mapping.
 
       :type poly: integer
+      :arg mask: collision mask: The collision mask (16 layers mapped to a 16-bit integer) is combined with each object's collision group, to hit only a subset of the objects in the scene. Only those objects for which ``collisionGroup & mask`` is true can be hit.
+      :type mask: bitfield
       :return: (object, hitpoint, hitnormal) or (object, hitpoint, hitnormal, polygon) or (object, hitpoint, hitnormal, polygon, hituv).
 
          * object, hitpoint and hitnormal are None if no hit.
index e07660cef723947313495bfe0019fc495ac52590..fecd60eb212e5ceb33df13a9f6d9d47f7b00f567 100644 (file)
@@ -117,7 +117,7 @@ KX_ConstraintActuator::~KX_ConstraintActuator()
        // there's nothing to be done here, really....
 } /* end of destructor */
 
-bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data))
 {
 
        m_hitObject = client->m_gameobject;
@@ -153,7 +153,7 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *resu
 /* This function is used to pre-filter the object before casting the ray on them.
  * This is useful for "X-Ray" option when we want to see "through" unwanted object.
  */
-bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo *client)
+bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data))
 {
        if (client->m_type > KX_ClientObjectInfo::ACTOR)
        {
@@ -347,7 +347,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
                                                spc = parent->GetPhysicsController();
                                        }
                                }
-                               KX_RayCast::Callback<KX_ConstraintActuator> callback(this,dynamic_cast<PHY_IPhysicsController*>(spc));
+                               KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this,dynamic_cast<PHY_IPhysicsController*>(spc));
                                result = KX_RayCast::RayTest(pe, position, topoint, callback);
                                if (result)     {
                                        MT_Vector3 newnormal = callback.m_hitNormal;
@@ -459,7 +459,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
                                m_hitObject = NULL;
                                // distance of Fh area is stored in m_minimum
                                MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
-                               KX_RayCast::Callback<KX_ConstraintActuator> callback(this, spc);
+                               KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this, spc);
                                result = KX_RayCast::RayTest(pe, position, topoint, callback);
                                // we expect a hit object
                                if (!m_hitObject)
index edb2e5e0180bc61348e8b8e49b7fe5bd0da708b8..af617655d5e83f07c852c03f2f2da318658ac7f4 100644 (file)
@@ -37,6 +37,8 @@
 #include "MT_Vector3.h"
 #include "KX_ClientObjectInfo.h"
 
+#include "BLI_utildefines.h"
+
 class KX_RayCast;
 class KX_GameObject;
 
@@ -113,9 +115,11 @@ protected:
                KX_ACT_CONSTRAINT_LOCAL = 1024,
                KX_ACT_CONSTRAINT_DOROTFH = 2048
        };
-       bool IsValidMode(KX_CONSTRAINTTYPE m); 
-       bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
-       bool NeedRayCast(KX_ClientObjectInfo*);
+       bool IsValidMode(KX_CONSTRAINTTYPE m);
+       /// \see KX_RayCast
+       bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data));
+       /// \see KX_RayCast
+       bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data));
 
        KX_ConstraintActuator(SCA_IObject* gameobj,
                                                  int posDamptime,
index c3da80bc14fed93a46f98c8491db9a3ef518a02e..d7a94f0601c55859a306a3e5a8a5a67e0f619855 100644 (file)
@@ -47,7 +47,6 @@
 #include "KX_MeshProxy.h"
 #include "KX_PolyProxy.h"
 #include <stdio.h> // printf
-#include <climits> // USHRT_MAX
 #include "SG_Controller.h"
 #include "PHY_IGraphicController.h"
 #include "SG_Node.h"
@@ -108,8 +107,6 @@ KX_GameObject::KX_GameObject(
       m_bOccluder(false),
       m_pPhysicsController(NULL),
       m_pGraphicController(NULL),
-      m_xray(false),
-      m_pHitObject(NULL),
       m_pObstacleSimulation(NULL),
       m_pInstanceObjects(NULL),
       m_pDupliGroupObject(NULL),
@@ -2361,8 +2358,8 @@ int KX_GameObject::pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_
                return PY_SET_ATTR_FAIL;
        }
 
-       if (val < 0 || val > USHRT_MAX) {
-               PyErr_Format(PyExc_AttributeError, "gameOb.collisionGroup = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
+       if (val == 0 || val & ~((1 << OB_MAX_COL_MASKS) - 1)) {
+               PyErr_Format(PyExc_AttributeError, "gameOb.collisionGroup = int: KX_GameObject, expected a int bit field, 0 < group < %i", (1 << OB_MAX_COL_MASKS));
                return PY_SET_ATTR_FAIL;
        }
 
@@ -2386,8 +2383,8 @@ int KX_GameObject::pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_D
                return PY_SET_ATTR_FAIL;
        }
 
-       if (val < 0 || val > USHRT_MAX) {
-               PyErr_Format(PyExc_AttributeError, "gameOb.collisionMask = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
+       if (val == 0 || val & ~((1 << OB_MAX_COL_MASKS) - 1)) {
+               PyErr_Format(PyExc_AttributeError, "gameOb.collisionMask = int: KX_GameObject, expected a int bit field, 0 < mask < %i", (1 << OB_MAX_COL_MASKS));
                return PY_SET_ATTR_FAIL;
        }
 
@@ -3572,15 +3569,32 @@ KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo,
        return returnValue;
 }
 
-bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+struct KX_GameObject::RayCastData
+{
+       RayCastData(STR_String prop, bool xray, short mask)
+               :m_prop(prop),
+               m_xray(xray),
+               m_mask(mask),
+               m_hitObject(NULL)
+       {
+       }
+
+       STR_String m_prop;
+       bool m_xray;
+       unsigned short m_mask;
+       KX_GameObject *m_hitObject;
+};
+
+bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, RayCastData *rayData)
 {
        KX_GameObject* hitKXObj = client->m_gameobject;
-       
+
        // if X-ray option is selected, the unwnted objects were not tested, so get here only with true hit
        // if not, all objects were tested and the front one may not be the correct one.
-       if (m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL)
+       if ((rayData->m_xray || rayData->m_prop.Length() == 0 || hitKXObj->GetProperty(rayData->m_prop) != NULL) && 
+               hitKXObj->GetUserCollisionGroup() & rayData->m_mask)
        {
-               m_pHitObject = hitKXObj;
+               rayData->m_hitObject = hitKXObj;
                return true;
        }
        // return true to stop RayCast::RayTest from looping, the above test was decisive
@@ -3591,10 +3605,10 @@ bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void
 /* this function is used to pre-filter the object before casting the ray on them.
  * This is useful for "X-Ray" option when we want to see "through" unwanted object.
  */
-bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo *client)
+bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo *client, RayCastData *rayData)
 {
        KX_GameObject* hitKXObj = client->m_gameobject;
-       
+
        if (client->m_type > KX_ClientObjectInfo::ACTOR)
        {
                // Unknown type of object, skip it.
@@ -3605,7 +3619,8 @@ bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo *client)
        
        // if X-Ray option is selected, skip object that don't match the criteria as we see through them
        // if not, test all objects because we don't know yet which one will be on front
-       if (!m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL)
+       if ((!rayData->m_xray || rayData->m_prop.Length() == 0 || hitKXObj->GetProperty(rayData->m_prop) != NULL) && 
+               hitKXObj->GetUserCollisionGroup() & rayData->m_mask)
        {
                return true;
        }
@@ -3652,17 +3667,11 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo,
        KX_GameObject *parent = GetParent();
        if (!spc && parent)
                spc = parent->GetPhysicsController();
-       
-       m_pHitObject = NULL;
-       if (propName)
-               m_testPropName = propName;
-       else
-               m_testPropName.SetLength(0);
-       KX_RayCast::Callback<KX_GameObject> callback(this,spc);
-       KX_RayCast::RayTest(pe, fromPoint, toPoint, callback);
 
-       if (m_pHitObject)
-               return m_pHitObject->GetProxy();
+       RayCastData rayData(propName, false, (1 << OB_MAX_COL_MASKS) - 1);
+       KX_RayCast::Callback<KX_GameObject, RayCastData> callback(this, spc, &rayData);
+       if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback))
+               return rayData.m_hitObject->GetProxy();
        
        Py_RETURN_NONE;
 }
@@ -3713,7 +3722,7 @@ static PyObject *none_tuple_5()
 }
 
 KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
-                                  "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n"
+                                  "rayCast(to,from,dist,prop,face,xray,poly,mask): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n"
                                   " If no hit, return (None,None,None) or (None,None,None,None) or (None,None,None,None,None).\n"
 " to   = 3-tuple or object reference for destination of ray (if object, use center of object)\n"
 " from = 3-tuple or object reference for origin of ray (if object, use center of object)\n"
@@ -3727,6 +3736,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
 "                        2=>return value is a 5-tuple, the 4th element is the KX_PolyProxy object\n"
 "                           and the 5th element is the vector of UV coordinates at the hit point of the None if there is no UV mapping\n"
 "        If 0 or omitted, return value is a 3-tuple\n"
+" mask = collision mask: the collision mask that ray can hit, 0 < mask < 65536\n"
 "Note: The object on which you call this method matters: the ray will ignore it.\n"
 "      prop and xray option interact as follow:\n"
 "        prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n"
@@ -3742,8 +3752,9 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
        char *propName = NULL;
        KX_GameObject *other;
        int face=0, xray=0, poly=0;
+       int mask = (1 << OB_MAX_COL_MASKS) - 1;
 
-       if (!PyArg_ParseTuple(args,"O|Ofsiii:rayCast", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) {
+       if (!PyArg_ParseTuple(args,"O|Ofsiiii:rayCast", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly, &mask)) {
                return NULL; // Python sets a simple error
        }
 
@@ -3773,11 +3784,16 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
                        fromPoint = other->NodeGetWorldPosition();
                } else
                {
-                       PyErr_SetString(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly): KX_GameObject, the second optional argument to rayCast must be a vector or a KX_GameObject");
+                       PyErr_SetString(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly,mask): KX_GameObject, the second optional argument to rayCast must be a vector or a KX_GameObject");
                        return NULL;
                }
        }
-       
+
+       if (mask == 0 || mask & ~((1 << OB_MAX_COL_MASKS) - 1)) {
+               PyErr_Format(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly,mask): KX_GameObject, mask argument to rayCast must be a int bitfield, 0 < mask < %i", (1 << OB_MAX_COL_MASKS));
+               return NULL;
+       }
+
        if (dist != 0.0f) {
                MT_Vector3 toDir = toPoint-fromPoint;
                if (MT_fuzzyZero(toDir.length2())) {
@@ -3796,22 +3812,16 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
        KX_GameObject *parent = GetParent();
        if (!spc && parent)
                spc = parent->GetPhysicsController();
-       
-       m_pHitObject = NULL;
-       if (propName)
-               m_testPropName = propName;
-       else
-               m_testPropName.SetLength(0);
-       m_xray = xray;
+
        // to get the hit results
-       KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face,(poly==2));
-       KX_RayCast::RayTest(pe, fromPoint, toPoint, callback);
+       RayCastData rayData(propName, xray, mask);
+       KX_RayCast::Callback<KX_GameObject, RayCastData> callback(this, spc, &rayData, face, (poly == 2));
 
-       if (m_pHitObject)
+       if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback))
        {
                PyObject *returnValue = (poly == 2) ? PyTuple_New(5) : (poly) ? PyTuple_New(4) : PyTuple_New(3);
                if (returnValue) { // unlikely this would ever fail, if it does python sets an error
-                       PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->GetProxy());
+                       PyTuple_SET_ITEM(returnValue, 0, rayData.m_hitObject->GetProxy());
                        PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint));
                        PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal));
                        if (poly)
index c10802a83b21f598f4d238606737cec396c5ca7f..abd109a5e52aa68bc8070d3d2050c72fd2769e55 100644 (file)
@@ -111,9 +111,6 @@ protected:
 
        PHY_IPhysicsController*                         m_pPhysicsController;
        PHY_IGraphicController*                         m_pGraphicController;
-       STR_String                                                      m_testPropName;
-       bool                                                            m_xray;
-       KX_GameObject*                                          m_pHitObject;
 
        SG_Node*                                                        m_pSGNode;
 
@@ -131,9 +128,18 @@ protected:
        BL_ActionManager* GetActionManager();
        
        bool                                                            m_bRecordAnimation;
+
 public:
        bool                                                            m_isDeformable;
 
+       /**
+        * KX_GameObject custom infos for ray cast, it contains property name,
+        * collision mask, xray flag and hited object.
+        * This structure is created during ray cast and passed as argument 
+        * "data" to functions KX_GameObject::NeedRayCast and KX_GameObject::RayHit.
+        */
+       struct RayCastData;
+
        /**
         * Helper function for modules that can't include KX_ClientObjectInfo.h
         */
@@ -661,8 +667,10 @@ public:
                return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent());
        }
 
-       bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
-       bool NeedRayCast(KX_ClientObjectInfo* client);
+       /// \see KX_RayCast
+       bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, RayCastData *rayData);
+       /// \see KX_RayCast
+       bool NeedRayCast(KX_ClientObjectInfo *client, RayCastData *rayData);
 
 
        /**
index 46f27e1a2df7a72b7b069770f2cee840db801ad7..db2cb1fdcfd39f999a57d608d14abbc4bc47f56a 100644 (file)
@@ -144,7 +144,7 @@ bool KX_MouseFocusSensor::Evaluate()
        return result;
 }
 
-bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *result, void * const data)
+bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *result, void *UNUSED(data))
 {
        KX_GameObject* hitKXObj = client_info->m_gameobject;
        
@@ -198,7 +198,7 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r
 /* this function is used to pre-filter the object before casting the ray on them.
  * This is useful for "X-Ray" option when we want to see "through" unwanted object.
  */
-bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo* client)
+bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data))
 {
        KX_GameObject *hitKXObj = client->m_gameobject;
 
@@ -356,7 +356,7 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam)
        PHY_IPhysicsEnvironment* physics_environment = m_kxscene->GetPhysicsEnvironment();
 
        // get UV mapping
-       KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller,NULL,false,true);
+       KX_RayCast::Callback<KX_MouseFocusSensor, void> callback(this,physics_controller,NULL,false,true);
         
        KX_RayCast::RayTest(physics_environment, m_prevSourcePoint, m_prevTargetPoint, callback);
        
index 0c7c8ab676ad8b0f4884b641275ccca632996a69..dd9295b2ff4b135db99a9716e798995b1657e79e 100644 (file)
@@ -35,6 +35,8 @@
 
 #include "SCA_MouseSensor.h"
 
+#include "BLI_utildefines.h"
+
 class KX_RayCast;
 
 /**
@@ -90,8 +92,10 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
                return result;
        };
 
-       bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
-       bool NeedRayCast(KX_ClientObjectInfo* client);
+       /// \see KX_RayCast
+       bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data));
+       /// \see KX_RayCast
+       bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data));
        
        const MT_Point3& RaySource() const;
        const MT_Point3& RayTarget() const;
index e47ac676eb1d0234cdcd7f642a89bc677f4036c5..c977fb8f3858018e211f735de91c7a549fe963a1 100644 (file)
@@ -44,12 +44,15 @@ struct KX_ClientObjectInfo;
 /**
  *  Defines a function for doing a ray cast.
  *
- *  eg KX_RayCast::RayTest(ignore_physics_controller, physics_environment, frompoint, topoint, result_point, result_normal, KX_RayCast::Callback<KX_MyClass>(this, data)
+ *  eg KX_RayCast::RayTest(ignore_physics_controller, physics_environment, frompoint, topoint, result_point, result_normal, KX_RayCast::Callback<MyClass, MyDataClass>(this, data)
  *
- *  Calls myclass->RayHit(client, hit_point, hit_normal, data) for all client
+ *  Calls myclass->NeedRayCast(client, data) for all client in environment
+ *  and myclass->RayHit(client, hit_point, hit_normal, data) for all client
  *  between frompoint and topoint
  *
- *  myclass->RayHit should return true to end the raycast, false to ignore the current client.
+ *  myclass->NeedRayCast should return true to ray test the current client.
+ *
+ *  myclass->RayHit should return true to end the raycast, false to ignore the current client and to continue.
  *
  *  Returns true if a client was accepted, false if nothing found.
  */
@@ -80,10 +83,10 @@ public:
        /** 
         *  Callback wrapper.
         *
-        *  Construct with KX_RayCast::Callback<MyClass>(this, data)
+        *  Construct with KX_RayCast::Callback<MyClass, MyDataClass>(this, data)
         *  and pass to KX_RayCast::RayTest
         */
-       template<class T> class Callback;
+       template<class T, class dataT> class Callback;
        
        /// Public interface.
        /// Implement bool RayHit in your class to receive ray callbacks.
@@ -99,12 +102,18 @@ public:
 #endif
 };
 
-template<class T> class KX_RayCast::Callback : public KX_RayCast
+template<class T, class dataT>
+class KX_RayCast::Callback : public KX_RayCast
 {
        T *self;
-       void *data;
+       /**
+        * Some user info passed as argument in constructor.
+        * It contains all info needed to check client in NeedRayCast
+        * and RayHit.
+        */
+       dataT *data;
 public:
-       Callback(T *_self, PHY_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false, bool faceUV=false)
+       Callback(T *_self, PHY_IPhysicsController *controller = NULL, dataT *_data = NULL, bool faceNormal = false, bool faceUV = false)
                : KX_RayCast(controller, faceNormal, faceUV),
                self(_self),
                data(_data)
@@ -127,7 +136,7 @@ public:
                        MT_assert(info && "Physics controller with no client object info");
                        return false;
                }
-               return self->NeedRayCast(info);
+               return self->NeedRayCast(info, data);
        }
        
        
index c97d233a67bfe3d6628f1f8b03b9d28df4a41653..4ffb5f332db23fd782094e204f141de21a9c7bd7 100644 (file)
@@ -107,7 +107,7 @@ bool KX_RaySensor::IsPositiveTrigger()
        return result;
 }
 
-bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data))
 {
 
        KX_GameObject* hitKXObj = client->m_gameobject;
@@ -158,7 +158,7 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void
 /* this function is used to pre-filter the object before casting the ray on them.
  * This is useful for "X-Ray" option when we want to see "through" unwanted object.
  */
-bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo *client)
+bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data))
 {
        KX_GameObject *hitKXObj = client->m_gameobject;
 
@@ -282,7 +282,7 @@ bool KX_RaySensor::Evaluate()
        PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment();
        
 
-       KX_RayCast::Callback<KX_RaySensor> callback(this, spc);
+       KX_RayCast::Callback<KX_RaySensor, void> callback(this, spc);
        KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback);
 
        /* now pass this result to some controller */
index 4604863a233b0a390a8c484224d00d431bf9a581..1901bb04f868d3563f059268fdcaa51c516a2abf 100644 (file)
@@ -38,6 +38,8 @@
 #include "SCA_IScene.h" /* only for scene replace */
 #include "KX_Scene.h" /* only for scene replace */
 
+#include "BLI_utildefines.h"
+
 struct KX_ClientObjectInfo;
 class KX_RayCast;
 
@@ -74,8 +76,10 @@ public:
        virtual bool IsPositiveTrigger();
        virtual void Init();
 
-       bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
-       bool NeedRayCast(KX_ClientObjectInfo* client);
+       /// \see KX_RayCast
+       bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data));
+       /// \see KX_RayCast
+       bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data));
 
        virtual void            Replace_IScene(SCA_IScene *val) 
        {       
index 1758b7abf9f91ebc03d07be39eadfc78d986ac4c..bd84c3c96b1b0b54cbe21a5c0be1fa1280f2e239 100644 (file)
@@ -1215,10 +1215,9 @@ void RAS_OpenGLRasterizer::RemoveLight(RAS_ILightObject* lightobject)
                m_lights.erase(lit);
 }
 
-bool RAS_OpenGLRasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+bool RAS_OpenGLRasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast *result, double *oglmatrix)
 {
        if (result->m_hitMesh) {
-               double* const oglmatrix = (double* const) data;
 
                RAS_Polygon* poly = result->m_hitMesh->GetPolygon(result->m_hitPolygon);
                if (!poly->IsVisible())
@@ -1328,7 +1327,7 @@ void RAS_OpenGLRasterizer::applyTransform(double* oglmatrix,int objectdrawmode )
                        if (!physics_controller && parent)
                                physics_controller = parent->GetPhysicsController();
 
-                       KX_RayCast::Callback<RAS_OpenGLRasterizer> callback(this, physics_controller, oglmatrix);
+                       KX_RayCast::Callback<RAS_OpenGLRasterizer, double> callback(this, physics_controller, oglmatrix);
                        if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback))
                        {
                                // couldn't find something to cast the shadow on...
index ad49ebe5179c0ce322d3095caf378e0a4accb7b5..67a11f64726dc30a0b53b6a2086cddb52e35bcba 100644 (file)
@@ -45,6 +45,8 @@ using namespace std;
 #include "RAS_MaterialBucket.h"
 #include "RAS_IPolygonMaterial.h"
 
+#include "BLI_utildefines.h"
+
 class RAS_IStorage;
 class RAS_ICanvas;
 class RAS_OpenGLLight;
@@ -306,8 +308,10 @@ public:
        void PushMatrix();
        void PopMatrix();
 
-       bool RayHit(struct KX_ClientObjectInfo *client, class KX_RayCast *result, void * const data);
-       bool NeedRayCast(struct KX_ClientObjectInfo *) { return true; }
+       /// \see KX_RayCast
+       bool RayHit(struct KX_ClientObjectInfo *client, class KX_RayCast *result, double *oglmatrix);
+       /// \see KX_RayCast
+       bool NeedRayCast(struct KX_ClientObjectInfo *, void *UNUSED(data)) { return true; }
 
        RAS_ILightObject* CreateLight();
        void AddLight(RAS_ILightObject* lightobject);