4952c1050a78ebe17282a68ad7653fa6d2e6e3fa
[blender.git] / source / gameengine / Ketsji / KX_CameraActuator.cpp
1 /**
2  * KX_CameraActuator.cpp
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  *
34  */
35
36 #include "KX_CameraActuator.h"
37 #include <iostream>
38 #include <math.h>
39 #include "KX_GameObject.h"
40
41 STR_String KX_CameraActuator::X_AXIS_STRING = "x";
42 STR_String KX_CameraActuator::Y_AXIS_STRING = "y";
43
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48
49 /* ------------------------------------------------------------------------- */
50 /* Native functions                                                          */
51 /* ------------------------------------------------------------------------- */
52
53 KX_CameraActuator::KX_CameraActuator(
54         SCA_IObject* gameobj, 
55         const CValue *obj,
56         MT_Scalar hght,
57         MT_Scalar minhght,
58         MT_Scalar maxhght,
59         bool  xytog,
60         PyTypeObject* T
61 ): 
62         SCA_IActuator(gameobj, T),
63         m_ob (obj),
64         m_height (hght),
65         m_minHeight (minhght),
66         m_maxHeight (maxhght),
67         m_x (xytog)
68 {
69         // nothing to do
70 }
71
72 KX_CameraActuator::~KX_CameraActuator()
73 {
74         //nothing to do
75 }
76
77         CValue* 
78 KX_CameraActuator::
79 GetReplica(
80 ) {
81         KX_CameraActuator* replica = new KX_CameraActuator(*this);
82         replica->ProcessReplica();
83         // this will copy properties and so on...
84         CValue::AddDataToReplica(replica);
85         return replica;
86 };
87
88
89
90
91 /* three functions copied from blender arith... don't know if there's an equivalent */
92
93 float Normalise(float *n)
94 {
95         float d;
96         
97         d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
98         /* FLT_EPSILON is too large! A larger value causes normalise errors in a scaled down utah teapot */
99         if(d>0.0000000000001) {
100                 d= sqrt(d);
101
102                 n[0]/=d; 
103                 n[1]/=d; 
104                 n[2]/=d;
105         } else {
106                 n[0]=n[1]=n[2]= 0.0;
107                 d= 0.0;
108         }
109         return d;
110 }
111
112 void Crossf(float *c, float *a, float *b)
113 {
114         c[0] = a[1] * b[2] - a[2] * b[1];
115         c[1] = a[2] * b[0] - a[0] * b[2];
116         c[2] = a[0] * b[1] - a[1] * b[0];
117 }
118
119
120 void VecUpMat3(float *vec, float mat[][3], short axis)
121 {
122
123         // Construct a camera matrix s.t. the specified axis
124
125         // maps to the given vector (*vec). Also defines the rotation
126
127         // about this axis by mapping one of the other axis to the y-axis.
128
129
130         float inp;
131         short cox = 0, coy = 0, coz = 0;
132         
133         /* up varieeren heeft geen zin, is eigenlijk helemaal geen up!
134          * zie VecUpMat3old
135          */
136
137         if(axis==0) {
138                 cox= 0; coy= 1; coz= 2;         /* Y up Z tr */
139         }
140         if(axis==1) {
141                 cox= 1; coy= 2; coz= 0;         /* Z up X tr */
142         }
143         if(axis==2) {
144                 cox= 2; coy= 0; coz= 1;         /* X up Y tr */
145         }
146         if(axis==3) {
147                 cox= 0; coy= 1; coz= 2;         /* Y op -Z tr */
148                 vec[0]= -vec[0];
149                 vec[1]= -vec[1];
150                 vec[2]= -vec[2];
151         }
152         if(axis==4) {
153                 cox= 1; coy= 0; coz= 2;         /*  */
154         }
155         if(axis==5) {
156                 cox= 2; coy= 1; coz= 0;         /* Y up X tr */
157         }
158
159         mat[coz][0]= vec[0];
160         mat[coz][1]= vec[1];
161         mat[coz][2]= vec[2];
162         Normalise((float *)mat[coz]);
163         
164         inp= mat[coz][2];
165         mat[coy][0]= - inp*mat[coz][0];
166         mat[coy][1]= - inp*mat[coz][1];
167         mat[coy][2]= 1.0 - inp*mat[coz][2];
168
169         Normalise((float *)mat[coy]);
170         
171         Crossf(mat[cox], mat[coy], mat[coz]);
172         
173 }
174
175 bool KX_CameraActuator::Update(double curtime, bool frame)
176 {
177         bool result = true;
178
179         KX_GameObject *obj = (KX_GameObject*) GetParent();
180         MT_Point3 from = obj->NodeGetWorldPosition();
181         MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation();
182         /* These casts are _very_ dangerous!!! */
183         MT_Point3 lookat = ((KX_GameObject*)m_ob)->NodeGetWorldPosition();
184         MT_Matrix3x3 actormat = ((KX_GameObject*)m_ob)->NodeGetWorldOrientation();
185
186         float fp1[3], fp2[3], rc[3];
187         float inp, fac; //, factor = 0.0; /* some factor...                                    */
188         float mindistsq, maxdistsq, distsq;
189         float mat[3][3];
190         
191         /* wondering... is it really neccesary/desirable to suppress negative    */
192         /* events here?                                                          */
193         bool bNegativeEvent = IsNegativeEvent();
194         RemoveAllEvents();
195
196         if (bNegativeEvent) return false;
197         
198         /* The rules:                                                            */
199         /* CONSTRAINT 1: not implemented */
200         /* CONSTRAINT 2: can camera see actor?              */
201         /* CONSTRAINT 3: fixed height relative to floor below actor.             */
202         /* CONSTRAINT 4: camera rotates behind actor                              */
203         /* CONSTRAINT 5: minimum / maximum distance                             */
204         /* CONSTRAINT 6: again: fixed height relative to floor below actor        */
205         /* CONSTRAINT 7: track to floor below actor                               */
206         /* CONSTRAINT 8: look a little bit left or right, depending on how the
207
208            character is looking (horizontal x)
209  */
210
211         /* ...and then set the camera position. Since we assume the parent of    */
212         /* this actuator is always a camera, just set the parent position and    */
213         /* rotation. We do not check whether we really have a camera as parent.  */
214         /* It may be better to turn this into a general tracking actuator later  */
215         /* on, since lots of plausible relations can be filled in here.          */
216
217         /* ... set up some parameters ...                                        */
218         /* missing here: the 'floorloc' of the actor's shadow */
219
220         mindistsq= m_minHeight*m_minHeight;
221         maxdistsq= m_maxHeight*m_maxHeight;
222
223         /* C1: not checked... is a future option                                 */
224
225         /* C2: blender test_visibility function. Can this be a ray-test?         */
226
227         /* C3: fixed height  */
228         from[2] = (15.0*from[2] + lookat[2] + m_height)/16.0;
229
230
231         /* C4: camera behind actor   */
232         if (m_x) {
233                 fp1[0] = actormat[0][0];
234                 fp1[1] = actormat[1][0];
235                 fp1[2] = actormat[2][0];
236
237                 fp2[0] = frommat[0][0];
238                 fp2[1] = frommat[1][0];
239                 fp2[2] = frommat[2][0];
240         } 
241         else {
242                 fp1[0] = actormat[0][1];
243                 fp1[1] = actormat[1][1];
244                 fp1[2] = actormat[2][1];
245
246                 fp2[0] = frommat[0][1];
247                 fp2[1] = frommat[1][1];
248                 fp2[2] = frommat[2][1];
249         }
250         
251         inp= fp1[0]*fp2[0] + fp1[1]*fp2[1] + fp1[2]*fp2[2];
252         fac= (-1.0 + inp)/32.0;
253
254         from[0]+= fac*fp1[0];
255         from[1]+= fac*fp1[1];
256         from[2]+= fac*fp1[2];
257         
258         /* alleen alstie ervoor ligt: cross testen en loodrechte bijtellen */
259         if(inp<0.0) {
260                 if(fp1[0]*fp2[1] - fp1[1]*fp2[0] > 0.0) {
261                         from[0]-= fac*fp1[1];
262                         from[1]+= fac*fp1[0];
263                 }
264                 else {
265                         from[0]+= fac*fp1[1];
266                         from[1]-= fac*fp1[0];
267                 }
268         }
269
270         /* CONSTRAINT 5: minimum / maximum afstand */
271
272         rc[0]= (lookat[0]-from[0]);
273         rc[1]= (lookat[1]-from[1]);
274         rc[2]= (lookat[2]-from[2]);
275         distsq= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2];
276
277         if(distsq > maxdistsq) {
278                 distsq = 0.15*(distsq-maxdistsq)/distsq;
279                 
280                 from[0] += distsq*rc[0];
281                 from[1] += distsq*rc[1];
282                 from[2] += distsq*rc[2];
283         }
284         else if(distsq < mindistsq) {
285                 distsq = 0.15*(mindistsq-distsq)/mindistsq;
286                 
287                 from[0] -= distsq*rc[0];
288                 from[1] -= distsq*rc[1];
289                 from[2] -= distsq*rc[2];
290         }
291
292
293         /* CONSTRAINT 7: track to schaduw */
294         rc[0]= (lookat[0]-from[0]);
295         rc[1]= (lookat[1]-from[1]);
296         rc[2]= (lookat[2]-from[2]);
297         VecUpMat3(rc, mat, 3);  /* y up Track -z */
298         
299
300
301
302         /* now set the camera position and rotation */
303         
304         obj->NodeSetLocalPosition(from);
305         
306         actormat[0][0]= mat[0][0]; actormat[0][1]= mat[1][0]; actormat[0][2]= mat[2][0];
307         actormat[1][0]= mat[0][1]; actormat[1][1]= mat[1][1]; actormat[1][2]= mat[2][1];
308         actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2];
309         obj->NodeSetLocalOrientation(actormat);
310
311         return result;
312 }
313
314 CValue *KX_CameraActuator::findObject(char *obName) 
315 {
316         /* hook to object system */
317         return NULL;
318 }
319
320 bool KX_CameraActuator::string2axischoice(const char *axisString) 
321 {
322         bool res = true;
323
324         res = !(axisString == Y_AXIS_STRING);
325
326         return res;
327 }
328
329 /* ------------------------------------------------------------------------- */
330 /* Python functions                                                          */
331 /* ------------------------------------------------------------------------- */
332
333 /* Integration hooks ------------------------------------------------------- */
334 PyTypeObject KX_CameraActuator::Type = {
335         PyObject_HEAD_INIT(&PyType_Type)
336         0,
337         "KX_CameraActuator",
338         sizeof(KX_CameraActuator),
339         0,
340         PyDestructor,
341         0,
342         __getattr,
343         __setattr,
344         0, //&MyPyCompare,
345         __repr,
346         0, //&cvalue_as_number,
347         0,
348         0,
349         0,
350         0
351 };
352
353 PyParentObject KX_CameraActuator::Parents[] = {
354         &KX_CameraActuator::Type,
355         &SCA_IActuator::Type,
356         &SCA_ILogicBrick::Type,
357         &CValue::Type,
358         NULL
359 };
360
361 PyMethodDef KX_CameraActuator::Methods[] = {
362         {NULL,NULL,NULL,NULL} //Sentinel
363 };
364
365 PyObject* KX_CameraActuator::_getattr(const STR_String& attr) {
366         _getattr_up(SCA_IActuator);
367 }
368
369
370 /* eof */