From 73079730638f1f21c04b075839d87377315e8f86 Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Thu, 17 Jul 2014 23:00:30 -0700 Subject: BGE: Add property/material detection and X-Ray for mouse over any sensor This patch adds a Property/Material detection and a X-Ray mode to the mouse over any sensor like on the ray sensor. Proposal: http://blenderartists.org/forum/showthread.php?261847-BGE-proposal-Mouse-Over-Any-sensor-with-Property-and-X-Ray&highlight=proposal Reviewers: moguri Reviewed By: moguri Differential Revision: https://developer.blender.org/D653 --- .../bge_types/bge.types.KX_MouseFocusSensor.rst | 17 +++++ source/blender/editors/space_logic/logic_window.c | 26 ++++++- source/blender/makesdna/DNA_sensor_types.h | 4 +- source/blender/makesrna/intern/rna_sensor.c | 27 +++++++ source/gameengine/Converter/KX_ConvertSensors.cpp | 7 ++ source/gameengine/Ketsji/KX_MouseFocusSensor.cpp | 88 ++++++++++++++++++---- source/gameengine/Ketsji/KX_MouseFocusSensor.h | 20 ++++- 7 files changed, 171 insertions(+), 18 deletions(-) diff --git a/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst b/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst index dda73eadb52..0600a4b5aae 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst @@ -64,3 +64,20 @@ base class --- :class:`SCA_MouseSensor` :type: boolean + .. attribute:: useXRay + + If enabled it allows the sensor to see through game objects that don't have the selected property or material. + + :type: boolean + + .. attribute:: propName + + The property or material the sensor is looking for. + + :type: string + + .. attribute:: useMaterial + + Determines if the sensor is looking for a property or material. KX_True = Find material; KX_False = Find property. + + :type: boolean diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 32547275e56..1a0aab75fb8 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1144,15 +1144,35 @@ static void draw_sensor_message(uiLayout *layout, PointerRNA *ptr) uiItemR(layout, ptr, "subject", 0, NULL, ICON_NONE); } -static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr) +static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr, bContext *C) { - uiLayout *split; + uiLayout *split, *split2; + + Object *ob = (Object *)ptr->id.data; + PointerRNA main_ptr; split = uiLayoutSplit(layout, 0.8f, false); uiItemR(split, ptr, "mouse_event", 0, NULL, ICON_NONE); if (RNA_enum_get(ptr, "mouse_event") == BL_SENS_MOUSE_MOUSEOVER_ANY) + { uiItemR(split, ptr, "use_pulse", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + + split = uiLayoutSplit(layout, 0.3f, false); + uiItemR(split, ptr, "use_material", 0, "", ICON_NONE); + + split2 = uiLayoutSplit(split, 0.7f, false); + if (RNA_enum_get(ptr, "use_material") == SENS_RAY_PROPERTY) + { + uiItemR(split2, ptr, "property", 0, "", ICON_NONE); + } + else + { + RNA_main_pointer_create(CTX_data_main(C), &main_ptr); + uiItemPointerR(split2, ptr, "material", &main_ptr, "materials", "", ICON_MATERIAL_DATA); + } + uiItemR(split2, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + } } static void draw_sensor_near(uiLayout *layout, PointerRNA *ptr) @@ -1273,7 +1293,7 @@ static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) draw_sensor_message(box, ptr); break; case SENS_MOUSE: - draw_sensor_mouse(box, ptr); + draw_sensor_mouse(box, ptr, C); break; case SENS_NEAR: draw_sensor_near(box, ptr); diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h index cd1977c0ce3..8d59a13768b 100644 --- a/source/blender/makesdna/DNA_sensor_types.h +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -57,7 +57,9 @@ typedef struct bMouseSensor { short type; short flag; short pad1; - short pad2; + short mode; /* flag to choose material or property */ + char propname[64]; + char matname[64]; } bMouseSensor; /* DEPRECATED */ diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index aeef04f4ac7..3944b59dff7 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -405,6 +405,12 @@ static void rna_def_mouse_sensor(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static const EnumPropertyItem prop_mouse_type_items[] = { + {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a material for ray intersections"}, + {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a property for ray intersections"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "MouseSensor", "Sensor"); RNA_def_struct_ui_text(srna, "Mouse Sensor", "Sensor to detect mouse events"); RNA_def_struct_sdna_from(srna, "bMouseSensor", "data"); @@ -419,6 +425,27 @@ static void rna_def_mouse_sensor(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_MOUSE_FOCUS_PULSE); RNA_def_property_ui_text(prop, "Pulse", "Moving the mouse over a different object generates a pulse"); RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "use_material", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, prop_mouse_type_items); + RNA_def_property_ui_text(prop, "M/P", "Toggle collision on material or property"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "propname"); + RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "matname"); + RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "use_x_ray", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_RAY_XRAY); + RNA_def_property_ui_text(prop, "X-Ray", "Toggle X-Ray option (see through objects that don't have the property)"); + RNA_def_property_update(prop, NC_LOGIC, NULL); } static void rna_def_keyboard_sensor(BlenderRNA *brna) diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 93a5ee11366..0d706fcd924 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -329,12 +329,19 @@ void BL_ConvertSensors(struct Object* blenderobject, gameobj); } else { /* give us a focus-aware sensor */ + bool bFindMaterial = (bmouse->mode & SENS_COLLISION_MATERIAL); + bool bXRay = (bmouse->flag & SENS_RAY_XRAY); + STR_String checkname = (bFindMaterial? bmouse->matname : bmouse->propname); + gamesensor = new KX_MouseFocusSensor(eventmgr, startx, starty, keytype, trackfocus, (bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true:false, + checkname, + bFindMaterial, + bXRay, kxscene, kxengine, gameobj); diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index 2dbafdad3d9..e21ac386bc8 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -60,15 +60,21 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, int startx, int starty, - short int mousemode, - int focusmode, - bool bTouchPulse, - KX_Scene* kxscene, - KX_KetsjiEngine *kxengine, - SCA_IObject* gameobj) + short int mousemode, + int focusmode, + bool bTouchPulse, + const STR_String& propname, + bool bFindMaterial, + bool bXRay, + KX_Scene* kxscene, + KX_KetsjiEngine *kxengine, + SCA_IObject* gameobj) : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj), m_focusmode(focusmode), m_bTouchPulse(bTouchPulse), + m_propertyname(propname), + m_bFindMaterial(bFindMaterial), + m_bXRay(bXRay), m_kxscene(kxscene), m_kxengine(kxengine) { @@ -146,20 +152,73 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r * self-hits are excluded by setting the correct ignore-object.) * Hitspots now become valid. */ KX_GameObject* thisObj = (KX_GameObject*) GetParent(); + + bool bFound = false; + if ((m_focusmode == 2) || hitKXObj == thisObj) { - m_hitObject = hitKXObj; - m_hitPosition = result->m_hitPoint; - m_hitNormal = result->m_hitNormal; - m_hitUV = result->m_hitUV; - return true; + if (m_propertyname.Length() == 0) + { + bFound = true; + } + else + { + if (m_bFindMaterial) + { + if (client_info->m_auxilary_info) + { + bFound = (m_propertyname== ((char*)client_info->m_auxilary_info)); + } + } + else + { + bFound = hitKXObj->GetProperty(m_propertyname) != NULL; + } + } + + if (bFound) + { + m_hitObject = hitKXObj; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; + m_hitUV = result->m_hitUV; + return true; + } } return true; // object must be visible to trigger //return false; // occluded objects can trigger } - +/* 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) +{ + 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; + } + if (m_bXRay && m_propertyname.Length() != 0) + { + if (m_bFindMaterial) + { + // not quite correct: an object may have multiple material + // should check all the material and not only the first one + if (!client->m_auxilary_info || (m_propertyname != ((char*)client->m_auxilary_info))) + return false; + } + else + { + if (client->m_gameobject->GetProperty(m_propertyname) == NULL) + return false; + } + } + return true; +} bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) { @@ -384,7 +443,10 @@ PyAttributeDef KX_MouseFocusSensor::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("hitPosition", KX_MouseFocusSensor, pyattr_get_hit_position), KX_PYATTRIBUTE_RO_FUNCTION("hitNormal", KX_MouseFocusSensor, pyattr_get_hit_normal), KX_PYATTRIBUTE_RO_FUNCTION("hitUV", KX_MouseFocusSensor, pyattr_get_hit_uv), - KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor,m_bTouchPulse), + KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor, m_bTouchPulse), + KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_MouseFocusSensor, m_bXRay), + KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_MouseFocusSensor, m_bFindMaterial), + KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_MouseFocusSensor, m_propertyname), { NULL } //Sentinel }; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index 1f7809831e7..903c3c03571 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -57,6 +57,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor short int mousemode, int focusmode, bool bTouchPulse, + const STR_String& propname, + bool bFindMaterial, + bool bXRay, KX_Scene* kxscene, KX_KetsjiEngine* kxengine, SCA_IObject* gameobj); @@ -88,7 +91,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor }; bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); - bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } + bool NeedRayCast(KX_ClientObjectInfo* client); const MT_Point3& RaySource() const; const MT_Point3& RayTarget() const; @@ -133,6 +136,21 @@ class KX_MouseFocusSensor : public SCA_MouseSensor */ bool m_bTouchPulse; + /** + * Flags get trought other objects + */ + bool m_bXRay; + + /** + * Flags material + */ + bool m_bFindMaterial; + + /** + * Property or material name + */ + STR_String m_propertyname; + /** * Flags whether the previous test evaluated positive. */ -- cgit v1.2.3