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