Blender  V2.59
SCA_ISensor.cpp
Go to the documentation of this file.
00001 /*
00002  * Abstract class for sensor logic bricks
00003  *
00004  * $Id: SCA_ISensor.cpp 35169 2011-02-25 13:32:11Z jesterking $
00005  *
00006  * ***** BEGIN GPL LICENSE BLOCK *****
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software Foundation,
00020  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021  *
00022  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00023  * All rights reserved.
00024  *
00025  * The Original Code is: all of this file.
00026  *
00027  * Contributor(s): none yet.
00028  *
00029  * ***** END GPL LICENSE BLOCK *****
00030  */
00031 
00037 #include <stddef.h>
00038 
00039 #include "SCA_ISensor.h"
00040 #include "SCA_EventManager.h"
00041 #include "SCA_LogicManager.h"
00042 // needed for IsTriggered()
00043 #include "SCA_PythonController.h"
00044 
00045 #include <stdio.h>
00046 
00047 /* Native functions */
00048 void    SCA_ISensor::ReParent(SCA_IObject* parent)
00049 {
00050         SCA_ILogicBrick::ReParent(parent);
00051         // will be done when the sensor is activated
00052         //m_eventmgr->RegisterSensor(this);
00053         //this->SetActive(false);
00054 }
00055 
00056 
00057 SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
00058                                                  class SCA_EventManager* eventmgr) :
00059         SCA_ILogicBrick(gameobj)
00060 {
00061         m_links = 0;
00062         m_suspended = false;
00063         m_invert = false;
00064         m_level = false;
00065         m_tap = false;
00066         m_reset = false;
00067         m_pos_ticks = 0;
00068         m_neg_ticks = 0;
00069         m_pos_pulsemode = false;
00070         m_neg_pulsemode = false;
00071         m_pulse_frequency = 0;
00072         m_state = false;
00073         m_prev_state = false;
00074         
00075         m_eventmgr = eventmgr;
00076 }
00077 
00078 
00079 SCA_ISensor::~SCA_ISensor()  
00080 {
00081         // intentionally empty
00082 }
00083 
00084 void SCA_ISensor::ProcessReplica()
00085 {
00086         SCA_ILogicBrick::ProcessReplica();
00087         m_linkedcontrollers.clear();
00088 }
00089 
00090 bool SCA_ISensor::IsPositiveTrigger() { 
00091         bool result = false;
00092         
00093         if (m_eventval) {
00094                 result = (m_eventval->GetNumber() != 0.0);
00095         }
00096         if (m_invert) {
00097                 result = !result;
00098         }
00099         
00100         return result;
00101 }
00102 
00103 void SCA_ISensor::SetPulseMode(bool posmode, 
00104                                                            bool negmode,
00105                                                            int freq) {
00106         m_pos_pulsemode = posmode;
00107         m_neg_pulsemode = negmode;
00108         m_pulse_frequency = freq;
00109 }
00110 
00111 void SCA_ISensor::SetInvert(bool inv) {
00112         m_invert = inv;
00113 }
00114 
00115 void SCA_ISensor::SetLevel(bool lvl) {
00116         m_level = lvl;
00117 }
00118 
00119 void SCA_ISensor::SetTap(bool tap) {
00120         m_tap = tap;
00121 }
00122 
00123 
00124 double SCA_ISensor::GetNumber() {
00125         return GetState();
00126 }
00127 
00128 void SCA_ISensor::Suspend() {
00129         m_suspended = true;
00130 }
00131 
00132 bool SCA_ISensor::IsSuspended() {
00133         return m_suspended;
00134 }
00135 
00136 void SCA_ISensor::Resume() {
00137         m_suspended = false;
00138 }
00139 
00140 void SCA_ISensor::Init() {
00141         printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name.Ptr());
00142 }
00143 
00144 void SCA_ISensor::DecLink() {
00145         m_links--;
00146         if (m_links < 0) 
00147         {
00148                 printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
00149                 m_links = 0;
00150         }
00151         if (!m_links)
00152         {
00153                 // sensor is detached from all controllers, remove it from manager
00154                 UnregisterToManager();
00155         }
00156 }
00157 
00158 void SCA_ISensor::RegisterToManager()
00159 {
00160         // sensor is just activated, initialize it
00161         Init();
00162         m_state = false;
00163         m_eventmgr->RegisterSensor(this);
00164 }
00165 
00166 void SCA_ISensor::Replace_EventManager(class SCA_LogicManager* logicmgr)
00167 {
00168         if(m_links) { /* true if we're used currently */
00169 
00170                 m_eventmgr->RemoveSensor(this);
00171                 m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType());
00172                 m_eventmgr->RegisterSensor(this);
00173         }
00174         else {
00175                 m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType());
00176         }
00177 }
00178 
00179 void SCA_ISensor::LinkToController(SCA_IController* controller)
00180 {
00181         m_linkedcontrollers.push_back(controller);
00182 }
00183 
00184 void SCA_ISensor::UnlinkController(SCA_IController* controller)
00185 {
00186         std::vector<class SCA_IController*>::iterator contit;
00187         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
00188         {
00189                 if ((*contit) == controller)
00190                 {
00191                         *contit = m_linkedcontrollers.back();
00192                         m_linkedcontrollers.pop_back();
00193                         return;
00194                 }
00195         }
00196         printf("Missing link from sensor %s:%s to controller %s:%s\n", 
00197                 m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), 
00198                 controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr());
00199 }
00200 
00201 void SCA_ISensor::UnlinkAllControllers()
00202 {
00203         std::vector<class SCA_IController*>::iterator contit;
00204         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
00205         {
00206                 (*contit)->UnlinkSensor(this);
00207         }
00208         m_linkedcontrollers.clear();
00209 }
00210 
00211 void SCA_ISensor::UnregisterToManager()
00212 {
00213         m_eventmgr->RemoveSensor(this);
00214         m_links = 0;
00215 }
00216 
00217 void SCA_ISensor::ActivateControllers(class SCA_LogicManager* logicmgr)
00218 {
00219     for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
00220                 c!=m_linkedcontrollers.end();++c)
00221         {
00222                 SCA_IController* contr = *c;
00223                 if (contr->IsActive())
00224                         logicmgr->AddTriggeredController(contr, this);
00225         }
00226 }
00227 
00228 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr)
00229 {
00230         
00231         // calculate if a __triggering__ is wanted
00232         // don't evaluate a sensor that is not connected to any controller
00233         if (m_links && !m_suspended) {
00234                 bool result = this->Evaluate();
00235                 // store the state for the rest of the logic system
00236                 m_prev_state = m_state;
00237                 m_state = this->IsPositiveTrigger();
00238                 if (result) {
00239                         // the sensor triggered this frame
00240                         if (m_state || !m_tap) {
00241                                 ActivateControllers(logicmgr);  
00242                                 // reset these counters so that pulse are synchronized with transition
00243                                 m_pos_ticks = 0;
00244                                 m_neg_ticks = 0;
00245                         } else
00246                         {
00247                                 result = false;
00248                         }
00249                 } else
00250                 {
00251                         /* First, the pulsing behaviour, if pulse mode is
00252                          * active. It seems something goes wrong if pulse mode is
00253                          * not set :( */
00254                         if (m_pos_pulsemode) {
00255                                 m_pos_ticks++;
00256                                 if (m_pos_ticks > m_pulse_frequency) {
00257                                         if ( m_state )
00258                                         {
00259                                                 ActivateControllers(logicmgr);
00260                                                 result = true;
00261                                         }
00262                                         m_pos_ticks = 0;
00263                                 } 
00264                         }
00265                         // negative pulse doesn't make sense in tap mode, skip
00266                         if (m_neg_pulsemode && !m_tap)
00267                         {
00268                                 m_neg_ticks++;
00269                                 if (m_neg_ticks > m_pulse_frequency) {
00270                                         if (!m_state )
00271                                         {
00272                                                 ActivateControllers(logicmgr);
00273                                                 result = true;
00274                                         }
00275                                         m_neg_ticks = 0;
00276                                 }
00277                         }
00278                 }
00279                 if (m_tap)
00280                 {
00281                         // in tap mode: we send always a negative pulse immediately after a positive pulse
00282                         if (!result)
00283                         {
00284                                 // the sensor did not trigger on this frame
00285                                 if (m_prev_state)
00286                                 {
00287                                         // but it triggered on previous frame => send a negative pulse
00288                                         ActivateControllers(logicmgr);
00289                                         result = true;
00290                                 }
00291                                 // in any case, absence of trigger means sensor off
00292                                 m_state = false;
00293                         }
00294                 }
00295                 if (!result && m_level)
00296                 {
00297                         // This level sensor is connected to at least one controller that was just made 
00298                         // active but it did not generate an event yet, do it now to those controllers only 
00299                         for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
00300                                 c!=m_linkedcontrollers.end();++c)
00301                         {
00302                                 SCA_IController* contr = *c;
00303                                 if (contr->IsJustActivated())
00304                                         logicmgr->AddTriggeredController(contr, this);
00305                         }
00306                 }
00307         } 
00308 }
00309 
00310 #ifdef WITH_PYTHON
00311 
00312 /* ----------------------------------------------- */
00313 /* Python Functions                                                        */
00314 /* ----------------------------------------------- */
00315 
00316 KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset,
00317 "reset()\n"
00318 "\tReset sensor internal state, effect depends on the type of sensor and settings.\n"
00319 "\tThe sensor is put in its initial state as if it was just activated.\n")
00320 {
00321         Init();
00322         m_prev_state = false;
00323         Py_RETURN_NONE;
00324 }
00325 
00326 /* ----------------------------------------------- */
00327 /* Python Integration Hooks                                            */
00328 /* ----------------------------------------------- */
00329 
00330 PyTypeObject SCA_ISensor::Type = {
00331         PyVarObject_HEAD_INIT(NULL, 0)
00332         "SCA_ISensor",
00333         sizeof(PyObjectPlus_Proxy),
00334         0,
00335         py_base_dealloc,
00336         0,
00337         0,
00338         0,
00339         0,
00340         py_base_repr,
00341         0,0,0,0,0,0,0,0,0,
00342         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00343         0,0,0,0,0,0,0,
00344         Methods,
00345         0,
00346         0,
00347         &SCA_ILogicBrick::Type,
00348         0,0,0,0,0,0,
00349         py_base_new
00350 };
00351 
00352 PyMethodDef SCA_ISensor::Methods[] = {
00353         KX_PYMETHODTABLE_NOARGS(SCA_ISensor, reset),
00354         {NULL,NULL} //Sentinel
00355 };
00356 
00357 PyAttributeDef SCA_ISensor::Attributes[] = {
00358         KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode),
00359         KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode),
00360         KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency),
00361         KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert),
00362         KX_PYATTRIBUTE_BOOL_RW_CHECK("level",SCA_ISensor,m_level,pyattr_check_level),
00363         KX_PYATTRIBUTE_BOOL_RW_CHECK("tap",SCA_ISensor,m_tap,pyattr_check_tap),
00364         KX_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered),
00365         KX_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive),
00366         KX_PYATTRIBUTE_RO_FUNCTION("status", SCA_ISensor, pyattr_get_status),
00367         KX_PYATTRIBUTE_RO_FUNCTION("pos_ticks", SCA_ISensor, pyattr_get_posTicks),
00368         KX_PYATTRIBUTE_RO_FUNCTION("neg_ticks", SCA_ISensor, pyattr_get_negTicks),
00369         { NULL }        //Sentinel
00370 };
00371 
00372 
00373 PyObject* SCA_ISensor::pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00374 {
00375         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
00376         int retval = 0;
00377         if (SCA_PythonController::m_sCurrentController)
00378                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(self);
00379         return PyLong_FromSsize_t(retval);
00380 }
00381 
00382 PyObject* SCA_ISensor::pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00383 {
00384         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
00385         return PyLong_FromSsize_t(self->GetState());
00386 }
00387 
00388 PyObject* SCA_ISensor::pyattr_get_status(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00389 {
00390         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
00391         int status = 0;
00392         if (self->GetState()) 
00393         {
00394                 if (self->GetState() == self->GetPrevState()) 
00395                 {
00396                         status = 2;
00397                 }
00398                 else 
00399                 {
00400                         status = 1;
00401                 }
00402         }
00403         else if (self->GetState() != self->GetPrevState()) 
00404         {
00405                 status = 3;
00406         }
00407         return PyLong_FromSsize_t(status);
00408 }
00409 
00410 PyObject* SCA_ISensor::pyattr_get_posTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00411 {
00412         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
00413         return PyLong_FromLong(self->GetPosTicks());
00414 }
00415 
00416 PyObject* SCA_ISensor::pyattr_get_negTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00417 {
00418         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
00419         return PyLong_FromLong(self->GetNegTicks());
00420 }
00421 
00422 int SCA_ISensor::pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00423 {
00424         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
00425         if (self->m_level)
00426                 self->m_tap = false;
00427         return 0;
00428 }
00429 
00430 int SCA_ISensor::pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00431 {
00432         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
00433         if (self->m_tap)
00434                 self->m_level = false;
00435         return 0;
00436 }
00437 #endif // WITH_PYTHON
00438 
00439 /* eof */