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