Blender V2.61 - r43446
|
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