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