diff options
Diffstat (limited to 'source/gameengine/Ketsji')
-rw-r--r-- | source/gameengine/Ketsji/KX_ConstraintActuator.cpp | 50 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_ConstraintActuator.h | 5 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_GameObject.cpp | 101 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_GameObject.h | 5 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_MeshProxy.cpp | 31 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_MeshProxy.h | 2 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_MouseFocusSensor.cpp | 16 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_MouseFocusSensor.h | 6 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_PolyProxy.cpp | 265 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_PolyProxy.h | 71 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_RayCast.cpp | 85 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_RayCast.h | 60 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_RaySensor.cpp | 41 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_RaySensor.h | 4 |
14 files changed, 609 insertions, 133 deletions
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index e00ec68ad33..4b57b0e8c54 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -109,16 +109,11 @@ KX_ConstraintActuator::~KX_ConstraintActuator() // there's nothing to be done here, really.... } /* end of destructor */ -bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client->m_gameobject; - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } bool bFound = false; if (m_property[0] == 0) @@ -139,8 +134,26 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_p bFound = hitKXObj->GetProperty(m_property) != NULL; } } + // update the hit status + result->m_hitFound = bFound; + // stop looking + return true; +} - return bFound; +/* 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) +{ + if (client->m_type > KX_ClientObjectInfo::ACTOR) + { + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found in ray casting\n", client->m_type); + return false; + } + // no X-Ray function yet + return true; } bool KX_ConstraintActuator::Update(double curtime, bool frame) @@ -287,8 +300,6 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) direction.normalize(); { MT_Point3 topoint = position + (m_maximumBound) * direction; - MT_Point3 resultpoint; - MT_Vector3 resultnormal; PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment(); KX_IPhysicsController *spc = obj->GetPhysicsController(); @@ -304,9 +315,10 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) parent->Release(); } } - result = KX_RayCast::RayTest(spc, pe, position, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_ConstraintActuator>(this)); - + KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc); + result = KX_RayCast::RayTest(pe, position, topoint, callback); if (result) { + MT_Vector3 newnormal = callback.m_hitNormal; // compute new position & orientation if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) { // if none option is set, the actuator does nothing but detect ray @@ -316,27 +328,27 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) if (m_option & KX_ACT_CONSTRAINT_NORMAL) { // the new orientation must be so that the axis is parallel to normal if (sign) - resultnormal = -resultnormal; + newnormal = -newnormal; // apply damping on the direction if (m_rotDampTime) { MT_Scalar rotFilter = 1.0/(1.0+m_rotDampTime); - resultnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*resultnormal; + newnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*newnormal; } else if (m_posDampTime) { - resultnormal = -filter*direction + (1.0-filter)*resultnormal; + newnormal = -filter*direction + (1.0-filter)*newnormal; } - obj->AlignAxisToVect(resultnormal, axis); - direction = -resultnormal; + obj->AlignAxisToVect(newnormal, axis); + direction = -newnormal; } if (m_option & KX_ACT_CONSTRAINT_DISTANCE) { if (m_posDampTime) { - newdistance = filter*(position-resultpoint).length()+(1.0-filter)*m_minimumBound; + newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound; } else { newdistance = m_minimumBound; } } else { - newdistance = (position-resultpoint).length(); + newdistance = (position-callback.m_hitPoint).length(); } - newposition = resultpoint-newdistance*direction; + newposition = callback.m_hitPoint-newdistance*direction; } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { // no contact but still keep running result = true; diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index d9f39124cac..6ec4de9aad9 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -37,6 +37,8 @@ #include "MT_Vector3.h" #include "KX_ClientObjectInfo.h" +class KX_RayCast; + class KX_ConstraintActuator : public SCA_IActuator { Py_Header; @@ -100,7 +102,8 @@ protected: KX_ACT_CONSTRAINT_DISTANCE = 512 }; bool IsValidMode(KX_CONSTRAINTTYPE m); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo*); KX_ConstraintActuator(SCA_IObject* gameobj, int posDamptime, diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 010ee1ebae9..51322f8429e 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -51,6 +51,7 @@ typedef unsigned long uint_ptr; #include "KX_GameObject.h" #include "RAS_MeshObject.h" #include "KX_MeshProxy.h" +#include "KX_PolyProxy.h" #include <stdio.h> // printf #include "SG_Controller.h" #include "KX_IPhysicsController.h" @@ -84,6 +85,7 @@ KX_GameObject::KX_GameObject( m_bVisible(true), m_pPhysicsController1(NULL), m_pPhysicsEnvironment(NULL), + m_xray(false), m_pHitObject(NULL), m_isDeformable(false) { @@ -1628,25 +1630,45 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo, return returnValue; } -bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { + 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) + { + m_pHitObject = hitKXObj; + return true; + } + // return true to stop RayCast::RayTest from looping, the above test was decisive + // We would want to loop only if we want to get more than one hit point + return true; +} +/* 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) +{ KX_GameObject* hitKXObj = client->m_gameobject; if (client->m_type > KX_ClientObjectInfo::ACTOR) { - // false hit + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found in ray casting\n", client->m_type); return false; } - - if (m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) + + // 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) { - m_pHitObject = hitKXObj; return true; } - + // skip the object return false; - } KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, @@ -1686,8 +1708,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, toPoint = fromPoint + (dist) * toDir; } - MT_Point3 resultPoint; - MT_Vector3 resultNormal; PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); @@ -1701,7 +1721,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, m_testPropName = propName; else m_testPropName.SetLength(0); - KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this)); + KX_RayCast::RayTest(pe, fromPoint, toPoint, KX_RayCast::Callback<KX_GameObject>(this,spc)); if (m_pHitObject) { @@ -1712,13 +1732,24 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, } KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, - "rayCast(to,from,dist,prop): cast a ray and return tuple (object,hit,normal) of contact point with object within dist that matches prop or (None,None,None) tuple if no hit\n" -" prop = property name that object must have; can be omitted => detect any object\n" -" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" + "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) of contact point with object within dist that matches prop.\n" + " If no hit, return (None,None,None) or (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" " Can be None or omitted => start from self object center\n" -" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" -"Note: the object on which you call this method matters: the ray will ignore it if it goes through it\n") +" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" +" prop = property name that object must have; can be omitted => detect any object\n" +" face = normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin\n" +" xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n" +" poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n" +" which can be None if hit object has no mesh or if there is no hit\n" +" If 0 or omitted, return value is a 3-tuple\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" +" prop off, xray on : idem\n" +" prop on, xray off: return closest hit if it matches prop, no hit otherwise\n" +" prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray\n") { MT_Point3 toPoint; MT_Point3 fromPoint; @@ -1727,8 +1758,9 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, float dist = 0.0f; char *propName = NULL; KX_GameObject *other; + int face=0, xray=0, poly=0; - if (!PyArg_ParseTuple(args,"O|Ofs", &pyto, &pyfrom, &dist, &propName)) { + if (!PyArg_ParseTuple(args,"O|Ofsiii", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) { return NULL; // Python sets a simple error } @@ -1774,8 +1806,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, return Py_BuildValue("OOO", Py_None, Py_None, Py_None); } - MT_Point3 resultPoint; - MT_Vector3 resultNormal; PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); @@ -1789,20 +1819,41 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, m_testPropName = propName; else m_testPropName.SetLength(0); - KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this)); + m_xray = xray; + // to get the hit results + KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face); + KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); - if (m_pHitObject) + if (m_pHitObject) { - PyObject* returnValue = PyTuple_New(3); + PyObject* returnValue = (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->AddRef()); - PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(resultPoint)); - PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(resultNormal)); + PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint)); + PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal)); + if (poly) + { + if (callback.m_hitMesh) + { + // if this field is set, then we can trust that m_hitPolygon is a valid polygon + RAS_Polygon* poly = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon); + KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, poly); + PyTuple_SET_ITEM(returnValue, 3, polyproxy); + } + else + { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(returnValue, 3, Py_None); + } + } } return returnValue; } - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); - //Py_RETURN_NONE; + // no hit + if (poly) + return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None); + else + return Py_BuildValue("OOO", Py_None, Py_None, Py_None); } /* --------------------------------------------------------------------- diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 06171905220..508bc7cdfd0 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -54,6 +54,7 @@ //Forward declarations. struct KX_ClientObjectInfo; +class KX_RayCast; class RAS_MeshObject; class KX_IPhysicsController; class PHY_IPhysicsEnvironment; @@ -88,6 +89,7 @@ protected: // used for ray casting PHY_IPhysicsEnvironment* m_pPhysicsEnvironment; STR_String m_testPropName; + bool m_xray; KX_GameObject* m_pHitObject; SG_Node* m_pSGNode; @@ -428,7 +430,8 @@ public: return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent()); } - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client); /** diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index a0ac9cfd4ff..29842af7fb6 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp @@ -35,6 +35,7 @@ #include "RAS_MeshObject.h" #include "KX_VertexProxy.h" +#include "KX_PolyProxy.h" #include "KX_PolygonMaterial.h" #include "KX_BlenderMaterial.h" @@ -71,10 +72,12 @@ PyParentObject KX_MeshProxy::Parents[] = { PyMethodDef KX_MeshProxy::Methods[] = { {"getNumMaterials", (PyCFunction)KX_MeshProxy::sPyGetNumMaterials,METH_VARARGS}, +{"getNumPolygons", (PyCFunction)KX_MeshProxy::sPyGetNumPolygons,METH_NOARGS}, {"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS}, {"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS}, {"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS}, {"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS}, +{"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS}, KX_PYMETHODTABLE(KX_MeshProxy, reinstancePhysicsMesh), //{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS}, @@ -146,6 +149,12 @@ PyObject* KX_MeshProxy::PyGetNumMaterials(PyObject* self, return PyInt_FromLong(num); } +PyObject* KX_MeshProxy::PyGetNumPolygons(PyObject* self) +{ + int num = m_meshobj->NumPolygons(); + return PyInt_FromLong(num); +} + PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self, PyObject* args, PyObject* kwds) @@ -234,6 +243,28 @@ PyObject* KX_MeshProxy::PyGetVertex(PyObject* self, } +PyObject* KX_MeshProxy::PyGetPolygon(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + int polyindex= 1; + PyObject* polyob = NULL; + + if (!PyArg_ParseTuple(args,"i",&polyindex)) + return NULL; + + RAS_Polygon* polygon = m_meshobj->GetPolygon(polyindex); + if (polygon) + { + polyob = new KX_PolyProxy(m_meshobj, polygon); + } + else + { + PyErr_SetString(PyExc_AttributeError, "Invalid polygon index"); + } + return polyob; +} + KX_PYMETHODDEF_DOC(KX_MeshProxy, reinstancePhysicsMesh, "Reinstance the physics mesh.") { diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h index 7c6202c15a4..3335c349673 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.h +++ b/source/gameengine/Ketsji/KX_MeshProxy.h @@ -57,10 +57,12 @@ public: KX_PYMETHOD(KX_MeshProxy,GetNumMaterials); KX_PYMETHOD(KX_MeshProxy,GetMaterialName); KX_PYMETHOD(KX_MeshProxy,GetTextureName); + KX_PYMETHOD_NOARGS(KX_MeshProxy,GetNumPolygons); // both take materialid (int) KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength); KX_PYMETHOD(KX_MeshProxy,GetVertex); + KX_PYMETHOD(KX_MeshProxy,GetPolygon); KX_PYMETHOD_DOC(KX_MeshProxy, reinstancePhysicsMesh); }; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index db0bef8b7e1..721bd4d44d6 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -122,16 +122,10 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event) return result; } -bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client_info->m_gameobject; - if (client_info->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - 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 @@ -142,8 +136,8 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hi if ((m_focusmode == 2) || hitKXObj == thisObj) { m_hitObject = hitKXObj; - m_hitPosition = hit_point; - m_hitNormal = hit_normal; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; return true; } @@ -158,8 +152,6 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) m_hitObject = 0; m_hitPosition = MT_Vector3(0,0,0); m_hitNormal = MT_Vector3(1,0,0); - MT_Point3 resultpoint; - MT_Vector3 resultnormal; /* All screen handling in the gameengine is done by GL, * specifically the model/view and projection parts. The viewport @@ -280,7 +272,7 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) bool result = false; - result = KX_RayCast::RayTest(physics_controller, physics_environment, frompoint3, topoint3, resultpoint, resultnormal, KX_RayCast::Callback<KX_MouseFocusSensor>(this)); + KX_RayCast::RayTest(physics_environment, frompoint3, topoint3, KX_RayCast::Callback<KX_MouseFocusSensor>(this,physics_controller)); result = (m_hitObject!=0); diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index b011ebe1288..a6cc39d66eb 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -33,6 +33,8 @@ #include "SCA_MouseSensor.h" +class KX_RayCast; + /** * The mouse focus sensor extends the basic SCA_MouseSensor. It has * been placed in KX because it needs access to the rasterizer and @@ -76,7 +78,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor return result; }; - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } + /* --------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp new file mode 100644 index 00000000000..658c8a98e4f --- /dev/null +++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp @@ -0,0 +1,265 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "KX_PolyProxy.h" +#include "KX_MeshProxy.h" +#include "RAS_MeshObject.h" +#include "KX_BlenderMaterial.h" +#include "KX_PolygonMaterial.h" + +#include "KX_PyMath.h" + +PyTypeObject KX_PolyProxy::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_PolyProxy", + sizeof(KX_PolyProxy), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject KX_PolyProxy::Parents[] = { + &KX_PolyProxy::Type, + &SCA_IObject::Type, + &CValue::Type, + NULL +}; + +PyMethodDef KX_PolyProxy::Methods[] = { + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialIndex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getNumVertex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isVisible), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isCollider), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialName), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getTextureName), + KX_PYMETHODTABLE(KX_PolyProxy,getVertexIndex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMesh), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterial), + {NULL,NULL} //Sentinel +}; + +PyObject* +KX_PolyProxy::_getattr(const STR_String& attr) +{ + if (attr == "matname") + { + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); + } + if (attr == "texture") + { + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); + } + if (attr == "material") + { + RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); + if(polymat->GetFlag() & RAS_BLENDERMAT) + { + KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + else + { + KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + } + if (attr == "matid") + { + // we'll have to scan through the material bucket of the mes and compare with + // the one of the polygon + RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); + unsigned int matid; + for (matid=0; matid<m_mesh->NumMaterials(); matid++) + { + RAS_MaterialBucket* meshBucket = m_mesh->GetMaterialBucket(matid); + if (meshBucket == polyBucket) + // found it + break; + } + return PyInt_FromLong(matid); + } + if (attr == "v1") + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[0]); + } + if (attr == "v2") + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[1]); + } + if (attr == "v3") + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[2]); + } + if (attr == "v4") + { + return PyInt_FromLong(((m_polygon->VertexCount()>3)?m_polygon->GetVertexIndexBase().m_indexarray[3]:0)); + } + if (attr == "visible") + { + return PyInt_FromLong(m_polygon->IsVisible()); + } + if (attr == "collide") + { + return PyInt_FromLong(m_polygon->IsCollider()); + } + _getattr_up(SCA_IObject); +} + +KX_PolyProxy::KX_PolyProxy(const RAS_MeshObject*mesh, RAS_Polygon* polygon) +: m_mesh((RAS_MeshObject*)mesh), + m_polygon(polygon) +{ +} + +KX_PolyProxy::~KX_PolyProxy() +{ +} + + +// stuff for cvalue related things +CValue* KX_PolyProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;} +CValue* KX_PolyProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} +STR_String sPolyName="polygone"; +const STR_String & KX_PolyProxy::GetText() {return sPolyName;}; +float KX_PolyProxy::GetNumber() { return -1;} +STR_String KX_PolyProxy::GetName() { return sPolyName;} +void KX_PolyProxy::SetName(STR_String) { }; +CValue* KX_PolyProxy::GetReplica() { return NULL;} +void KX_PolyProxy::ReplicaSetName(STR_String) {}; + + +// stuff for python integration + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialIndex, +"getMaterialIndex() : return the material index of the polygon in the mesh\n") +{ + RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); + unsigned int matid; + for (matid=0; matid<m_mesh->NumMaterials(); matid++) + { + RAS_MaterialBucket* meshBucket = m_mesh->GetMaterialBucket(matid); + if (meshBucket == polyBucket) + // found it + break; + } + return PyInt_FromLong(matid); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getNumVertex, +"getNumVertex() : returns the number of vertex of the polygon, 3 or 4\n") +{ + return PyInt_FromLong(m_polygon->VertexCount()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isVisible, +"isVisible() : returns whether the polygon is visible or not\n") +{ + return PyInt_FromLong(m_polygon->IsVisible()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isCollider, +"isCollider() : returns whether the polygon is receives collision or not\n") +{ + return PyInt_FromLong(m_polygon->IsCollider()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialName, +"getMaterialName() : returns the polygon material name, \"NoMaterial\" if no material\n") +{ + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getTextureName, +"getTexturelName() : returns the polygon texture name, \"NULL\" if no texture\n") +{ + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); +} + +KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, +"getVertexIndex(vertex) : returns the mesh vertex index of a polygon vertex\n" +"vertex: index of the vertex in the polygon: 0->3\n" +"return value can be used to retrieve the vertex details through mesh proxy\n" +"Note: getVertexIndex(3) on a triangle polygon returns 0\n") +{ + int index; + if (!PyArg_ParseTuple(args,"i",&index)) + { + return NULL; + } + if (index < 0 || index > 3) + { + PyErr_SetString(PyExc_AttributeError, "Valid range for index is 0-3"); + return NULL; + } + if (index < m_polygon->VertexCount()) + { + return PyInt_FromLong(m_polygon->GetVertexIndexBase().m_indexarray[index]); + } + return PyInt_FromLong(0); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMesh, +"getMesh() : returns a mesh proxy\n") +{ + KX_MeshProxy* meshproxy = new KX_MeshProxy((RAS_MeshObject*)m_mesh); + return meshproxy; +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterial, +"getMaterial() : returns a material\n") +{ + RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); + if(polymat->GetFlag() & RAS_BLENDERMAT) + { + KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + else + { + KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } +} diff --git a/source/gameengine/Ketsji/KX_PolyProxy.h b/source/gameengine/Ketsji/KX_PolyProxy.h new file mode 100644 index 00000000000..506e2c2a656 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PolyProxy.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __KX_POLYROXY +#define __KX_POLYPROXY + +#include "SCA_IObject.h" + +class KX_PolyProxy : public SCA_IObject +{ + Py_Header; +protected: + class RAS_Polygon* m_polygon; + class RAS_MeshObject* m_mesh; +public: + KX_PolyProxy(const class RAS_MeshObject*mesh, class RAS_Polygon* polygon); + virtual ~KX_PolyProxy(); + + // stuff for cvalue related things + CValue* Calc(VALUE_OPERATOR op, CValue *val) ; + CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); + const STR_String & GetText(); + float GetNumber(); + STR_String GetName(); + void SetName(STR_String name); // Set the name of the value + void ReplicaSetName(STR_String name); + CValue* GetReplica(); + + +// stuff for python integration + virtual PyObject* _getattr(const STR_String& attr); + + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialIndex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getNumVertex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isVisible) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isCollider) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialName) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getTextureName) + KX_PYMETHOD_DOC(KX_PolyProxy,getVertexIndex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMesh) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterial) + +}; + +#endif //__KX_POLYPROXY + diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp index 89e2d645d54..974d4b992a6 100644 --- a/source/gameengine/Ketsji/KX_RayCast.cpp +++ b/source/gameengine/Ketsji/KX_RayCast.cpp @@ -40,7 +40,21 @@ #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" -bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, MT_Point3& result_point, MT_Vector3& result_normal, const KX_RayCast& callback) +KX_RayCast::KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal) + :PHY_IRayCastFilterCallback(dynamic_cast<PHY_IPhysicsController*>(ignoreController), faceNormal) +{ +} + +void KX_RayCast::reportHit(PHY_RayCastResult* result) +{ + m_hitFound = true; + m_hitPoint.setValue((const float*)result->m_hitPoint); + m_hitNormal.setValue((const float*)result->m_hitNormal); + m_hitMesh = result->m_meshObject; + m_hitPolygon = result->m_polygon; +} + +bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback) { // Loops over all physics objects between frompoint and topoint, // calling callback.RayHit for each one. @@ -50,58 +64,51 @@ bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsE // returns true if an object was found, false if not. MT_Point3 frompoint(_frompoint); const MT_Vector3 todir( (topoint - frompoint).safe_normalized() ); + MT_Point3 prevpoint(_frompoint+todir*(-1.f)); PHY_IPhysicsController* hit_controller; - PHY__Vector3 phy_pos; - PHY__Vector3 phy_normal; - while((hit_controller = physics_environment->rayTest(dynamic_cast<PHY_IPhysicsController*>(ignore_controller), + while((hit_controller = physics_environment->rayTest(callback, frompoint.x(),frompoint.y(),frompoint.z(), - topoint.x(),topoint.y(),topoint.z(), - phy_pos[0],phy_pos[1],phy_pos[2], - phy_normal[0],phy_normal[1],phy_normal[2]))) + topoint.x(),topoint.y(),topoint.z())) != NULL) { - result_point = MT_Point3(phy_pos); - result_normal = MT_Vector3(phy_normal); KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo()); if (!info) { printf("no info!\n"); MT_assert(info && "Physics controller with no client object info"); - return false; + break; } - if (callback.RayHit(info, result_point, result_normal)) - return true; - - // There is a bug in the code below: the delta is computed with the wrong - // sign on the face opposite to the center, resulting in infinite looping. - // In Blender 2.45 this code was never executed because callback.RayHit() always - // returned true, causing the ray sensor to stop on the first object. - // To avoid changing the behaviour will simply return false here. - // It should be discussed if we want the ray sensor to "see" through objects - // that don't have the required property/material (condition to get here) - return false; - - // skip past the object and keep tracing - /* We add 0.01 of fudge, so that if the margin && radius == 0., we don't endless loop. */ - MT_Scalar marg = 0.01 + hit_controller->GetMargin(); - marg += 2.f * hit_controller->GetMargin(); + // The biggest danger to to endless loop, prevent this by checking that the + // hit point always progresses along the ray direction.. + prevpoint -= callback.m_hitPoint; + if (prevpoint.length2() < MT_EPSILON) + break; + + if (callback.RayHit(info)) + // caller may decide to stop the loop and still cancel the hit + return callback.m_hitFound; + + // Skip past the object and keep tracing. + // Note that retrieving in a single shot multiple hit points would be possible + // but it would require some change in Bullet. + prevpoint = callback.m_hitPoint; + /* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */ + MT_Scalar marg = 0.001 + hit_controller->GetMargin(); + marg *= 2.f; /* Calculate the other side of this object */ - PHY__Vector3 hitpos; - hit_controller->getPosition(hitpos); - MT_Point3 hitObjPos(hitpos); - - MT_Vector3 hitvector = hitObjPos - result_point; - if (hitvector.dot(hitvector) > MT_EPSILON) - { - hitvector.normalize(); - marg *= 2.*todir.dot(hitvector); - } - frompoint = result_point + marg * todir; + MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal)); + if (h <= 0.01) + // the normal is almost orthogonal to the ray direction, cannot compute the other side + break; + marg /= h; + frompoint = callback.m_hitPoint + marg * todir; + // verify that we are not passed the to point + if ((topoint - frompoint).dot(todir) < 0.f) + break; } - - return hit_controller; + return false; } diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h index 607dabd8afc..c3084c997a1 100644 --- a/source/gameengine/Ketsji/KX_RayCast.h +++ b/source/gameengine/Ketsji/KX_RayCast.h @@ -30,12 +30,14 @@ #ifndef __KX_RAYCAST_H__ #define __KX_RAYCAST_H__ -class MT_Point3; -class MT_Vector3; -class KX_IPhysicsController; -class PHY_IPhysicsEnvironment; +#include "PHY_IPhysicsEnvironment.h" +#include "PHY_IPhysicsController.h" +#include "MT_Point3.h" +#include "MT_Vector3.h" +class RAS_MeshObject; struct KX_ClientObjectInfo; +class KX_IPhysicsController; /** * Defines a function for doing a ray cast. @@ -49,17 +51,27 @@ struct KX_ClientObjectInfo; * * Returns true if a client was accepted, false if nothing found. */ -class KX_RayCast +class KX_RayCast : public PHY_IRayCastFilterCallback { -protected: - KX_RayCast() {}; public: + bool m_hitFound; + MT_Point3 m_hitPoint; + MT_Vector3 m_hitNormal; + const RAS_MeshObject* m_hitMesh; + int m_hitPolygon; + + KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal); virtual ~KX_RayCast() {} + /** + * The physic environment returns the ray casting result through this function + */ + virtual void reportHit(PHY_RayCastResult* result); + /** ray test callback. * either override this in your class, or use a callback wrapper. */ - virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const = 0; + virtual bool RayHit(KX_ClientObjectInfo* client) = 0; /** * Callback wrapper. @@ -71,13 +83,11 @@ public: /// Public interface. /// Implement bool RayHit in your class to receive ray callbacks. - static bool RayTest(KX_IPhysicsController* physics_controller, + static bool RayTest( PHY_IPhysicsEnvironment* physics_environment, - const MT_Point3& _frompoint, + const MT_Point3& frompoint, const MT_Point3& topoint, - MT_Point3& result_point, - MT_Vector3& result_normal, - const KX_RayCast& callback); + KX_RayCast& callback); }; @@ -86,18 +96,32 @@ template<class T> class KX_RayCast::Callback : public KX_RayCast T *self; void *data; public: - Callback(T *_self, void *_data = NULL) - : self(_self), + Callback(T *_self, KX_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false) + : KX_RayCast(controller, faceNormal), + self(_self), data(_data) { } ~Callback() {} - - virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const + + virtual bool RayHit(KX_ClientObjectInfo* client) { - return self->RayHit(client, hit_point, hit_normal, data); + return self->RayHit(client, this, data); } + + virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller) + { + KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(controller->getNewClientInfo()); + + if (!info) + { + MT_assert(info && "Physics controller with no client object info"); + return false; + } + return self->NeedRayCast(info); + } + }; diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index a416c8c9f89..f62df542be5 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -104,16 +104,10 @@ bool KX_RaySensor::IsPositiveTrigger() return result; } -bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client->m_gameobject; - - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } bool bFound = false; if (m_propertyname.Length() == 0) @@ -139,16 +133,29 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_ { m_rayHit = true; m_hitObject = hitKXObj; - m_hitPosition = hit_point; - m_hitNormal = hit_normal; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; } - - return bFound; - + // no multi-hit search yet + return true; } - +/* 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) +{ + if (client->m_type > KX_ClientObjectInfo::ACTOR) + { + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found ray casting\n", client->m_type); + return false; + } + // no X-Ray function yet + return true; +} bool KX_RaySensor::Evaluate(CValue* event) { @@ -215,8 +222,6 @@ bool KX_RaySensor::Evaluate(CValue* event) m_rayDirection = todir; MT_Point3 topoint = frompoint + (m_distance) * todir; - MT_Point3 resultpoint; - MT_Vector3 resultnormal; PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment(); if (!pe) @@ -238,7 +243,7 @@ bool KX_RaySensor::Evaluate(CValue* event) PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment(); - result = KX_RayCast::RayTest(spc, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_RaySensor>(this)); + KX_RayCast::RayTest(physics_environment, frompoint, topoint, KX_RayCast::Callback<KX_RaySensor>(this, spc)); /* now pass this result to some controller */ @@ -265,6 +270,10 @@ bool KX_RaySensor::Evaluate(CValue* event) // notify logicsystem that ray JUST left the Object result = true; } + else + { + result = false; + } } if (reset) diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index f4305b053d1..9e53f80b69c 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -36,6 +36,7 @@ #include "MT_Point3.h" struct KX_ClientObjectInfo; +class KX_RayCast; class KX_RaySensor : public SCA_ISensor { @@ -68,7 +69,8 @@ public: virtual bool IsPositiveTrigger(); virtual void Init(); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client); KX_PYMETHOD_DOC(KX_RaySensor,GetHitObject); KX_PYMETHOD_DOC(KX_RaySensor,GetHitPosition); |