Blender V2.61 - r43446

KX_IPO_SGController.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  * Scenegraph controller for ipos.
00027  */
00028 
00034 #if defined(_WIN64)
00035 typedef unsigned __int64 uint_ptr;
00036 #else
00037 typedef unsigned long uint_ptr;
00038 #endif
00039 
00040 #if defined(WIN32) && !defined(FREE_WINDOWS)
00041 // This warning tells us about truncation of __long__ stl-generated names.
00042 // It can occasionally cause DevStudio to have internal compiler warnings.
00043 #pragma warning( disable : 4786 )     
00044 #endif
00045 
00046 #include "KX_IPO_SGController.h"
00047 #include "KX_ScalarInterpolator.h"
00048 #include "KX_GameObject.h"
00049 #include "KX_IPhysicsController.h"
00050 #include "DNA_ipo_types.h"
00051 #include "BLI_math.h"
00052 
00053 // All objects should start on frame 1! Will we ever need an object to 
00054 // start on another frame, the 1.0 should change.
00055 KX_IpoSGController::KX_IpoSGController() 
00056 : m_ipo_as_force(false),
00057   m_ipo_add(false),
00058   m_ipo_local(false),
00059   m_modified(true),
00060   m_ipotime(1.0),
00061   m_ipo_start_initialized(false),
00062   m_ipo_start_euler(0.0,0.0,0.0),
00063   m_ipo_euler_initialized(false)
00064 {
00065     m_game_object = NULL;
00066     for (int i=0; i < KX_MAX_IPO_CHANNELS; i++)
00067         m_ipo_channels_active[i] = false;
00068 }
00069 
00070 
00071 void KX_IpoSGController::SetOption(
00072     int option,
00073     int value)
00074 {
00075     switch (option) {
00076     case SG_CONTR_IPO_IPO_AS_FORCE:
00077         m_ipo_as_force = (value != 0);
00078         m_modified = true;
00079         break;
00080     case SG_CONTR_IPO_IPO_ADD:
00081         m_ipo_add = (value != 0);
00082         m_modified = true;
00083         break;
00084     case SG_CONTR_IPO_RESET:
00085         if (m_ipo_start_initialized && value) {
00086             m_ipo_start_initialized = false;
00087             m_modified = true;
00088         }
00089         break;
00090     case SG_CONTR_IPO_LOCAL:
00091         if (value/* && ((SG_Node*)m_pObject)->GetSGParent() == NULL*/) {
00092             // only accept local Ipo if the object has no parent
00093             m_ipo_local = true;
00094         } else {
00095             m_ipo_local = false;
00096         }
00097         m_modified = true;
00098         break;
00099     default:
00100         ; /* just ignore the rest */
00101     }
00102 }
00103 
00104     void 
00105 KX_IpoSGController::UpdateSumoReference(
00106     )
00107 {
00108     if (m_game_object) {
00109 
00110     }
00111 }
00112 
00113     void 
00114 KX_IpoSGController::SetGameObject(
00115     KX_GameObject* go
00116     )
00117 {
00118     m_game_object = go;
00119 }
00120 
00121 
00122 
00123 bool KX_IpoSGController::Update(double currentTime)
00124 {
00125     if (m_modified)
00126     {
00127         T_InterpolatorList::iterator i;
00128         for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
00129             (*i)->Execute(m_ipotime);//currentTime);
00130         }
00131         
00132         SG_Spatial* ob = (SG_Spatial*)m_pObject;
00133 
00134         //initialization on the first frame of the IPO
00135         if (! m_ipo_start_initialized && currentTime > 0.0) {
00136             m_ipo_start_point = ob->GetLocalPosition();
00137             m_ipo_start_orient = ob->GetLocalOrientation();
00138             m_ipo_start_scale = ob->GetLocalScale();
00139             m_ipo_start_initialized = true;
00140             if (!m_ipo_euler_initialized) {
00141                 // do it only once to avoid angle discontinuities
00142                 m_ipo_start_orient.getEuler(m_ipo_start_euler[0], m_ipo_start_euler[1], m_ipo_start_euler[2]);
00143                 m_ipo_euler_initialized = true;
00144             }
00145         }
00146 
00147         //modifies position?
00148         if (m_ipo_channels_active[OB_LOC_X]  || m_ipo_channels_active[OB_LOC_Y]  || m_ipo_channels_active[OB_LOC_Z] ||
00149             m_ipo_channels_active[OB_DLOC_X] || m_ipo_channels_active[OB_DLOC_Y] || m_ipo_channels_active[OB_DLOC_Z])
00150         {
00151             if (m_ipo_as_force == true) 
00152             {
00153                 if (m_game_object && ob && m_game_object->GetPhysicsController()) 
00154                 {
00155                     m_game_object->GetPhysicsController()->ApplyForce(m_ipo_local ?
00156                         ob->GetWorldOrientation() * m_ipo_xform.GetPosition() :
00157                         m_ipo_xform.GetPosition(), false);
00158                 }
00159             } 
00160             else
00161             {
00162                 // Local ipo should be defined with the object position at (0,0,0)
00163                 // Local transform is applied to the object based on initial position
00164                 MT_Point3 newPosition(0.0,0.0,0.0);
00165                 
00166                 if (!m_ipo_add)
00167                     newPosition = ob->GetLocalPosition();
00168                 //apply separate IPO channels if there is any data in them
00169                 //Loc and dLoc act by themselves or are additive
00170                 //LocX and dLocX
00171                 if (m_ipo_channels_active[OB_LOC_X]) {
00172                     newPosition[0] = (m_ipo_channels_active[OB_DLOC_X] ? m_ipo_xform.GetPosition()[0] + m_ipo_xform.GetDeltaPosition()[0] : m_ipo_xform.GetPosition()[0]);
00173                 }
00174                 else if (m_ipo_channels_active[OB_DLOC_X] && m_ipo_start_initialized) {
00175                     newPosition[0] = (((!m_ipo_add)?m_ipo_start_point[0]:0.0) + m_ipo_xform.GetDeltaPosition()[0]);
00176                 }
00177                 //LocY and dLocY
00178                 if (m_ipo_channels_active[OB_LOC_Y]) {
00179                     newPosition[1] = (m_ipo_channels_active[OB_DLOC_Y] ? m_ipo_xform.GetPosition()[1] + m_ipo_xform.GetDeltaPosition()[1] : m_ipo_xform.GetPosition()[1]);
00180                 }
00181                 else if (m_ipo_channels_active[OB_DLOC_Y] && m_ipo_start_initialized) {
00182                     newPosition[1] = (((!m_ipo_add)?m_ipo_start_point[1]:0.0) + m_ipo_xform.GetDeltaPosition()[1]);
00183                 }
00184                 //LocZ and dLocZ
00185                 if (m_ipo_channels_active[OB_LOC_Z]) {
00186                     newPosition[2] = (m_ipo_channels_active[OB_DLOC_Z] ? m_ipo_xform.GetPosition()[2] + m_ipo_xform.GetDeltaPosition()[2] : m_ipo_xform.GetPosition()[2]);
00187                 }
00188                 else if (m_ipo_channels_active[OB_DLOC_Z] && m_ipo_start_initialized) {
00189                     newPosition[2] = (((!m_ipo_add)?m_ipo_start_point[2]:0.0) + m_ipo_xform.GetDeltaPosition()[2]);
00190                 }
00191                 if (m_ipo_add) {
00192                     if (m_ipo_local)
00193                         newPosition = m_ipo_start_point + m_ipo_start_scale*(m_ipo_start_orient*newPosition);
00194                     else
00195                         newPosition = m_ipo_start_point + newPosition;
00196                 }
00197                 if (m_game_object)
00198                     m_game_object->NodeSetLocalPosition(newPosition);
00199             }
00200         }
00201         //modifies orientation?
00202         if (m_ipo_channels_active[OB_ROT_X]  || m_ipo_channels_active[OB_ROT_Y]  || m_ipo_channels_active[OB_ROT_Z] ||
00203             m_ipo_channels_active[OB_DROT_X] || m_ipo_channels_active[OB_DROT_Y] || m_ipo_channels_active[OB_DROT_Z])
00204         {
00205             if (m_ipo_as_force) {
00206                 
00207                 if (m_game_object && ob) {
00208                     m_game_object->ApplyTorque(m_ipo_local ?
00209                         ob->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() :
00210                         m_ipo_xform.GetEulerAngles(), false);
00211                 }
00212             } else if (m_ipo_add) {
00213                 if (m_ipo_start_initialized) {
00214                     double yaw=0, pitch=0,  roll=0; //delta Euler angles
00215 
00216                     //RotX and dRotX
00217                     if (m_ipo_channels_active[OB_ROT_X])
00218                         yaw += m_ipo_xform.GetEulerAngles()[0];
00219                     if (m_ipo_channels_active[OB_DROT_X])
00220                         yaw += m_ipo_xform.GetDeltaEulerAngles()[0];
00221 
00222                     //RotY dRotY
00223                     if (m_ipo_channels_active[OB_ROT_Y])
00224                         pitch += m_ipo_xform.GetEulerAngles()[1];
00225                     if (m_ipo_channels_active[OB_DROT_Y])
00226                         pitch += m_ipo_xform.GetDeltaEulerAngles()[1];
00227                     
00228                     //RotZ and dRotZ
00229                     if (m_ipo_channels_active[OB_ROT_Z])
00230                         roll += m_ipo_xform.GetEulerAngles()[2];
00231                     if (m_ipo_channels_active[OB_DROT_Z])
00232                         roll += m_ipo_xform.GetDeltaEulerAngles()[2];
00233 
00234                     MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll));
00235                     if (m_ipo_local)
00236                         rotation = m_ipo_start_orient * rotation;
00237                     else
00238                         rotation = rotation * m_ipo_start_orient;
00239                     if (m_game_object)
00240                         m_game_object->NodeSetLocalOrientation(rotation);
00241                 }
00242             } else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) {
00243                 if (m_ipo_euler_initialized) {
00244                     // assume all channel absolute
00245                     // All 3 channels should be specified but if they are not, we will take 
00246                     // the value at the start of the game to avoid angle sign reversal 
00247                     double yaw=m_ipo_start_euler[0], pitch=m_ipo_start_euler[1], roll=m_ipo_start_euler[2];
00248 
00249                     //RotX and dRotX
00250                     if (m_ipo_channels_active[OB_ROT_X]) {
00251                         yaw = (m_ipo_channels_active[OB_DROT_X] ? (m_ipo_xform.GetEulerAngles()[0] + m_ipo_xform.GetDeltaEulerAngles()[0]) : m_ipo_xform.GetEulerAngles()[0] );
00252                     }
00253                     else if (m_ipo_channels_active[OB_DROT_X]) {
00254                         yaw += m_ipo_xform.GetDeltaEulerAngles()[0];
00255                     }
00256 
00257                     //RotY dRotY
00258                     if (m_ipo_channels_active[OB_ROT_Y]) {
00259                         pitch = (m_ipo_channels_active[OB_DROT_Y] ? (m_ipo_xform.GetEulerAngles()[1] + m_ipo_xform.GetDeltaEulerAngles()[1]) : m_ipo_xform.GetEulerAngles()[1] );
00260                     }
00261                     else if (m_ipo_channels_active[OB_DROT_Y]) {
00262                         pitch += m_ipo_xform.GetDeltaEulerAngles()[1];
00263                     }
00264                     
00265                     //RotZ and dRotZ
00266                     if (m_ipo_channels_active[OB_ROT_Z]) {
00267                         roll = (m_ipo_channels_active[OB_DROT_Z] ? (m_ipo_xform.GetEulerAngles()[2] + m_ipo_xform.GetDeltaEulerAngles()[2]) : m_ipo_xform.GetEulerAngles()[2] );
00268                     }
00269                     else if (m_ipo_channels_active[OB_DROT_Z]) {
00270                         roll += m_ipo_xform.GetDeltaEulerAngles()[2];
00271                     }
00272                     if (m_game_object)
00273                         m_game_object->NodeSetLocalOrientation(MT_Vector3(yaw, pitch, roll));
00274                 }
00275             } else if (m_ipo_start_initialized) {
00276                 // only DROT, treat as Add
00277                 double yaw=0, pitch=0,  roll=0; //delta Euler angles
00278 
00279                 //dRotX
00280                 if (m_ipo_channels_active[OB_DROT_X])
00281                     yaw = m_ipo_xform.GetDeltaEulerAngles()[0];
00282 
00283                 //dRotY
00284                 if (m_ipo_channels_active[OB_DROT_Y])
00285                     pitch = m_ipo_xform.GetDeltaEulerAngles()[1];
00286                 
00287                 //dRotZ
00288                 if (m_ipo_channels_active[OB_DROT_Z])
00289                     roll = m_ipo_xform.GetDeltaEulerAngles()[2];
00290 
00291                 // dRot are always local
00292                 MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll));
00293                 rotation = m_ipo_start_orient * rotation;
00294                 if (m_game_object)
00295                     m_game_object->NodeSetLocalOrientation(rotation);
00296             }
00297         }
00298         //modifies scale?
00299         if (m_ipo_channels_active[OB_SIZE_X] || m_ipo_channels_active[OB_SIZE_Y] || m_ipo_channels_active[OB_SIZE_Z] ||
00300             m_ipo_channels_active[OB_DSIZE_X] || m_ipo_channels_active[OB_DSIZE_Y] || m_ipo_channels_active[OB_DSIZE_Z])
00301         {
00302             //default is no scale change
00303             MT_Vector3 newScale(1.0,1.0,1.0);
00304             if (!m_ipo_add)
00305                 newScale = ob->GetLocalScale();
00306 
00307             if (m_ipo_channels_active[OB_SIZE_X]) {
00308                 newScale[0] = (m_ipo_channels_active[OB_DSIZE_X] ? (m_ipo_xform.GetScaling()[0] + m_ipo_xform.GetDeltaScaling()[0]) : m_ipo_xform.GetScaling()[0]);
00309             }
00310             else if (m_ipo_channels_active[OB_DSIZE_X] && m_ipo_start_initialized) {
00311                 newScale[0] = (m_ipo_xform.GetDeltaScaling()[0] + ((!m_ipo_add)?m_ipo_start_scale[0]:0.0));
00312             }
00313 
00314             //RotY dRotY
00315             if (m_ipo_channels_active[OB_SIZE_Y]) {
00316                 newScale[1] = (m_ipo_channels_active[OB_DSIZE_Y] ? (m_ipo_xform.GetScaling()[1] + m_ipo_xform.GetDeltaScaling()[1]): m_ipo_xform.GetScaling()[1]);
00317             }
00318             else if (m_ipo_channels_active[OB_DSIZE_Y] && m_ipo_start_initialized) {
00319                 newScale[1] = (m_ipo_xform.GetDeltaScaling()[1] + ((!m_ipo_add)?m_ipo_start_scale[1]:0.0));
00320             }
00321             
00322             //RotZ and dRotZ
00323             if (m_ipo_channels_active[OB_SIZE_Z]) {
00324                 newScale[2] = (m_ipo_channels_active[OB_DSIZE_Z] ? (m_ipo_xform.GetScaling()[2] + m_ipo_xform.GetDeltaScaling()[2]) : m_ipo_xform.GetScaling()[2]);
00325             }
00326             else if (m_ipo_channels_active[OB_DSIZE_Z] && m_ipo_start_initialized) {
00327                 newScale[2] = (m_ipo_xform.GetDeltaScaling()[2] + ((!m_ipo_add)?m_ipo_start_scale[2]:1.0));
00328             }
00329 
00330             if (m_ipo_add) {
00331                 newScale = m_ipo_start_scale * newScale;
00332             }
00333             if (m_game_object)
00334                 m_game_object->NodeSetLocalScale(newScale);
00335         }
00336 
00337         m_modified=false;
00338     }
00339     return false;
00340 }
00341 
00342 
00343 void KX_IpoSGController::AddInterpolator(KX_IInterpolator* interp)
00344 {
00345     this->m_interpolators.push_back(interp);
00346 }
00347 
00348 SG_Controller*  KX_IpoSGController::GetReplica(class SG_Node* destnode)
00349 {
00350     KX_IpoSGController* iporeplica = new KX_IpoSGController(*this);
00351     // clear object that ipo acts on in the replica.
00352     iporeplica->ClearObject();
00353     iporeplica->SetGameObject((KX_GameObject*)destnode->GetSGClientObject());
00354 
00355     // dirty hack, ask Gino for a better solution in the ipo implementation
00356     // hacken en zagen, in what we call datahiding, not written for replication :(
00357 
00358     T_InterpolatorList oldlist = m_interpolators;
00359     iporeplica->m_interpolators.clear();
00360 
00361     T_InterpolatorList::iterator i;
00362     for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
00363         KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
00364         iporeplica->AddInterpolator(copyipo);
00365 
00366         MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
00367         uint_ptr orgbase = (uint_ptr)&m_ipo_xform;
00368         uint_ptr orgloc = (uint_ptr)scaal;
00369         uint_ptr offset = orgloc-orgbase;
00370         uint_ptr newaddrbase = (uint_ptr)&iporeplica->m_ipo_xform;
00371         newaddrbase += offset;
00372         MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
00373         copyipo->SetNewTarget((MT_Scalar*)blaptr);
00374     }
00375     
00376     return iporeplica;
00377 }
00378 
00379 KX_IpoSGController::~KX_IpoSGController()
00380 {
00381 
00382     T_InterpolatorList::iterator i;
00383     for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
00384         delete (*i);
00385     }
00386     
00387 }