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 * 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 }