soc-2008-mxcurioni: merged changes to revision 15441
[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
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 /* Native functions */
41 void    SCA_ISensor::ReParent(SCA_IObject* parent)
42 {
43         SCA_ILogicBrick::ReParent(parent);
44         m_eventmgr->RegisterSensor(this);
45         this->SetActive(false);
46 }
47
48
49 SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
50                                                  class SCA_EventManager* eventmgr,
51                                                  PyTypeObject* T ) :
52         SCA_ILogicBrick(gameobj,T),
53         m_triggered(false)
54 {
55         m_links = 0;
56         m_suspended = false;
57         m_invert = false;
58         m_level = false;
59         m_reset = false;
60         m_pos_ticks = 0;
61         m_neg_ticks = 0;
62         m_pos_pulsemode = false;
63         m_neg_pulsemode = false;
64         m_pulse_frequency = 0;
65         
66         m_eventmgr = eventmgr;
67 }
68
69
70 SCA_ISensor::~SCA_ISensor()  
71 {
72         // intentionally empty
73 }
74
75 bool SCA_ISensor::IsPositiveTrigger() { 
76         bool result = false;
77         
78         if (m_eventval) {
79                 result = (m_eventval->GetNumber() != 0.0);
80         }
81         if (m_invert) {
82                 result = !result;
83         }
84         
85         return result;
86 }
87
88 void SCA_ISensor::SetPulseMode(bool posmode, 
89                                                            bool negmode,
90                                                            int freq) {
91         m_pos_pulsemode = posmode;
92         m_neg_pulsemode = negmode;
93         m_pulse_frequency = freq;
94 }
95
96 void SCA_ISensor::SetInvert(bool inv) {
97         m_invert = inv;
98 }
99
100 void SCA_ISensor::SetLevel(bool lvl) {
101         m_level = lvl;
102 }
103
104
105 float SCA_ISensor::GetNumber() {
106         return IsPositiveTrigger();
107 }
108
109 void SCA_ISensor::Suspend() {
110         m_suspended = true;
111 }
112
113 bool SCA_ISensor::IsSuspended() {
114         return m_suspended;
115 }
116
117 void SCA_ISensor::Resume() {
118         m_suspended = false;
119 }
120
121 void SCA_ISensor::Init() {
122         printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name.Ptr());
123 }
124
125 void SCA_ISensor::DecLink() {
126         m_links--;
127         if (m_links < 0) 
128         {
129                 printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
130                 m_links = 0;
131         }
132         if (!m_links)
133         {
134                 // sensor is detached from all controllers, initialize it so that it
135                 // is fresh as at startup when it is reattached again.
136                 Init();
137         }
138 }
139
140 /* python integration */
141
142 PyTypeObject SCA_ISensor::Type = {
143         PyObject_HEAD_INIT(&PyType_Type)
144         0,
145         "SCA_ISensor",
146         sizeof(SCA_ISensor),
147         0,
148         PyDestructor,
149         0,
150         __getattr,
151         __setattr,
152         0, //&MyPyCompare,
153         __repr,
154         0, //&cvalue_as_number,
155         0,
156         0,
157         0,
158         0
159 };
160
161 PyParentObject SCA_ISensor::Parents[] = {
162         &SCA_ISensor::Type,
163         &SCA_ILogicBrick::Type,
164         &CValue::Type,
165         NULL
166 };
167 PyMethodDef SCA_ISensor::Methods[] = {
168         {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, 
169          METH_VARARGS, IsPositive_doc},
170         {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, 
171          METH_VARARGS, GetUsePosPulseMode_doc},
172         {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, 
173          METH_VARARGS, SetUsePosPulseMode_doc},
174         {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency, 
175          METH_VARARGS, GetFrequency_doc},
176         {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency, 
177          METH_VARARGS, SetFrequency_doc},
178         {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode, 
179          METH_VARARGS, GetUseNegPulseMode_doc},
180         {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode, 
181          METH_VARARGS, SetUseNegPulseMode_doc},
182         {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert, 
183          METH_VARARGS, GetInvert_doc},
184         {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert, 
185          METH_VARARGS, SetInvert_doc},
186         {"getLevel", (PyCFunction) SCA_ISensor::sPyGetLevel, 
187          METH_VARARGS, GetLevel_doc},
188         {"setLevel", (PyCFunction) SCA_ISensor::sPySetLevel, 
189          METH_VARARGS, SetLevel_doc},
190         {NULL,NULL} //Sentinel
191 };
192
193
194 PyObject*
195 SCA_ISensor::_getattr(const STR_String& attr)
196 {
197   _getattr_up(SCA_ILogicBrick);
198 }
199
200
201 void SCA_ISensor::RegisterToManager()
202 {
203         m_eventmgr->RegisterSensor(this);
204 }
205
206 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr,      CValue* event)
207 {
208         
209         // calculate if a __triggering__ is wanted
210         // don't evaluate a sensor that is not connected to any controller
211         if (m_links && !m_suspended) {
212                 bool result = this->Evaluate(event);
213                 if (result) {
214                         logicmgr->AddActivatedSensor(this);     
215                 } else
216                 {
217                         /* First, the pulsing behaviour, if pulse mode is
218                          * active. It seems something goes wrong if pulse mode is
219                          * not set :( */
220                         if (m_pos_pulsemode) {
221                                 m_pos_ticks++;
222                                 if (m_pos_ticks > m_pulse_frequency) {
223                                         if ( this->IsPositiveTrigger() )
224                                         {
225                                                 logicmgr->AddActivatedSensor(this);
226                                         }
227                                         m_pos_ticks = 0;
228                                 } 
229                         }
230                         
231                         if (m_neg_pulsemode)
232                         {
233                                 m_neg_ticks++;
234                                 if (m_neg_ticks > m_pulse_frequency) {
235                                         if (!this->IsPositiveTrigger() )
236                                         {
237                                                 logicmgr->AddActivatedSensor(this);
238                                         }
239                                         m_neg_ticks = 0;
240                                 }
241                         }
242                 }
243         } 
244 }
245
246 /* Python functions: */
247 char SCA_ISensor::IsPositive_doc[] = 
248 "isPositive()\n"
249 "\tReturns whether the sensor is registered a positive event.\n";
250 PyObject* SCA_ISensor::PyIsPositive(PyObject* self, PyObject* args, PyObject* kwds)
251 {
252         int retval = IsPositiveTrigger();
253         return PyInt_FromLong(retval);
254 }
255
256 /**
257  * getUsePulseMode: getter for the pulse mode (KX_TRUE = on)
258  */
259 char SCA_ISensor::GetUsePosPulseMode_doc[] = 
260 "getUsePosPulseMode()\n"
261 "\tReturns whether positive pulse mode is active.\n";
262 PyObject* SCA_ISensor::PyGetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
263 {
264         return BoolToPyArg(m_pos_pulsemode);
265 }
266
267 /**
268  * setUsePulseMode: setter for the pulse mode (KX_TRUE = on)
269  */
270 char SCA_ISensor::SetUsePosPulseMode_doc[] = 
271 "setUsePosPulseMode(pulse?)\n"
272 "\t - pulse? : Pulse when a positive event occurs?\n"
273 "\t            (KX_TRUE, KX_FALSE)\n"
274 "\tSet whether to do pulsing when positive pulses occur.\n";
275 PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
276 {
277         int pyarg = 0;
278         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
279         m_pos_pulsemode = PyArgToBool(pyarg);
280         Py_Return;
281 }
282
283 /**
284  * getFrequency: getter for the pulse mode interval
285  */
286 char SCA_ISensor::GetFrequency_doc[] = 
287 "getFrequency()\n"
288 "\tReturns the frequency of the updates in pulse mode.\n" ;
289 PyObject* SCA_ISensor::PyGetFrequency(PyObject* self, PyObject* args, PyObject* kwds)
290 {
291         return PyInt_FromLong(m_pulse_frequency);
292 }
293
294 /**
295  * setFrequency: setter for the pulse mode (KX_TRUE = on)
296  */
297 char SCA_ISensor::SetFrequency_doc[] = 
298 "setFrequency(pulse_frequency)\n"
299 "\t- pulse_frequency: The frequency of the updates in pulse mode (integer)"
300 "\tSet the frequency of the updates in pulse mode.\n"
301 "\tIf the frequency is negative, it is set to 0.\n" ;
302 PyObject* SCA_ISensor::PySetFrequency(PyObject* self, PyObject* args, PyObject* kwds)
303 {
304         int pulse_frequencyArg = 0;
305
306         if(!PyArg_ParseTuple(args, "i", &pulse_frequencyArg)) {
307                 return NULL;
308         }
309         
310         /* We can do three things here: clip, ignore and raise an exception.  */
311         /* Exceptions don't work yet, ignoring is not desirable now...        */
312         if (pulse_frequencyArg < 0) {
313                 pulse_frequencyArg = 0;
314         };      
315         m_pulse_frequency = pulse_frequencyArg;
316
317         Py_Return;
318 }
319
320
321 char SCA_ISensor::GetInvert_doc[] = 
322 "getInvert()\n"
323 "\tReturns whether or not pulses from this sensor are inverted.\n" ;
324 PyObject* SCA_ISensor::PyGetInvert(PyObject* self, PyObject* args, PyObject* kwds)
325 {
326         return BoolToPyArg(m_invert);
327 }
328
329 char SCA_ISensor::SetInvert_doc[] = 
330 "setInvert(invert?)\n"
331 "\t- invert?: Invert the event-values? (KX_TRUE, KX_FALSE)\n"
332 "\tSet whether to invert pulses.\n";
333 PyObject* SCA_ISensor::PySetInvert(PyObject* self, PyObject* args, PyObject* kwds)
334 {
335         int pyarg = 0;
336         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
337         m_invert = PyArgToBool(pyarg);
338         Py_Return;
339 }
340
341 char SCA_ISensor::GetLevel_doc[] = 
342 "getLevel()\n"
343 "\tReturns whether this sensor is a level detector or a edge detector.\n"
344 "\tIt makes a difference only in case of logic state transition (state actuator).\n"
345 "\tA level detector will immediately generate a pulse if the condition for the\n"
346 "\tdetector is met when entering the state. A edge detector will wait for an off-on\n"
347 "\ttransition to occur.\n"
348 "\tOnly some sensors implement this feature: keyboard.\n";
349 PyObject* SCA_ISensor::PyGetLevel(PyObject* self, PyObject* args, PyObject* kwds)
350 {
351         return BoolToPyArg(m_level);
352 }
353
354 char SCA_ISensor::SetLevel_doc[] = 
355 "setLevel(level?)\n"
356 "\t- level?: Detect level instead of edge? (KX_TRUE, KX_FALSE)\n"
357 "\tSet whether to detect level or edge transition when entering a state.\n";
358 PyObject* SCA_ISensor::PySetLevel(PyObject* self, PyObject* args, PyObject* kwds)
359 {
360         int pyarg = 0;
361         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
362         m_level = PyArgToBool(pyarg);
363         Py_Return;
364 }
365
366 char SCA_ISensor::GetUseNegPulseMode_doc[] = 
367 "getUseNegPulseMode()\n"
368 "\tReturns whether negative pulse mode is active.\n";
369 PyObject* SCA_ISensor::PyGetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
370 {
371         return BoolToPyArg(m_neg_pulsemode);
372 }
373
374 char SCA_ISensor::SetUseNegPulseMode_doc[] = 
375 "setUseNegPulseMode(pulse?)\n"
376 "\t - pulse? : Pulse when a negative event occurs?\n"
377 "\t            (KX_TRUE, KX_FALSE)\n"
378 "\tSet whether to do pulsing when negative pulses occur.\n";
379 PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
380 {
381         int pyarg = 0;
382         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
383         m_neg_pulsemode = PyArgToBool(pyarg);
384         Py_Return;
385 }
386
387 /* eof */