Merge from trunk
[blender.git] / source / gameengine / GameLogic / SCA_ISensor.cpp
1 /**
2  * Abstract class for sensor logic bricks
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL 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.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include "SCA_ISensor.h"
33 #include "SCA_EventManager.h"
34 #include "SCA_LogicManager.h"
35 // needed for IsTriggered()
36 #include "SCA_PythonController.h"
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 /* Native functions */
43 void    SCA_ISensor::ReParent(SCA_IObject* parent)
44 {
45         SCA_ILogicBrick::ReParent(parent);
46         // will be done when the sensor is activated
47         //m_eventmgr->RegisterSensor(this);
48         this->SetActive(false);
49 }
50
51
52 SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
53                                                  class SCA_EventManager* eventmgr,
54                                                  PyTypeObject* T ) :
55         SCA_ILogicBrick(gameobj,T),
56         m_triggered(false)
57 {
58         m_links = 0;
59         m_suspended = false;
60         m_invert = false;
61         m_level = false;
62         m_reset = false;
63         m_pos_ticks = 0;
64         m_neg_ticks = 0;
65         m_pos_pulsemode = false;
66         m_neg_pulsemode = false;
67         m_pulse_frequency = 0;
68         
69         m_eventmgr = eventmgr;
70 }
71
72
73 SCA_ISensor::~SCA_ISensor()  
74 {
75         // intentionally empty
76 }
77
78 bool SCA_ISensor::IsPositiveTrigger() { 
79         bool result = false;
80         
81         if (m_eventval) {
82                 result = (m_eventval->GetNumber() != 0.0);
83         }
84         if (m_invert) {
85                 result = !result;
86         }
87         
88         return result;
89 }
90
91 void SCA_ISensor::SetPulseMode(bool posmode, 
92                                                            bool negmode,
93                                                            int freq) {
94         m_pos_pulsemode = posmode;
95         m_neg_pulsemode = negmode;
96         m_pulse_frequency = freq;
97 }
98
99 void SCA_ISensor::SetInvert(bool inv) {
100         m_invert = inv;
101 }
102
103 void SCA_ISensor::SetLevel(bool lvl) {
104         m_level = lvl;
105 }
106
107
108 float SCA_ISensor::GetNumber() {
109         return IsPositiveTrigger();
110 }
111
112 void SCA_ISensor::Suspend() {
113         m_suspended = true;
114 }
115
116 bool SCA_ISensor::IsSuspended() {
117         return m_suspended;
118 }
119
120 void SCA_ISensor::Resume() {
121         m_suspended = false;
122 }
123
124 void SCA_ISensor::Init() {
125         printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name.Ptr());
126 }
127
128 void SCA_ISensor::DecLink() {
129         m_links--;
130         if (m_links < 0) 
131         {
132                 printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
133                 m_links = 0;
134         }
135         if (!m_links)
136         {
137                 // sensor is detached from all controllers, remove it from manager
138                 UnregisterToManager();
139         }
140 }
141
142 /* python integration */
143
144 PyTypeObject SCA_ISensor::Type = {
145         PyObject_HEAD_INIT(&PyType_Type)
146         0,
147         "SCA_ISensor",
148         sizeof(SCA_ISensor),
149         0,
150         PyDestructor,
151         0,
152         __getattr,
153         __setattr,
154         0, //&MyPyCompare,
155         __repr,
156         0, //&cvalue_as_number,
157         0,
158         0,
159         0,
160         0
161 };
162
163 PyParentObject SCA_ISensor::Parents[] = {
164         &SCA_ISensor::Type,
165         &SCA_ILogicBrick::Type,
166         &CValue::Type,
167         NULL
168 };
169 PyMethodDef SCA_ISensor::Methods[] = {
170         {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, 
171          METH_NOARGS, IsPositive_doc},
172         {"isTriggered", (PyCFunction) SCA_ISensor::sPyIsTriggered, 
173          METH_VARARGS, IsTriggered_doc},
174         {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, 
175          METH_NOARGS, GetUsePosPulseMode_doc},
176         {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, 
177          METH_VARARGS, SetUsePosPulseMode_doc},
178         {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency, 
179          METH_NOARGS, GetFrequency_doc},
180         {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency, 
181          METH_VARARGS, SetFrequency_doc},
182         {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode, 
183          METH_NOARGS, GetUseNegPulseMode_doc},
184         {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode, 
185          METH_VARARGS, SetUseNegPulseMode_doc},
186         {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert, 
187          METH_NOARGS, GetInvert_doc},
188         {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert, 
189          METH_VARARGS, SetInvert_doc},
190         {"getLevel", (PyCFunction) SCA_ISensor::sPyGetLevel, 
191          METH_NOARGS, GetLevel_doc},
192         {"setLevel", (PyCFunction) SCA_ISensor::sPySetLevel, 
193          METH_VARARGS, SetLevel_doc},
194         {"reset", (PyCFunction) SCA_ISensor::sPyReset, 
195          METH_NOARGS, Reset_doc},
196         {NULL,NULL} //Sentinel
197 };
198
199
200 PyObject*
201 SCA_ISensor::_getattr(const STR_String& attr)
202 {
203   _getattr_up(SCA_ILogicBrick);
204 }
205
206
207 void SCA_ISensor::RegisterToManager()
208 {
209         // sensor is just activated, initialize it
210         Init();
211         m_newControllers.erase(m_newControllers.begin(), m_newControllers.end());
212         m_eventmgr->RegisterSensor(this);
213 }
214
215 void SCA_ISensor::UnregisterToManager()
216 {
217         m_eventmgr->RemoveSensor(this);
218 }
219
220 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr,      CValue* event)
221 {
222         
223         // calculate if a __triggering__ is wanted
224         // don't evaluate a sensor that is not connected to any controller
225         if (m_links && !m_suspended) {
226                 bool result = this->Evaluate(event);
227                 if (result) {
228                         logicmgr->AddActivatedSensor(this);     
229                         // reset these counters so that pulse are synchronized with transition
230                         m_pos_ticks = 0;
231                         m_neg_ticks = 0;
232                 } else
233                 {
234                         /* First, the pulsing behaviour, if pulse mode is
235                          * active. It seems something goes wrong if pulse mode is
236                          * not set :( */
237                         if (m_pos_pulsemode) {
238                                 m_pos_ticks++;
239                                 if (m_pos_ticks > m_pulse_frequency) {
240                                         if ( this->IsPositiveTrigger() )
241                                         {
242                                                 logicmgr->AddActivatedSensor(this);
243                                         }
244                                         m_pos_ticks = 0;
245                                 } 
246                         }
247                         
248                         if (m_neg_pulsemode)
249                         {
250                                 m_neg_ticks++;
251                                 if (m_neg_ticks > m_pulse_frequency) {
252                                         if (!this->IsPositiveTrigger() )
253                                         {
254                                                 logicmgr->AddActivatedSensor(this);
255                                         }
256                                         m_neg_ticks = 0;
257                                 }
258                         }
259                 }
260                 if (!m_newControllers.empty())
261                 {
262                         if (!IsActive() && m_level)
263                         {
264                                 // This level sensor is connected to at least one controller that was just made 
265                                 // active but it did not generate an event yet, do it now to those controllers only 
266                                 for (std::vector<SCA_IController*>::iterator ci=m_newControllers.begin();
267                                          ci != m_newControllers.end(); ci++)
268                                 {
269                                         logicmgr->AddTriggeredController(*ci, this);
270                                 }
271                         }
272                         // clear the list. Instead of using clear, which also release the memory,
273                         // use erase, which keeps the memory available for next time.
274                         m_newControllers.erase(m_newControllers.begin(), m_newControllers.end());
275                 }
276         } 
277 }
278
279 /* Python functions: */
280 char SCA_ISensor::IsPositive_doc[] = 
281 "isPositive()\n"
282 "\tReturns whether the sensor is in an active state.\n";
283 PyObject* SCA_ISensor::PyIsPositive(PyObject* self)
284 {
285         int retval = IsPositiveTrigger();
286         return PyInt_FromLong(retval);
287 }
288
289 char SCA_ISensor::IsTriggered_doc[] = 
290 "isTriggered()\n"
291 "\tReturns whether the sensor has triggered the current controller.\n";
292 PyObject* SCA_ISensor::PyIsTriggered(PyObject* self)
293 {
294         // check with the current controller
295         int retval = 0;
296         if (SCA_PythonController::m_sCurrentController)
297                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(this);
298         return PyInt_FromLong(retval);
299 }
300
301 /**
302  * getUsePulseMode: getter for the pulse mode (KX_TRUE = on)
303  */
304 char SCA_ISensor::GetUsePosPulseMode_doc[] = 
305 "getUsePosPulseMode()\n"
306 "\tReturns whether positive pulse mode is active.\n";
307 PyObject* SCA_ISensor::PyGetUsePosPulseMode(PyObject* self)
308 {
309         return BoolToPyArg(m_pos_pulsemode);
310 }
311
312 /**
313  * setUsePulseMode: setter for the pulse mode (KX_TRUE = on)
314  */
315 char SCA_ISensor::SetUsePosPulseMode_doc[] = 
316 "setUsePosPulseMode(pulse?)\n"
317 "\t - pulse? : Pulse when a positive event occurs?\n"
318 "\t            (KX_TRUE, KX_FALSE)\n"
319 "\tSet whether to do pulsing when positive pulses occur.\n";
320 PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
321 {
322         int pyarg = 0;
323         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
324         m_pos_pulsemode = PyArgToBool(pyarg);
325         Py_Return;
326 }
327
328 /**
329  * getFrequency: getter for the pulse mode interval
330  */
331 char SCA_ISensor::GetFrequency_doc[] = 
332 "getFrequency()\n"
333 "\tReturns the frequency of the updates in pulse mode.\n" ;
334 PyObject* SCA_ISensor::PyGetFrequency(PyObject* self)
335 {
336         return PyInt_FromLong(m_pulse_frequency);
337 }
338
339 /**
340  * setFrequency: setter for the pulse mode (KX_TRUE = on)
341  */
342 char SCA_ISensor::SetFrequency_doc[] = 
343 "setFrequency(pulse_frequency)\n"
344 "\t- pulse_frequency: The frequency of the updates in pulse mode (integer)"
345 "\tSet the frequency of the updates in pulse mode.\n"
346 "\tIf the frequency is negative, it is set to 0.\n" ;
347 PyObject* SCA_ISensor::PySetFrequency(PyObject* self, PyObject* args, PyObject* kwds)
348 {
349         int pulse_frequencyArg = 0;
350
351         if(!PyArg_ParseTuple(args, "i", &pulse_frequencyArg)) {
352                 return NULL;
353         }
354         
355         /* We can do three things here: clip, ignore and raise an exception.  */
356         /* Exceptions don't work yet, ignoring is not desirable now...        */
357         if (pulse_frequencyArg < 0) {
358                 pulse_frequencyArg = 0;
359         };      
360         m_pulse_frequency = pulse_frequencyArg;
361
362         Py_Return;
363 }
364
365
366 char SCA_ISensor::GetInvert_doc[] = 
367 "getInvert()\n"
368 "\tReturns whether or not pulses from this sensor are inverted.\n" ;
369 PyObject* SCA_ISensor::PyGetInvert(PyObject* self)
370 {
371         return BoolToPyArg(m_invert);
372 }
373
374 char SCA_ISensor::SetInvert_doc[] = 
375 "setInvert(invert?)\n"
376 "\t- invert?: Invert the event-values? (KX_TRUE, KX_FALSE)\n"
377 "\tSet whether to invert pulses.\n";
378 PyObject* SCA_ISensor::PySetInvert(PyObject* self, PyObject* args, PyObject* kwds)
379 {
380         int pyarg = 0;
381         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
382         m_invert = PyArgToBool(pyarg);
383         Py_Return;
384 }
385
386 char SCA_ISensor::GetLevel_doc[] = 
387 "getLevel()\n"
388 "\tReturns whether this sensor is a level detector or a edge detector.\n"
389 "\tIt makes a difference only in case of logic state transition (state actuator).\n"
390 "\tA level detector will immediately generate a pulse, negative or positive\n"
391 "\tdepending on the sensor condition, as soon as the state is activated.\n"
392 "\tA edge detector will wait for a state change before generating a pulse.\n";
393 PyObject* SCA_ISensor::PyGetLevel(PyObject* self)
394 {
395         return BoolToPyArg(m_level);
396 }
397
398 char SCA_ISensor::SetLevel_doc[] = 
399 "setLevel(level?)\n"
400 "\t- level?: Detect level instead of edge? (KX_TRUE, KX_FALSE)\n"
401 "\tSet whether to detect level or edge transition when entering a state.\n";
402 PyObject* SCA_ISensor::PySetLevel(PyObject* self, PyObject* args, PyObject* kwds)
403 {
404         int pyarg = 0;
405         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
406         m_level = PyArgToBool(pyarg);
407         Py_Return;
408 }
409
410 char SCA_ISensor::GetUseNegPulseMode_doc[] = 
411 "getUseNegPulseMode()\n"
412 "\tReturns whether negative pulse mode is active.\n";
413 PyObject* SCA_ISensor::PyGetUseNegPulseMode(PyObject* self)
414 {
415         return BoolToPyArg(m_neg_pulsemode);
416 }
417
418 char SCA_ISensor::SetUseNegPulseMode_doc[] = 
419 "setUseNegPulseMode(pulse?)\n"
420 "\t - pulse? : Pulse when a negative event occurs?\n"
421 "\t            (KX_TRUE, KX_FALSE)\n"
422 "\tSet whether to do pulsing when negative pulses occur.\n";
423 PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
424 {
425         int pyarg = 0;
426         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
427         m_neg_pulsemode = PyArgToBool(pyarg);
428         Py_Return;
429 }
430
431 char SCA_ISensor::Reset_doc[] = 
432 "reset()\n"
433 "\tReset sensor internal state, effect depends on the type of sensor and settings.\n"
434 "\tThe sensor is put in its initial state as if it was just activated.\n";
435 PyObject* SCA_ISensor::PyReset(PyObject* self)
436 {
437         Init();
438         Py_Return;
439 }
440
441
442 /* eof */