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