blender/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
Mitchell Stokes b90de0331d BGE: Cleaning up the BGE's physics code and removing KX_IPhysicsController and KX_BulletPhysicsController. Instead, we just use PHY_IPhysicsController, which removes a lot of duplicate code.
This is a squashed commit of the following:
    BGE Physics Cleanup: Fix crashes with LibLoading and replication. Also fixing some memory leaks.
    BGE Physics Cleanup: Removing KX_IPhysicsController and KX_BulletPhysicsController.
    BGE Physics Cleanup: Moving the replication code outside of KX_BlenderBulletController and switching KX_ConvertPhysicsObjects to create a CcdPhysicsController instead of a KX_BlenderBulletController.
    BGE Physics Cleanup: Getting rid of an unsued KX_BulletPhysicsController.h include in KX_Scene.cpp.
    BGE Physics Cleanup: Removing unused KX_IPhysicsController and KX_BulletPhysicsController includes.
    BGE Physics Cleanup: Removing m_pPhysicsController1 and GetPhysicsController1() from KX_GameObject.
    BGE Physics Cleanup: Remove SetRigidBody() from KX_IPhysicsController and remove GetName() from CcdPhysicsController.
    BGE Physics Cleanup: Moving Add/RemoveCompoundChild() from KX_IPhysicsController to PHY_IPhysicsController.
    BGE Physics Cleanup: Removing GetLocalInertia() from KX_IPhysicsController.
    BGE Physics Cleanup: Making BlenderBulletCharacterController derive from PHY_ICharacter and removing CharacterWrapper from CcdPhysicsEnvironment.cpp. Also removing the character functions from KX_IPhysicsController.
    BGE Physics Cleanup: Removing GetOrientation(), SetOrientation(), SetPosition(), SetScaling(), and GetRadius() from KX_IPhysicsController.
    BGE Physics Cleanup: Removing GetReactionForce() since all implementations returned (0, 0, 0). The Python interface for KX_GameObject still has reaction force code, but it still also returns (0, 0, 0). This can probably be removed as well, but removing it can break scripts, so I'll leave it for now.
    BGE Physics Cleanup: Removing Get/SetLinVelocityMin() and Get/SetLinVelocityMax() from KX_IPhysicsController.
    BGE Physics Cleanup: Removing SetMargin(), RelativeTranslate(), and RelativeRotate() from KX_IPhysicsController.
    BGE Physics Cleanup: Using constant references for function arguments in PHY_IPhysicsController where appropriate.
    BGE Physics Cleanup: Removing ApplyImpulse() from KX_IPhysicsController.
    BGE Physics Cleanup: Removing ResolveCombinedVelocities() from KX_IPhysicsController.
    BGE Physics Cleanup: Accidently removed a return when cleaning up KX_GameObject::PyGetVelocity().
    BGE Physics Cleanup: Remove GetLinearVelocity(), GetAngularVelocity() and GetVelocity() from KX_IPhysicsController. The corresponding PHY_IPhysicsController functions now also take Moto types instead of scalars to match the KX_IPhysicsController interface.
    BGE Physics Cleanup: Moving SuspendDynamics, RestoreDynamics, SetMass, GetMass, and SetTransform from KX_IPhysicsController to PHY_IPhysicsController.
    BGE Physics Cleanup: PHY_IPhysicsEnvironment and derived classes now use the same naming scheme as PHY_IController.
    BGE Physics Cleanup: PHY_IMotionState and derived classes now use the same naming convention as PHY_IController.
    BGE Phsyics Cleanup: Making PHY_IController and its derived classes follow a consistent naming scheme for member functions. They now all start with capital letters (e.g., setWorldOrientation becomes SetWorldOrientation).
    BGE Physics Cleanup: Getting rid of KX_GameObject::SuspendDynamics() and KX_GameObject::RestoreDynamics(). Instead, use the functions from the physics controller.
    BGE: Some first steps in trying to cleanup the KX_IPhysicsController mess. KX_GameObject now has a GetPhysicsController() and a GetPhysicsController1(). The former returns a PHY_IPhysicsController* while the latter returns a KX_IPhysicsController. The goal is to get everything using GetPhysicsController() instead of GetPhysicsController1().
