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
This commit is contained in:
Mitchell Stokes
2014-07-17 23:00:30 -07:00
parent 841ade32be
commit 7307973063
7 changed files with 171 additions and 18 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);

View File

@@ -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
};

View File

@@ -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.
*/