|
Blender
V2.59
|
00001 /* 00002 * KX_CameraActuator.cpp 00003 * 00004 * $Id: KX_CameraActuator.cpp 37455 2011-06-13 17:08:33Z dfelinto $ 00005 * 00006 * ***** BEGIN GPL LICENSE BLOCK ***** 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00023 * All rights reserved. 00024 * 00025 * The Original Code is: all of this file. 00026 * 00027 * Contributor(s): none yet. 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 * 00031 */ 00032 00038 #include "KX_CameraActuator.h" 00039 #include <iostream> 00040 #include <math.h> 00041 #include <float.h> 00042 #include "KX_GameObject.h" 00043 00044 #include "PyObjectPlus.h" 00045 00046 00047 /* ------------------------------------------------------------------------- */ 00048 /* Native functions */ 00049 /* ------------------------------------------------------------------------- */ 00050 00051 KX_CameraActuator::KX_CameraActuator( 00052 SCA_IObject* gameobj, 00053 SCA_IObject *obj, 00054 float hght, 00055 float minhght, 00056 float maxhght, 00057 bool xytog, 00058 float damping 00059 ): 00060 SCA_IActuator(gameobj, KX_ACT_CAMERA), 00061 m_ob (obj), 00062 m_height (hght), 00063 m_minHeight (minhght), 00064 m_maxHeight (maxhght), 00065 m_x (xytog), 00066 m_damping (damping) 00067 { 00068 if (m_ob) 00069 m_ob->RegisterActuator(this); 00070 } 00071 00072 KX_CameraActuator::~KX_CameraActuator() 00073 { 00074 if (m_ob) 00075 m_ob->UnregisterActuator(this); 00076 } 00077 00078 CValue* 00079 KX_CameraActuator:: 00080 GetReplica( 00081 ) { 00082 KX_CameraActuator* replica = new KX_CameraActuator(*this); 00083 replica->ProcessReplica(); 00084 return replica; 00085 }; 00086 00087 void KX_CameraActuator::ProcessReplica() 00088 { 00089 if (m_ob) 00090 m_ob->RegisterActuator(this); 00091 SCA_IActuator::ProcessReplica(); 00092 } 00093 00094 bool KX_CameraActuator::UnlinkObject(SCA_IObject* clientobj) 00095 { 00096 if (clientobj == m_ob) 00097 { 00098 // this object is being deleted, we cannot continue to track it. 00099 m_ob = NULL; 00100 return true; 00101 } 00102 return false; 00103 } 00104 00105 00106 void KX_CameraActuator::Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map) 00107 { 00108 void **h_obj = (*obj_map)[m_ob]; 00109 if (h_obj) { 00110 if (m_ob) 00111 m_ob->UnregisterActuator(this); 00112 m_ob = (SCA_IObject*)(*h_obj); 00113 m_ob->RegisterActuator(this); 00114 } 00115 } 00116 00117 /* three functions copied from blender arith... don't know if there's an equivalent */ 00118 00119 static float Kx_Normalize(float *n) 00120 { 00121 float d; 00122 00123 d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; 00124 /* FLT_EPSILON is too large! A larger value causes normalize errors in a scaled down utah teapot */ 00125 if(d>0.0000000000001) { 00126 d= sqrt(d); 00127 00128 n[0]/=d; 00129 n[1]/=d; 00130 n[2]/=d; 00131 } else { 00132 n[0]=n[1]=n[2]= 0.0; 00133 d= 0.0; 00134 } 00135 return d; 00136 } 00137 00138 static void Kx_Crossf(float *c, float *a, float *b) 00139 { 00140 c[0] = a[1] * b[2] - a[2] * b[1]; 00141 c[1] = a[2] * b[0] - a[0] * b[2]; 00142 c[2] = a[0] * b[1] - a[1] * b[0]; 00143 } 00144 00145 00146 static void Kx_VecUpMat3(float *vec, float mat[][3], short axis) 00147 { 00148 00149 // Construct a camera matrix s.t. the specified axis 00150 00151 // maps to the given vector (*vec). Also defines the rotation 00152 00153 // about this axis by mapping one of the other axis to the y-axis. 00154 00155 00156 float inp; 00157 short cox = 0, coy = 0, coz = 0; 00158 00159 /* up varieeren heeft geen zin, is eigenlijk helemaal geen up! 00160 * zie VecUpMat3old 00161 */ 00162 00163 if(axis==0) { 00164 cox= 0; coy= 1; coz= 2; /* Y up Z tr */ 00165 } 00166 if(axis==1) { 00167 cox= 1; coy= 2; coz= 0; /* Z up X tr */ 00168 } 00169 if(axis==2) { 00170 cox= 2; coy= 0; coz= 1; /* X up Y tr */ 00171 } 00172 if(axis==3) { 00173 cox= 0; coy= 1; coz= 2; /* Y op -Z tr */ 00174 vec[0]= -vec[0]; 00175 vec[1]= -vec[1]; 00176 vec[2]= -vec[2]; 00177 } 00178 if(axis==4) { 00179 cox= 1; coy= 0; coz= 2; /* */ 00180 } 00181 if(axis==5) { 00182 cox= 2; coy= 1; coz= 0; /* Y up X tr */ 00183 } 00184 00185 mat[coz][0]= vec[0]; 00186 mat[coz][1]= vec[1]; 00187 mat[coz][2]= vec[2]; 00188 if (Kx_Normalize((float *)mat[coz]) == 0.f) { 00189 /* this is a very abnormal situation: the camera has reach the object center exactly 00190 We will choose a completely arbitrary direction */ 00191 mat[coz][0] = 1.0f; 00192 mat[coz][1] = 0.0f; 00193 mat[coz][2] = 0.0f; 00194 } 00195 00196 inp= mat[coz][2]; 00197 mat[coy][0]= - inp*mat[coz][0]; 00198 mat[coy][1]= - inp*mat[coz][1]; 00199 mat[coy][2]= 1.0 - inp*mat[coz][2]; 00200 00201 if (Kx_Normalize((float *)mat[coy]) == 0.f) { 00202 /* the camera is vertical, chose the y axis arbitrary */ 00203 mat[coy][0] = 0.f; 00204 mat[coy][1] = 1.f; 00205 mat[coy][2] = 0.f; 00206 } 00207 00208 Kx_Crossf(mat[cox], mat[coy], mat[coz]); 00209 00210 } 00211 00212 bool KX_CameraActuator::Update(double curtime, bool frame) 00213 { 00214 /* wondering... is it really neccesary/desirable to suppress negative */ 00215 /* events here? */ 00216 bool bNegativeEvent = IsNegativeEvent(); 00217 RemoveAllEvents(); 00218 00219 if (bNegativeEvent || !m_ob) 00220 return false; 00221 00222 KX_GameObject *obj = (KX_GameObject*) GetParent(); 00223 MT_Point3 from = obj->NodeGetWorldPosition(); 00224 MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation(); 00225 /* These casts are _very_ dangerous!!! */ 00226 MT_Point3 lookat = ((KX_GameObject*)m_ob)->NodeGetWorldPosition(); 00227 MT_Matrix3x3 actormat = ((KX_GameObject*)m_ob)->NodeGetWorldOrientation(); 00228 00229 float fp1[3], fp2[3], rc[3]; 00230 float inp, fac; //, factor = 0.0; /* some factor... */ 00231 float mindistsq, maxdistsq, distsq; 00232 float mat[3][3]; 00233 00234 /* The rules: */ 00235 /* CONSTRAINT 1: not implemented */ 00236 /* CONSTRAINT 2: can camera see actor? */ 00237 /* CONSTRAINT 3: fixed height relative to floor below actor. */ 00238 /* CONSTRAINT 4: camera rotates behind actor */ 00239 /* CONSTRAINT 5: minimum / maximum distance */ 00240 /* CONSTRAINT 6: again: fixed height relative to floor below actor */ 00241 /* CONSTRAINT 7: track to floor below actor */ 00242 /* CONSTRAINT 8: look a little bit left or right, depending on how the 00243 00244 character is looking (horizontal x) 00245 */ 00246 00247 /* ...and then set the camera position. Since we assume the parent of */ 00248 /* this actuator is always a camera, just set the parent position and */ 00249 /* rotation. We do not check whether we really have a camera as parent. */ 00250 /* It may be better to turn this into a general tracking actuator later */ 00251 /* on, since lots of plausible relations can be filled in here. */ 00252 00253 /* ... set up some parameters ... */ 00254 /* missing here: the 'floorloc' of the actor's shadow */ 00255 00256 mindistsq= m_minHeight*m_minHeight; 00257 maxdistsq= m_maxHeight*m_maxHeight; 00258 00259 /* C1: not checked... is a future option */ 00260 00261 /* C2: blender test_visibility function. Can this be a ray-test? */ 00262 00263 /* C3: fixed height */ 00264 from[2] = (15.0*from[2] + lookat[2] + m_height)/16.0; 00265 00266 00267 /* C4: camera behind actor */ 00268 if (m_x) { 00269 fp1[0] = actormat[0][0]; 00270 fp1[1] = actormat[1][0]; 00271 fp1[2] = actormat[2][0]; 00272 00273 fp2[0] = frommat[0][0]; 00274 fp2[1] = frommat[1][0]; 00275 fp2[2] = frommat[2][0]; 00276 } 00277 else { 00278 fp1[0] = actormat[0][1]; 00279 fp1[1] = actormat[1][1]; 00280 fp1[2] = actormat[2][1]; 00281 00282 fp2[0] = frommat[0][1]; 00283 fp2[1] = frommat[1][1]; 00284 fp2[2] = frommat[2][1]; 00285 } 00286 00287 inp= fp1[0]*fp2[0] + fp1[1]*fp2[1] + fp1[2]*fp2[2]; 00288 fac= (-1.0 + inp) * m_damping; 00289 00290 from[0]+= fac*fp1[0]; 00291 from[1]+= fac*fp1[1]; 00292 from[2]+= fac*fp1[2]; 00293 00294 /* alleen alstie ervoor ligt: cross testen en loodrechte bijtellen */ 00295 if(inp<0.0) { 00296 if(fp1[0]*fp2[1] - fp1[1]*fp2[0] > 0.0) { 00297 from[0]-= fac*fp1[1]; 00298 from[1]+= fac*fp1[0]; 00299 } 00300 else { 00301 from[0]+= fac*fp1[1]; 00302 from[1]-= fac*fp1[0]; 00303 } 00304 } 00305 00306 /* CONSTRAINT 5: minimum / maximum afstand */ 00307 00308 rc[0]= (lookat[0]-from[0]); 00309 rc[1]= (lookat[1]-from[1]); 00310 rc[2]= (lookat[2]-from[2]); 00311 distsq= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2]; 00312 00313 if(distsq > maxdistsq) { 00314 distsq = 0.15*(distsq-maxdistsq)/distsq; 00315 00316 from[0] += distsq*rc[0]; 00317 from[1] += distsq*rc[1]; 00318 from[2] += distsq*rc[2]; 00319 } 00320 else if(distsq < mindistsq) { 00321 distsq = 0.15*(mindistsq-distsq)/mindistsq; 00322 00323 from[0] -= distsq*rc[0]; 00324 from[1] -= distsq*rc[1]; 00325 from[2] -= distsq*rc[2]; 00326 } 00327 00328 00329 /* CONSTRAINT 7: track to schaduw */ 00330 rc[0]= (lookat[0]-from[0]); 00331 rc[1]= (lookat[1]-from[1]); 00332 rc[2]= (lookat[2]-from[2]); 00333 Kx_VecUpMat3(rc, mat, 3); /* y up Track -z */ 00334 00335 00336 00337 00338 /* now set the camera position and rotation */ 00339 00340 obj->NodeSetLocalPosition(from); 00341 00342 actormat[0][0]= mat[0][0]; actormat[0][1]= mat[1][0]; actormat[0][2]= mat[2][0]; 00343 actormat[1][0]= mat[0][1]; actormat[1][1]= mat[1][1]; actormat[1][2]= mat[2][1]; 00344 actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2]; 00345 obj->NodeSetLocalOrientation(actormat); 00346 00347 return true; 00348 } 00349 00350 CValue *KX_CameraActuator::findObject(char *obName) 00351 { 00352 /* hook to object system */ 00353 return NULL; 00354 } 00355 00356 #ifdef WITH_PYTHON 00357 00358 /* ------------------------------------------------------------------------- */ 00359 /* Python functions */ 00360 /* ------------------------------------------------------------------------- */ 00361 00362 /* Integration hooks ------------------------------------------------------- */ 00363 PyTypeObject KX_CameraActuator::Type = { 00364 PyVarObject_HEAD_INIT(NULL, 0) 00365 "KX_CameraActuator", 00366 sizeof(PyObjectPlus_Proxy), 00367 0, 00368 py_base_dealloc, 00369 0, 00370 0, 00371 0, 00372 0, 00373 py_base_repr, 00374 0,0,0,0,0,0,0,0,0, 00375 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 00376 0,0,0,0,0,0,0, 00377 Methods, 00378 0, 00379 0, 00380 &SCA_IActuator::Type, 00381 0,0,0,0,0,0, 00382 py_base_new 00383 }; 00384 00385 PyMethodDef KX_CameraActuator::Methods[] = { 00386 {NULL, NULL} //Sentinel 00387 }; 00388 00389 PyAttributeDef KX_CameraActuator::Attributes[] = { 00390 KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_minHeight), 00391 KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_maxHeight), 00392 KX_PYATTRIBUTE_FLOAT_RW("height",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_height), 00393 KX_PYATTRIBUTE_BOOL_RW("useXY",KX_CameraActuator,m_x), 00394 KX_PYATTRIBUTE_RW_FUNCTION("object", KX_CameraActuator, pyattr_get_object, pyattr_set_object), 00395 KX_PYATTRIBUTE_FLOAT_RW("damping",0.f,10.f,KX_CameraActuator,m_damping), 00396 {NULL} 00397 }; 00398 00399 PyObject* KX_CameraActuator::pyattr_get_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 00400 { 00401 KX_CameraActuator* self= static_cast<KX_CameraActuator*>(self_v); 00402 if (self->m_ob==NULL) 00403 Py_RETURN_NONE; 00404 else 00405 return self->m_ob->GetProxy(); 00406 } 00407 00408 int KX_CameraActuator::pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00409 { 00410 KX_CameraActuator* self= static_cast<KX_CameraActuator*>(self_v); 00411 KX_GameObject *gameobj; 00412 00413 if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_CameraActuator")) 00414 return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error 00415 00416 if (self->m_ob) 00417 self->m_ob->UnregisterActuator(self); 00418 00419 if ((self->m_ob = (SCA_IObject*)gameobj)) 00420 self->m_ob->RegisterActuator(self); 00421 00422 return PY_SET_ATTR_SUCCESS; 00423 } 00424 00425 #endif // WITH_PYTHON 00426 00427 /* eof */