2013-11-04 19:22:47 +00:00

445 lines
13 KiB
C++

/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 *****
* KX_MouseFocusSensor determines mouse in/out/over events.
*/
/** \file gameengine/Ketsji/KX_MouseFocusSensor.cpp
* \ingroup ketsji
*/
#ifdef _MSC_VER
/* This warning tells us about truncation of __long__ stl-generated names.
* It can occasionally cause DevStudio to have internal compiler warnings. */
# pragma warning(disable:4786)
#endif
#include "MT_Point3.h"
#include "RAS_FramingManager.h"
#include "RAS_ICanvas.h"
#include "RAS_IRasterizer.h"
#include "SCA_IScene.h"
#include "KX_Scene.h"
#include "KX_Camera.h"
#include "KX_MouseFocusSensor.h"
#include "KX_PyMath.h"
#include "KX_RayCast.h"
#include "PHY_IPhysicsController.h"
#include "PHY_IPhysicsEnvironment.h"
#include "KX_ClientObjectInfo.h"
/* ------------------------------------------------------------------------- */
/* Native functions */
/* ------------------------------------------------------------------------- */
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)
: SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj),
m_focusmode(focusmode),
m_bTouchPulse(bTouchPulse),
m_kxscene(kxscene),
m_kxengine(kxengine)
{
Init();
}
void KX_MouseFocusSensor::Init()
{
m_mouse_over_in_previous_frame = (m_invert)?true:false;
m_positive_event = false;
m_hitObject = 0;
m_hitObject_Last = NULL;
m_reset = true;
m_hitPosition.setValue(0,0,0);
m_prevTargetPoint.setValue(0,0,0);
m_prevSourcePoint.setValue(0,0,0);
m_hitNormal.setValue(0,0,1);
}
bool KX_MouseFocusSensor::Evaluate()
{
bool result = false;
bool obHasFocus = false;
bool reset = m_reset && m_level;
// cout << "evaluate focus mouse sensor "<<endl;
m_reset = false;
if (m_focusmode) {
/* Focus behavior required. Test mouse-on. The rest is
* equivalent to handling a key. */
obHasFocus = ParentObjectHasFocus();
if (!obHasFocus) {
m_positive_event = false;
if (m_mouse_over_in_previous_frame) {
result = true;
}
} else {
m_positive_event = true;
if (!m_mouse_over_in_previous_frame) {
result = true;
}
else if (m_bTouchPulse && (m_hitObject != m_hitObject_Last)) {
result = true;
}
}
if (reset) {
// force an event
result = true;
}
} else {
/* No focus behavior required: revert to the basic mode. This
* mode is never used, because the converter never makes this
* sensor for a mouse-key event. It is here for
* completeness. */
result = SCA_MouseSensor::Evaluate();
m_positive_event = (m_val!=0);
}
m_mouse_over_in_previous_frame = obHasFocus;
m_hitObject_Last = (void *)m_hitObject;
return result;
}
bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *result, void * const data)
{
KX_GameObject* hitKXObj = client_info->m_gameobject;
/* Is this me? In the ray test, there are a lot of extra checks
* for aliasing artifacts from self-hits. That doesn't happen
* here, so a simple test suffices. Or does the camera also get
* self-hits? (No, and the raysensor shouldn't do it either, since
* self-hits are excluded by setting the correct ignore-object.)
* Hitspots now become valid. */
KX_GameObject* thisObj = (KX_GameObject*) GetParent();
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;
}
return true; // object must be visible to trigger
//return false; // occluded objects can trigger
}
bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam)
{
/* All screen handling in the gameengine is done by GL,
* specifically the model/view and projection parts. The viewport
* part is in the creator.
*
* The theory is this:
* WCS - world coordinates
* -> wcs_camcs_trafo ->
* camCS - camera coordinates
* -> camcs_clip_trafo ->
* clipCS - normalized device coordinates?
* -> normview_win_trafo
* winCS - window coordinates
*
* The first two transforms are respectively the model/view and
* the projection matrix. These are passed to the rasterizer, and
* we store them in the camera for easy access.
*
* For normalized device coords (xn = x/w, yn = y/w/zw) the
* windows coords become (lb = left bottom)
*
* xwin = [(xn + 1.0) * width]/2 + x_lb
* ywin = [(yn + 1.0) * height]/2 + y_lb
*
* Inverting (blender y is flipped!):
*
* xn = 2(xwin - x_lb)/width - 1.0
* yn = 2(ywin - y_lb)/height - 1.0
* = 2(height - y_blender - y_lb)/height - 1.0
* = 1.0 - 2(y_blender - y_lb)/height
*
* */
/* Because we don't want to worry about resize events, camera
* changes and all that crap, we just determine this over and
* over. Stop whining. We have lots of other calculations to do
* here as well. These reads are not the main cost. If there is no
* canvas, the test is irrelevant. The 1.0 makes sure the
* calculations don't bomb. Maybe we should explicitly guard for
* division by 0.0...*/
RAS_Rect area, viewport;
short m_y_inv = m_kxengine->GetCanvas()->GetHeight()-m_y;
m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport);
/* Check if the mouse is in the viewport */
if (( m_x < viewport.m_x2 && // less then right
m_x > viewport.m_x1 && // more then then left
m_y_inv < viewport.m_y2 && // below top
m_y_inv > viewport.m_y1) == 0) // above bottom
{
return false;
}
float height = float(viewport.m_y2 - viewport.m_y1 + 1);
float width = float(viewport.m_x2 - viewport.m_x1 + 1);
float x_lb = float(viewport.m_x1);
float y_lb = float(viewport.m_y1);
MT_Vector4 frompoint;
MT_Vector4 topoint;
/* m_y_inv - inverting for a bounds check is only part of it, now make relative to view bounds */
m_y_inv = (viewport.m_y2 - m_y_inv) + viewport.m_y1;
/* There's some strangeness I don't fully get here... These values
* _should_ be wrong! - see from point Z values */
/* build the from and to point in normalized device coordinates
* Normalized device coordinates are [-1,1] in x, y, z
*
* The actual z coordinates used don't have to be exact just infront and
* behind of the near and far clip planes.
*/
frompoint.setValue( (2 * (m_x-x_lb) / width) - 1.0,
1.0 - (2 * (m_y_inv - y_lb) / height),
-1.0,
1.0 );
topoint.setValue( (2 * (m_x-x_lb) / width) - 1.0,
1.0 - (2 * (m_y_inv-y_lb) / height),
1.0,
1.0 );
/* camera to world */
MT_Matrix4x4 camcs_wcs_matrix = MT_Matrix4x4(cam->GetCameraToWorld());
/* badly defined, the first time round.... I wonder why... I might
* want to guard against floating point errors here.*/
MT_Matrix4x4 clip_camcs_matrix = MT_Matrix4x4(cam->GetProjectionMatrix());
clip_camcs_matrix.invert();
/* shoot-points: clip to cam to wcs . win to clip was already done.*/
frompoint = clip_camcs_matrix * frompoint;
topoint = clip_camcs_matrix * topoint;
/* clipstart = - (frompoint[2] / frompoint[3])
* clipend = - (topoint[2] / topoint[3]) */
frompoint = camcs_wcs_matrix * frompoint;
topoint = camcs_wcs_matrix * topoint;
/* from hom wcs to 3d wcs: */
m_prevSourcePoint.setValue( frompoint[0]/frompoint[3],
frompoint[1]/frompoint[3],
frompoint[2]/frompoint[3]);
m_prevTargetPoint.setValue( topoint[0]/topoint[3],
topoint[1]/topoint[3],
topoint[2]/topoint[3]);
/* 2. Get the object from PhysicsEnvironment */
/* Shoot! Beware that the first argument here is an
* ignore-object. We don't ignore anything... */
PHY_IPhysicsController* physics_controller = cam->GetPhysicsController();
PHY_IPhysicsEnvironment* physics_environment = m_kxscene->GetPhysicsEnvironment();
// get UV mapping
KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller,NULL,false,true);
KX_RayCast::RayTest(physics_environment, m_prevSourcePoint, m_prevTargetPoint, callback);
if (m_hitObject)
return true;
return false;
}
bool KX_MouseFocusSensor::ParentObjectHasFocus()
{
m_hitObject = 0;
m_hitPosition.setValue(0,0,0);
m_hitNormal.setValue(1,0,0);
KX_Camera *cam= m_kxscene->GetActiveCamera();
if (ParentObjectHasFocusCamera(cam))
return true;
list<class KX_Camera*>* cameras = m_kxscene->GetCameras();
list<KX_Camera*>::iterator it = cameras->begin();
while (it != cameras->end()) {
if (((*it) != cam) && (*it)->GetViewport())
if (ParentObjectHasFocusCamera(*it))
return true;
it++;
}
return false;
}
const MT_Point3& KX_MouseFocusSensor::RaySource() const
{
return m_prevSourcePoint;
}
const MT_Point3& KX_MouseFocusSensor::RayTarget() const
{
return m_prevTargetPoint;
}
const MT_Point3& KX_MouseFocusSensor::HitPosition() const
{
return m_hitPosition;
}
const MT_Vector3& KX_MouseFocusSensor::HitNormal() const
{
return m_hitNormal;
}
const MT_Vector2& KX_MouseFocusSensor::HitUV() const
{
return m_hitUV;
}
#ifdef WITH_PYTHON
/* ------------------------------------------------------------------------- */
/* Python functions */
/* ------------------------------------------------------------------------- */
/* Integration hooks ------------------------------------------------------- */
PyTypeObject KX_MouseFocusSensor::Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"KX_MouseFocusSensor",
sizeof(PyObjectPlus_Proxy),
0,
py_base_dealloc,
0,
0,
0,
0,
py_base_repr,
0,0,0,0,0,0,0,0,0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0,0,0,0,0,0,0,
Methods,
0,
0,
&SCA_MouseSensor::Type,
0,0,0,0,0,0,
py_base_new
};
PyMethodDef KX_MouseFocusSensor::Methods[] = {
{NULL,NULL} //Sentinel
};
PyAttributeDef KX_MouseFocusSensor::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("raySource", KX_MouseFocusSensor, pyattr_get_ray_source),
KX_PYATTRIBUTE_RO_FUNCTION("rayTarget", KX_MouseFocusSensor, pyattr_get_ray_target),
KX_PYATTRIBUTE_RO_FUNCTION("rayDirection", KX_MouseFocusSensor, pyattr_get_ray_direction),
KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_MouseFocusSensor, pyattr_get_hit_object),
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),
{ NULL } //Sentinel
};
/* Attributes */
PyObject *KX_MouseFocusSensor::pyattr_get_ray_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseFocusSensor* self = static_cast<KX_MouseFocusSensor*>(self_v);
return PyObjectFrom(self->RaySource());
}
PyObject *KX_MouseFocusSensor::pyattr_get_ray_target(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseFocusSensor* self = static_cast<KX_MouseFocusSensor*>(self_v);
return PyObjectFrom(self->RayTarget());
}
PyObject *KX_MouseFocusSensor::pyattr_get_ray_direction(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseFocusSensor* self = static_cast<KX_MouseFocusSensor*>(self_v);
MT_Vector3 dir = self->RayTarget() - self->RaySource();
if (MT_fuzzyZero(dir)) dir.setValue(0,0,0);
else dir.normalize();
return PyObjectFrom(dir);
}
PyObject *KX_MouseFocusSensor::pyattr_get_hit_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseFocusSensor* self = static_cast<KX_MouseFocusSensor*>(self_v);
if (self->m_hitObject)
return self->m_hitObject->GetProxy();
Py_RETURN_NONE;
}
PyObject *KX_MouseFocusSensor::pyattr_get_hit_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseFocusSensor* self = static_cast<KX_MouseFocusSensor*>(self_v);
return PyObjectFrom(self->HitPosition());
}
PyObject *KX_MouseFocusSensor::pyattr_get_hit_normal(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseFocusSensor* self = static_cast<KX_MouseFocusSensor*>(self_v);
return PyObjectFrom(self->HitNormal());
}
PyObject *KX_MouseFocusSensor::pyattr_get_hit_uv(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseFocusSensor* self = static_cast<KX_MouseFocusSensor*>(self_v);
return PyObjectFrom(self->HitUV());
}
#endif // WITH_PYTHON
/* eof */