Blender  V2.59
KX_TrackToActuator.cpp
Go to the documentation of this file.
00001 
00004 //
00005 // Replace the mesh for this actuator's parent
00006 //
00007 // $Id: KX_TrackToActuator.cpp 36523 2011-05-06 20:18:42Z blendix $
00008 //
00009 // ***** BEGIN GPL LICENSE BLOCK *****
00010 //
00011 // This program is free software; you can redistribute it and/or
00012 // modify it under the terms of the GNU General Public License
00013 // as published by the Free Software Foundation; either version 2
00014 // of the License, or (at your option) any later version.
00015 //
00016 // This program is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 // GNU General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU General Public License
00022 // along with this program; if not, write to the Free Software Foundation,
00023 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00024 //
00025 // The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00026 // All rights reserved.
00027 //
00028 // The Original Code is: all of this file.
00029 //
00030 // Contributor(s): none yet.
00031 //
00032 // ***** END GPL LICENSE BLOCK *****
00033 
00034 // todo: not all trackflags / upflags are implemented/tested !
00035 // m_trackflag is used to determine the forward tracking direction
00036 // m_upflag for the up direction
00037 // normal situation is +y for forward, +z for up
00038 
00039 #include "MT_Scalar.h"
00040 #include "SCA_IActuator.h"
00041 #include "KX_TrackToActuator.h"
00042 #include "SCA_IScene.h"
00043 #include "SCA_LogicManager.h"
00044 #include <math.h>
00045 #include <iostream>
00046 #include "KX_GameObject.h"
00047 
00048 #include "PyObjectPlus.h"
00049 
00050 /* ------------------------------------------------------------------------- */
00051 /* Native functions                                                          */
00052 /* ------------------------------------------------------------------------- */
00053 
00054 
00055 
00056 KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, 
00057                                                                        SCA_IObject *ob,
00058                                                                            int time,
00059                                                                            bool allow3D,
00060                                                                            int trackflag,
00061                                                                            int upflag)
00062                                                                            : SCA_IActuator(gameobj, KX_ACT_TRACKTO)
00063 {
00064     m_time = time;
00065     m_allow3D = allow3D;
00066     m_object = ob;
00067         m_trackflag = trackflag;
00068         m_upflag = upflag;
00069         m_parentobj = 0;
00070         
00071         if (m_object)
00072                 m_object->RegisterActuator(this);
00073 
00074         {
00075                 // if the object is vertex parented, don't check parent orientation as the link is broken
00076                 if (!((KX_GameObject*)gameobj)->IsVertexParent()){
00077                         m_parentobj = ((KX_GameObject*)gameobj)->GetParent(); // check if the object is parented 
00078                         if (m_parentobj) {  
00079                                 // if so, store the initial local rotation
00080                                 // this is needed to revert the effect of the parent inverse node (TBC)
00081                                 m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation();
00082                                 // use registration mechanism rather than AddRef, it creates zombie objects
00083                                 m_parentobj->RegisterActuator(this);
00084                                 // GetParent did AddRef, undo here
00085                                 m_parentobj->Release();
00086                         }
00087                 }
00088         }
00089 
00090 } /* End of constructor */
00091 
00092 
00093 
00094 /* old function from Blender */
00095 MT_Matrix3x3 EulToMat3(float *eul)
00096 {
00097         MT_Matrix3x3 mat;
00098         float ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
00099         
00100         ci = cos(eul[0]); 
00101         cj = cos(eul[1]); 
00102         ch = cos(eul[2]);
00103         si = sin(eul[0]); 
00104         sj = sin(eul[1]); 
00105         sh = sin(eul[2]);
00106         cc = ci*ch; 
00107         cs = ci*sh; 
00108         sc = si*ch; 
00109         ss = si*sh;
00110 
00111         mat[0][0] = cj*ch; 
00112         mat[1][0] = sj*sc-cs; 
00113         mat[2][0] = sj*cc+ss;
00114         mat[0][1] = cj*sh; 
00115         mat[1][1] = sj*ss+cc; 
00116         mat[2][1] = sj*cs-sc;
00117         mat[0][2] = -sj;         
00118         mat[1][2] = cj*si;    
00119         mat[2][2] = cj*ci;
00120 
00121         return mat;
00122 }
00123 
00124 
00125 
00126 /* old function from Blender */
00127 void Mat3ToEulOld(MT_Matrix3x3 mat, float *eul)
00128 {
00129         MT_Scalar cy;
00130         
00131         cy = sqrt(mat[0][0]*mat[0][0] + mat[0][1]*mat[0][1]);
00132 
00133         if (cy > 16.0*FLT_EPSILON) {
00134                 eul[0] = atan2(mat[1][2], mat[2][2]);
00135                 eul[1] = atan2(-mat[0][2], cy);
00136                 eul[2] = atan2(mat[0][1], mat[0][0]);
00137         } else {
00138                 eul[0] = atan2(-mat[2][1], mat[1][1]);
00139                 eul[1] = atan2(-mat[0][2], cy);
00140                 eul[2] = 0.0;
00141         }
00142 }
00143 
00144 
00145 
00146 /* old function from Blender */
00147 void compatible_eulFast(float *eul, float *oldrot)
00148 {
00149         float dx, dy, dz;
00150         
00151         /* angular difference of 360 degrees */
00152 
00153         dx= eul[0] - oldrot[0];
00154         dy= eul[1] - oldrot[1];
00155         dz= eul[2] - oldrot[2];
00156 
00157         if( fabs(dx) > MT_PI) {
00158                 if(dx > 0.0) eul[0] -= MT_2_PI; else eul[0]+= MT_2_PI;
00159         }
00160         if( fabs(dy) > MT_PI) {
00161                 if(dy > 0.0) eul[1] -= MT_2_PI; else eul[1]+= MT_2_PI;
00162         }
00163         if( fabs(dz) > MT_PI ) {
00164                 if(dz > 0.0) eul[2] -= MT_2_PI; else eul[2]+= MT_2_PI;
00165         }
00166 }
00167 
00168 
00169 
00170 MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, int m_time)
00171 {
00172         float eul[3], oldeul[3];        
00173 
00174         Mat3ToEulOld(oldmat, oldeul);
00175         Mat3ToEulOld(mat, eul);
00176         compatible_eulFast(eul, oldeul);
00177         
00178         eul[0]= (m_time*oldeul[0] + eul[0])/(1.0+m_time);
00179         eul[1]= (m_time*oldeul[1] + eul[1])/(1.0+m_time);
00180         eul[2]= (m_time*oldeul[2] + eul[2])/(1.0+m_time);
00181         
00182         return EulToMat3(eul);
00183 }
00184 
00185 
00186 
00187 KX_TrackToActuator::~KX_TrackToActuator()
00188 {
00189         if (m_object)
00190                 m_object->UnregisterActuator(this);
00191         if (m_parentobj)
00192                 m_parentobj->UnregisterActuator(this);
00193 } /* end of destructor */
00194 
00195 void KX_TrackToActuator::ProcessReplica()
00196 {
00197         // the replica is tracking the same object => register it
00198         if (m_object)
00199                 m_object->RegisterActuator(this);
00200         if (m_parentobj)
00201                 m_parentobj->RegisterActuator(this);
00202         SCA_IActuator::ProcessReplica();
00203 }
00204 
00205 
00206 bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj)
00207 {
00208         if (clientobj == m_object)
00209         {
00210                 // this object is being deleted, we cannot continue to track it.
00211                 m_object = NULL;
00212                 return true;
00213         }
00214         if (clientobj == m_parentobj)
00215         {
00216                 m_parentobj = NULL;
00217                 return true;
00218         }
00219         return false;
00220 }
00221 
00222 void KX_TrackToActuator::Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map)
00223 {
00224         void **h_obj = (*obj_map)[m_object];
00225         if (h_obj) {
00226                 if (m_object)
00227                         m_object->UnregisterActuator(this);
00228                 m_object = (SCA_IObject*)(*h_obj);
00229                 m_object->RegisterActuator(this);
00230         }
00231 
00232         void **h_parobj = (*obj_map)[m_parentobj];
00233         if (h_parobj) {
00234                 if (m_parentobj)
00235                         m_parentobj->UnregisterActuator(this);
00236                 m_parentobj= (KX_GameObject*)(*h_parobj);
00237                 m_parentobj->RegisterActuator(this);
00238         }
00239 }
00240 
00241 
00242 bool KX_TrackToActuator::Update(double curtime, bool frame)
00243 {
00244         bool result = false;    
00245         bool bNegativeEvent = IsNegativeEvent();
00246         RemoveAllEvents();
00247 
00248         if (bNegativeEvent)
00249         {
00250                 // do nothing on negative events
00251         }
00252         else if (m_object)
00253         {
00254                 KX_GameObject* curobj = (KX_GameObject*) GetParent();
00255                 MT_Vector3 dir = ((KX_GameObject*)m_object)->NodeGetWorldPosition() - curobj->NodeGetWorldPosition();
00256                 if (dir.length2())
00257                         dir.normalize();
00258                 MT_Vector3 up(0,0,1);
00259                 
00260                 
00261 #ifdef DSADSA
00262                 switch (m_upflag)
00263                 {
00264                 case 0:
00265                         {
00266                                 up.setValue(1.0,0,0);
00267                                 break;
00268                         } 
00269                 case 1:
00270                         {
00271                                 up.setValue(0,1.0,0);
00272                                 break;
00273                         }
00274                 case 2:
00275                 default:
00276                         {
00277                                 up.setValue(0,0,1.0);
00278                         }
00279                 }
00280 #endif 
00281                 if (m_allow3D)
00282                 {
00283                         up = (up - up.dot(dir) * dir).safe_normalized();
00284                         
00285                 }
00286                 else
00287                 {
00288                         dir = (dir - up.dot(dir)*up).safe_normalized();
00289                 }
00290                 
00291                 MT_Vector3 left;
00292                 MT_Matrix3x3 mat;
00293                 
00294                 switch (m_trackflag)
00295                 {
00296                 case 0: // TRACK X
00297                         {
00298                                 // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
00299                                 left  = dir.safe_normalized();
00300                                 dir = (left.cross(up)).safe_normalized();
00301                                 mat.setValue (
00302                                         left[0], dir[0],up[0], 
00303                                         left[1], dir[1],up[1],
00304                                         left[2], dir[2],up[2]
00305                                         );
00306                                 
00307                                 break;
00308                         };
00309                 case 1: // TRACK Y
00310                         {
00311                                 // (0.0 , 1.0 , 0.0 ) y direction is forward, z (0.0 , 0.0 , 1.0 ) up
00312                                 left  = (dir.cross(up)).safe_normalized();
00313                                 mat.setValue (
00314                                         left[0], dir[0],up[0], 
00315                                         left[1], dir[1],up[1],
00316                                         left[2], dir[2],up[2]
00317                                         );
00318                                 
00319                                 break;
00320                         }
00321                         
00322                 case 2: // track Z
00323                         {
00324                                 left = up.safe_normalized();
00325                                 up = dir.safe_normalized();
00326                                 dir = left;
00327                                 left  = (dir.cross(up)).safe_normalized();
00328                                 mat.setValue (
00329                                         left[0], dir[0],up[0], 
00330                                         left[1], dir[1],up[1],
00331                                         left[2], dir[2],up[2]
00332                                         );
00333                                 break;
00334                         }
00335                         
00336                 case 3: // TRACK -X
00337                         {
00338                                 // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
00339                                 left  = -dir.safe_normalized();
00340                                 dir = -(left.cross(up)).safe_normalized();
00341                                 mat.setValue (
00342                                         left[0], dir[0],up[0], 
00343                                         left[1], dir[1],up[1],
00344                                         left[2], dir[2],up[2]
00345                                         );
00346                                 
00347                                 break;
00348                         };
00349                 case 4: // TRACK -Y
00350                         {
00351                                 // (0.0 , -1.0 , 0.0 ) -y direction is forward, z (0.0 , 0.0 , 1.0 ) up
00352                                 left  = (-dir.cross(up)).safe_normalized();
00353                                 mat.setValue (
00354                                         left[0], -dir[0],up[0], 
00355                                         left[1], -dir[1],up[1],
00356                                         left[2], -dir[2],up[2]
00357                                         );
00358                                 break;
00359                         }
00360                 case 5: // track -Z
00361                         {
00362                                 left = up.safe_normalized();
00363                                 up = -dir.safe_normalized();
00364                                 dir = left;
00365                                 left  = (dir.cross(up)).safe_normalized();
00366                                 mat.setValue (
00367                                         left[0], dir[0],up[0], 
00368                                         left[1], dir[1],up[1],
00369                                         left[2], dir[2],up[2]
00370                                         );
00371                                 
00372                                 break;
00373                         }
00374                         
00375                 default:
00376                         {
00377                                 // (1.0 , 0.0 , 0.0 ) -x direction is forward, z (0.0 , 0.0 , 1.0 ) up
00378                                 left  = -dir.safe_normalized();
00379                                 dir = -(left.cross(up)).safe_normalized();
00380                                 mat.setValue (
00381                                         left[0], dir[0],up[0], 
00382                                         left[1], dir[1],up[1],
00383                                         left[2], dir[2],up[2]
00384                                         );
00385                         }
00386                 }
00387                 
00388                 MT_Matrix3x3 oldmat;
00389                 oldmat= curobj->NodeGetWorldOrientation();
00390                 
00391                 /* erwin should rewrite this! */
00392                 mat= matrix3x3_interpol(oldmat, mat, m_time);
00393                 
00394 
00395                 if(m_parentobj){ // check if the model is parented and calculate the child transform
00396                                 
00397                         MT_Point3 localpos;
00398                         localpos = curobj->GetSGNode()->GetLocalPosition();
00399                         // Get the inverse of the parent matrix
00400                         MT_Matrix3x3 parentmatinv;
00401                         parentmatinv = m_parentobj->NodeGetWorldOrientation ().inverse ();                              
00402                         // transform the local coordinate system into the parents system
00403                         mat = parentmatinv * mat;
00404                         // append the initial parent local rotation matrix
00405                         mat = m_parentlocalmat * mat;
00406 
00407                         // set the models tranformation properties
00408                         curobj->NodeSetLocalOrientation(mat);
00409                         curobj->NodeSetLocalPosition(localpos);
00410                         //curobj->UpdateTransform();
00411                 }
00412                 else
00413                 {
00414                         curobj->NodeSetLocalOrientation(mat);
00415                 }
00416 
00417                 result = true;
00418         }
00419 
00420         return result;
00421 }
00422 
00423 #ifdef WITH_PYTHON
00424 
00425 /* ------------------------------------------------------------------------- */
00426 /* Python functions                                                          */
00427 /* ------------------------------------------------------------------------- */
00428 
00429 /* Integration hooks ------------------------------------------------------- */
00430 PyTypeObject KX_TrackToActuator::Type = {
00431         PyVarObject_HEAD_INIT(NULL, 0)
00432         "KX_TrackToActuator",
00433         sizeof(PyObjectPlus_Proxy),
00434         0,
00435         py_base_dealloc,
00436         0,
00437         0,
00438         0,
00439         0,
00440         py_base_repr,
00441         0,0,0,0,0,0,0,0,0,
00442         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00443         0,0,0,0,0,0,0,
00444         Methods,
00445         0,
00446         0,
00447         &SCA_IActuator::Type,
00448         0,0,0,0,0,0,
00449         py_base_new
00450 };
00451 
00452 PyMethodDef KX_TrackToActuator::Methods[] = {
00453         {NULL,NULL} //Sentinel
00454 };
00455 
00456 PyAttributeDef KX_TrackToActuator::Attributes[] = {
00457         KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_TrackToActuator,m_time),
00458         KX_PYATTRIBUTE_BOOL_RW("use3D",KX_TrackToActuator,m_allow3D),
00459         KX_PYATTRIBUTE_RW_FUNCTION("object", KX_TrackToActuator, pyattr_get_object, pyattr_set_object),
00460 
00461         { NULL }        //Sentinel
00462 };
00463 
00464 PyObject* KX_TrackToActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
00465 {
00466         KX_TrackToActuator* actuator = static_cast<KX_TrackToActuator*>(self);
00467         if (!actuator->m_object)        
00468                 Py_RETURN_NONE;
00469         else
00470                 return actuator->m_object->GetProxy();
00471 }
00472 
00473 int KX_TrackToActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00474 {
00475         KX_TrackToActuator* actuator = static_cast<KX_TrackToActuator*>(self);
00476         KX_GameObject *gameobj;
00477                 
00478         if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_TrackToActuator"))
00479                 return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
00480                 
00481         if (actuator->m_object != NULL)
00482                 actuator->m_object->UnregisterActuator(actuator);       
00483 
00484         actuator->m_object = (SCA_IObject*) gameobj;
00485                 
00486         if (actuator->m_object)
00487                 actuator->m_object->RegisterActuator(actuator);
00488                 
00489         return PY_SET_ATTR_SUCCESS;
00490 }
00491 
00492 #endif // WITH_PYTHON
00493 
00494 /* eof */