Blender V2.61 - r43446

KX_MouseFocusSensor.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  * KX_MouseFocusSensor determines mouse in/out/over events.
00027  */
00028 
00034 #if defined(WIN32) && !defined(FREE_WINDOWS)
00035 // This warning tells us about truncation of __long__ stl-generated names.
00036 // It can occasionally cause DevStudio to have internal compiler warnings.
00037 #pragma warning( disable : 4786 )     
00038 #endif
00039 
00040 #include "MT_Point3.h"
00041 #include "RAS_FramingManager.h"
00042 #include "RAS_ICanvas.h"
00043 #include "RAS_IRasterizer.h"
00044 #include "SCA_IScene.h"
00045 #include "KX_Scene.h"
00046 #include "KX_Camera.h"
00047 #include "KX_MouseFocusSensor.h"
00048 #include "KX_PyMath.h"
00049 
00050 #include "KX_RayCast.h"
00051 #include "KX_IPhysicsController.h"
00052 #include "PHY_IPhysicsController.h"
00053 #include "PHY_IPhysicsEnvironment.h"
00054 
00055 
00056 #include "KX_ClientObjectInfo.h"
00057 
00058 /* ------------------------------------------------------------------------- */
00059 /* Native functions                                                          */
00060 /* ------------------------------------------------------------------------- */
00061 
00062 KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, 
00063                                          int startx,
00064                                          int starty,
00065                                          short int mousemode,
00066                                          int focusmode,
00067                                          bool bTouchPulse,
00068                                          KX_Scene* kxscene,
00069                                          KX_KetsjiEngine *kxengine,
00070                                          SCA_IObject* gameobj)
00071     : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj),
00072       m_focusmode(focusmode),
00073       m_bTouchPulse(bTouchPulse),
00074       m_kxscene(kxscene),
00075       m_kxengine(kxengine)
00076 {
00077     Init();
00078 }
00079 
00080 void KX_MouseFocusSensor::Init()
00081 {
00082     m_mouse_over_in_previous_frame = (m_invert)?true:false;
00083     m_positive_event = false;
00084     m_hitObject = 0;
00085     m_hitObject_Last = NULL;
00086     m_reset = true;
00087     
00088     m_hitPosition.setValue(0,0,0);
00089     m_prevTargetPoint.setValue(0,0,0);
00090     m_prevSourcePoint.setValue(0,0,0);
00091     m_hitNormal.setValue(0,0,1);
00092 }
00093 
00094 bool KX_MouseFocusSensor::Evaluate()
00095 {
00096     bool result = false;
00097     bool obHasFocus = false;
00098     bool reset = m_reset && m_level;
00099 
00100 //      cout << "evaluate focus mouse sensor "<<endl;
00101     m_reset = false;
00102     if (m_focusmode) {
00103         /* Focus behaviour required. Test mouse-on. The rest is
00104          * equivalent to handling a key. */
00105         obHasFocus = ParentObjectHasFocus();
00106         
00107         if (!obHasFocus) {
00108             m_positive_event = false;
00109             if (m_mouse_over_in_previous_frame) {
00110                 result = true;
00111             } 
00112         } else {
00113             m_positive_event = true;
00114             if (!m_mouse_over_in_previous_frame) {
00115                 result = true;
00116             }
00117             else if(m_bTouchPulse && (m_hitObject != m_hitObject_Last)) {
00118                 result = true;
00119             }
00120         } 
00121         if (reset) {
00122             // force an event
00123             result = true;
00124         }
00125     } else {
00126         /* No focus behaviour required: revert to the basic mode. This
00127          * mode is never used, because the converter never makes this
00128          * sensor for a mouse-key event. It is here for
00129          * completeness. */
00130         result = SCA_MouseSensor::Evaluate();
00131         m_positive_event = (m_val!=0);
00132     }
00133 
00134     m_mouse_over_in_previous_frame = obHasFocus;
00135     m_hitObject_Last = (void *)m_hitObject;
00136                        
00137     return result;
00138 }
00139 
00140 bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, KX_RayCast* result, void * const data)
00141 {
00142     KX_GameObject* hitKXObj = client_info->m_gameobject;
00143     
00144     /* Is this me? In the ray test, there are a lot of extra checks
00145     * for aliasing artefacts from self-hits. That doesn't happen
00146     * here, so a simple test suffices. Or does the camera also get
00147     * self-hits? (No, and the raysensor shouldn't do it either, since
00148     * self-hits are excluded by setting the correct ignore-object.)
00149     * Hitspots now become valid. */
00150     KX_GameObject* thisObj = (KX_GameObject*) GetParent();
00151     if ((m_focusmode == 2) || hitKXObj == thisObj)
00152     {
00153         m_hitObject = hitKXObj;
00154         m_hitPosition = result->m_hitPoint;
00155         m_hitNormal = result->m_hitNormal;
00156         m_hitUV = result->m_hitUV;
00157         return true;
00158     }
00159     
00160     return true;     // object must be visible to trigger
00161     //return false;  // occluded objects can trigger
00162 }
00163 
00164 
00165 
00166 bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam)
00167 {
00168     /* All screen handling in the gameengine is done by GL,
00169      * specifically the model/view and projection parts. The viewport
00170      * part is in the creator. 
00171      *
00172      * The theory is this:
00173      * WCS - world coordinates
00174      * -> wcs_camcs_trafo ->
00175      * camCS - camera coordinates
00176      * -> camcs_clip_trafo ->
00177      * clipCS - normalized device coordinates?
00178      * -> normview_win_trafo
00179      * winCS - window coordinates
00180      *
00181      * The first two transforms are respectively the model/view and
00182      * the projection matrix. These are passed to the rasterizer, and
00183      * we store them in the camera for easy access.
00184      *
00185      * For normalized device coords (xn = x/w, yn = y/w/zw) the
00186      * windows coords become (lb = left bottom)
00187      *
00188      * xwin = [(xn + 1.0) * width]/2 + x_lb
00189      * ywin = [(yn + 1.0) * height]/2 + y_lb
00190      *
00191      * Inverting (blender y is flipped!):
00192      *
00193      * xn = 2(xwin - x_lb)/width - 1.0
00194      * yn = 2(ywin - y_lb)/height - 1.0 
00195      *    = 2(height - y_blender - y_lb)/height - 1.0
00196      *    = 1.0 - 2(y_blender - y_lb)/height
00197      *
00198      * */
00199      
00200     
00201     /* Because we don't want to worry about resize events, camera
00202      * changes and all that crap, we just determine this over and
00203      * over. Stop whining. We have lots of other calculations to do
00204      * here as well. These reads are not the main cost. If there is no
00205      * canvas, the test is irrelevant. The 1.0 makes sure the
00206      * calculations don't bomb. Maybe we should explicitly guard for
00207      * division by 0.0...*/
00208     
00209     RAS_Rect area, viewport;
00210     short m_y_inv = m_kxengine->GetCanvas()->GetHeight()-m_y;
00211     
00212     m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport);
00213     
00214     /* Check if the mouse is in the viewport */
00215     if ((   m_x < viewport.m_x2 &&  // less then right
00216             m_x > viewport.m_x1 &&  // more then then left
00217             m_y_inv < viewport.m_y2 &&  // below top
00218             m_y_inv > viewport.m_y1) == 0)  // above bottom
00219     {
00220         return false;
00221     }
00222 
00223     float height = float(viewport.m_y2 - viewport.m_y1 + 1);
00224     float width  = float(viewport.m_x2 - viewport.m_x1 + 1);
00225     
00226     float x_lb = float(viewport.m_x1);
00227     float y_lb = float(viewport.m_y1);
00228 
00229     MT_Vector4 frompoint;
00230     MT_Vector4 topoint;
00231     
00232     /* m_y_inv - inverting for a bounds check is only part of it, now make relative to view bounds */
00233     m_y_inv = (viewport.m_y2 - m_y_inv) + viewport.m_y1;
00234     
00235     
00236     /* There's some strangeness I don't fully get here... These values
00237      * _should_ be wrong! - see from point Z values */
00238     
00239     
00240     /*  build the from and to point in normalized device coordinates 
00241      *  Normalized device coordinates are [-1,1] in x, y, z
00242      *  
00243      *  The actual z coordinates used don't have to be exact just infront and 
00244      *  behind of the near and far clip planes.
00245      */ 
00246     frompoint.setValue( (2 * (m_x-x_lb) / width) - 1.0,
00247                         1.0 - (2 * (m_y_inv - y_lb) / height),
00248                         -1.0,
00249                         1.0 );
00250     
00251     topoint.setValue(   (2 * (m_x-x_lb) / width) - 1.0,
00252                         1.0 - (2 * (m_y_inv-y_lb) / height),
00253                         1.0,
00254                         1.0 );
00255     
00256     /* camera to world  */
00257     MT_Matrix4x4 camcs_wcs_matrix = MT_Matrix4x4(cam->GetCameraToWorld());
00258 
00259     /* badly defined, the first time round.... I wonder why... I might
00260      * want to guard against floating point errors here.*/
00261     MT_Matrix4x4 clip_camcs_matrix = MT_Matrix4x4(cam->GetProjectionMatrix());
00262     clip_camcs_matrix.invert();
00263 
00264     /* shoot-points: clip to cam to wcs . win to clip was already done.*/
00265     frompoint = clip_camcs_matrix * frompoint;
00266     topoint   = clip_camcs_matrix * topoint;
00267     /* clipstart = - (frompoint[2] / frompoint[3])
00268      * clipend = - (topoint[2] / topoint[3]) */
00269     frompoint = camcs_wcs_matrix * frompoint;
00270     topoint   = camcs_wcs_matrix * topoint;
00271     
00272     /* from hom wcs to 3d wcs: */
00273     m_prevSourcePoint.setValue( frompoint[0]/frompoint[3],
00274                                 frompoint[1]/frompoint[3],
00275                                 frompoint[2]/frompoint[3]); 
00276     
00277     m_prevTargetPoint.setValue( topoint[0]/topoint[3],
00278                                 topoint[1]/topoint[3],
00279                                 topoint[2]/topoint[3]); 
00280     
00281     /* 2. Get the object from PhysicsEnvironment */
00282     /* Shoot! Beware that the first argument here is an
00283      * ignore-object. We don't ignore anything... */
00284     KX_IPhysicsController* physics_controller = cam->GetPhysicsController();
00285     PHY_IPhysicsEnvironment* physics_environment = m_kxscene->GetPhysicsEnvironment();
00286 
00287     // get UV mapping
00288     KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller,NULL,false,true);
00289      
00290     KX_RayCast::RayTest(physics_environment, m_prevSourcePoint, m_prevTargetPoint, callback);
00291     
00292     if (m_hitObject)
00293         return true;
00294     
00295     return false;
00296 }
00297 
00298 bool KX_MouseFocusSensor::ParentObjectHasFocus()
00299 {
00300     m_hitObject = 0;
00301     m_hitPosition.setValue(0,0,0);
00302     m_hitNormal.setValue(1,0,0);
00303     
00304     KX_Camera *cam= m_kxscene->GetActiveCamera();
00305     
00306     if(ParentObjectHasFocusCamera(cam))
00307         return true;
00308 
00309     list<class KX_Camera*>* cameras = m_kxscene->GetCameras();
00310     list<KX_Camera*>::iterator it = cameras->begin();
00311     
00312     while(it != cameras->end())
00313     {
00314         if(((*it) != cam) && (*it)->GetViewport())
00315             if (ParentObjectHasFocusCamera(*it))
00316                 return true;
00317         
00318         it++;
00319     }
00320     
00321     return false;
00322 }
00323 
00324 const MT_Point3& KX_MouseFocusSensor::RaySource() const
00325 {
00326     return m_prevSourcePoint;
00327 }
00328 
00329 const MT_Point3& KX_MouseFocusSensor::RayTarget() const
00330 {
00331     return m_prevTargetPoint;
00332 }
00333 
00334 const MT_Point3& KX_MouseFocusSensor::HitPosition() const
00335 {
00336     return m_hitPosition;
00337 }
00338 
00339 const MT_Vector3& KX_MouseFocusSensor::HitNormal() const
00340 {
00341     return m_hitNormal;
00342 }
00343 
00344 const MT_Vector2& KX_MouseFocusSensor::HitUV() const
00345 {
00346     return m_hitUV;
00347 }
00348 
00349 #ifdef WITH_PYTHON
00350 
00351 /* ------------------------------------------------------------------------- */
00352 /* Python functions                                                          */
00353 /* ------------------------------------------------------------------------- */
00354 
00355 /* Integration hooks ------------------------------------------------------- */
00356 PyTypeObject KX_MouseFocusSensor::Type = {
00357     PyVarObject_HEAD_INIT(NULL, 0)
00358     "KX_MouseFocusSensor",
00359     sizeof(PyObjectPlus_Proxy),
00360     0,
00361     py_base_dealloc,
00362     0,
00363     0,
00364     0,
00365     0,
00366     py_base_repr,
00367     0,0,0,0,0,0,0,0,0,
00368     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00369     0,0,0,0,0,0,0,
00370     Methods,
00371     0,
00372     0,
00373     &SCA_MouseSensor::Type,
00374     0,0,0,0,0,0,
00375     py_base_new
00376 };
00377 
00378 PyMethodDef KX_MouseFocusSensor::Methods[] = {
00379     {NULL,NULL} //Sentinel
00380 };
00381 
00382 PyAttributeDef KX_MouseFocusSensor::Attributes[] = {
00383     KX_PYATTRIBUTE_RO_FUNCTION("raySource",     KX_MouseFocusSensor, pyattr_get_ray_source),
00384     KX_PYATTRIBUTE_RO_FUNCTION("rayTarget",     KX_MouseFocusSensor, pyattr_get_ray_target),
00385     KX_PYATTRIBUTE_RO_FUNCTION("rayDirection",  KX_MouseFocusSensor, pyattr_get_ray_direction),
00386     KX_PYATTRIBUTE_RO_FUNCTION("hitObject",     KX_MouseFocusSensor, pyattr_get_hit_object),
00387     KX_PYATTRIBUTE_RO_FUNCTION("hitPosition",   KX_MouseFocusSensor, pyattr_get_hit_position),
00388     KX_PYATTRIBUTE_RO_FUNCTION("hitNormal",     KX_MouseFocusSensor, pyattr_get_hit_normal),
00389     KX_PYATTRIBUTE_RO_FUNCTION("hitUV",     KX_MouseFocusSensor, pyattr_get_hit_uv),
00390     KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor,m_bTouchPulse),
00391     { NULL }    //Sentinel
00392 };
00393 
00394 /* Attributes */
00395 PyObject* KX_MouseFocusSensor::pyattr_get_ray_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00396 {
00397     KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v);
00398     return PyObjectFrom(self->RaySource());
00399 }
00400 
00401 PyObject* KX_MouseFocusSensor::pyattr_get_ray_target(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00402 {
00403     KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v);
00404     return PyObjectFrom(self->RayTarget());
00405 }
00406 
00407 PyObject* KX_MouseFocusSensor::pyattr_get_ray_direction(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00408 {
00409     KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v);
00410     MT_Vector3 dir = self->RayTarget() - self->RaySource();
00411     if(MT_fuzzyZero(dir))   dir.setValue(0,0,0);
00412     else                    dir.normalize();
00413     return PyObjectFrom(dir);
00414 }
00415 
00416 PyObject* KX_MouseFocusSensor::pyattr_get_hit_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00417 {
00418     KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v);
00419     
00420     if(self->m_hitObject)
00421         return self->m_hitObject->GetProxy();
00422     
00423     Py_RETURN_NONE;
00424 }
00425 
00426 PyObject* KX_MouseFocusSensor::pyattr_get_hit_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00427 {
00428     KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v);
00429     return PyObjectFrom(self->HitPosition());
00430 }
00431 
00432 PyObject* KX_MouseFocusSensor::pyattr_get_hit_normal(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00433 {
00434     KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v);
00435     return PyObjectFrom(self->HitNormal());
00436 }
00437 
00438 PyObject* KX_MouseFocusSensor::pyattr_get_hit_uv(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00439 {
00440     KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v);
00441     return PyObjectFrom(self->HitUV());
00442 }
00443 
00444 #endif // WITH_PYTHON
00445 
00446 /* eof */
00447