Blender V2.61 - r43446

SCA_PropertySensor.cpp

Go to the documentation of this file.
00001 /*
00002  * Property sensor
00003  *
00004  *
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00022  * All rights reserved.
00023  *
00024  * The Original Code is: all of this file.
00025  *
00026  * Contributor(s): none yet.
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00036 #include <stddef.h>
00037 
00038 #include <iostream>
00039 #include "SCA_PropertySensor.h"
00040 #include "Operator2Expr.h"
00041 #include "ConstExpr.h"
00042 #include "InputParser.h"
00043 #include "StringValue.h"
00044 #include "SCA_EventManager.h"
00045 #include "SCA_LogicManager.h"
00046 #include "BoolValue.h"
00047 #include "FloatValue.h"
00048 #include <stdio.h>
00049 
00050 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
00051                                      SCA_IObject* gameobj,
00052                                      const STR_String& propname,
00053                                      const STR_String& propval,
00054                                      const STR_String& propmaxval,
00055                                      KX_PROPSENSOR_TYPE checktype)
00056     : SCA_ISensor(gameobj,eventmgr),
00057       m_checktype(checktype),
00058       m_checkpropval(propval),
00059       m_checkpropmaxval(propmaxval),
00060       m_checkpropname(propname),
00061       m_range_expr(NULL)
00062 {
00063     //CParser pars;
00064     //pars.SetContext(this->AddRef());
00065     //CValue* resultval = m_rightexpr->Calculate();
00066 
00067     CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00068     if (!orgprop->IsError())
00069     {
00070         m_previoustext = orgprop->GetText();
00071     }
00072     orgprop->Release();
00073 
00074     if (m_checktype==KX_PROPSENSOR_INTERVAL)
00075     {
00076         PrecalculateRangeExpression();
00077     }
00078     Init();
00079 }
00080 
00081 void SCA_PropertySensor::Init()
00082 {
00083     m_recentresult = false;
00084     m_lastresult = m_invert?true:false;
00085     m_reset = true;
00086 }
00087 
00088 void SCA_PropertySensor::PrecalculateRangeExpression()
00089 {
00090         CParser pars;
00091         //The context is needed to retrieve the property at runtime but it creates
00092         //loop of references
00093         pars.SetContext(this->AddRef());
00094         STR_String checkstr = "(" + m_checkpropval + " <= " 
00095                             + m_checkpropname + ") && ( " 
00096                             + m_checkpropname + " <= " 
00097                             + m_checkpropmaxval + ")";
00098 
00099         m_range_expr = pars.ProcessText(checkstr);
00100 }
00101 
00102 // Forced deletion of precalculated range expression to break reference loop
00103 // Use this function when you know that you won't use the sensor anymore
00104 void SCA_PropertySensor::Delete()
00105 {
00106     if (m_range_expr)
00107     {
00108         m_range_expr->Release();
00109         m_range_expr = NULL;
00110     }
00111     Release();
00112 }
00113 
00114 CValue* SCA_PropertySensor::GetReplica()
00115 {
00116     SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
00117     // m_range_expr must be recalculated on replica!
00118     replica->ProcessReplica();
00119     replica->Init();
00120 
00121     replica->m_range_expr = NULL;
00122     if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
00123     {
00124         replica->PrecalculateRangeExpression();
00125     }
00126     
00127     
00128     return replica;
00129 }
00130 
00131 
00132 
00133 bool SCA_PropertySensor::IsPositiveTrigger()
00134 {
00135     bool result = m_recentresult;//CheckPropertyCondition();
00136     if (m_invert)
00137         result = !result;
00138 
00139     return result;
00140 }
00141 
00142 
00143 
00144 SCA_PropertySensor::~SCA_PropertySensor()
00145 {
00146     //if (m_rightexpr)
00147     //  m_rightexpr->Release();
00148 
00149     if (m_range_expr)
00150     {
00151         m_range_expr->Release();
00152         m_range_expr=NULL;
00153     }
00154 
00155 }
00156 
00157 
00158 
00159 bool SCA_PropertySensor::Evaluate()
00160 {
00161     bool result = CheckPropertyCondition();
00162     bool reset = m_reset && m_level;
00163     
00164     m_reset = false;
00165     if (m_lastresult!=result)
00166     {
00167         m_lastresult = result;
00168         return true;
00169     }
00170     return (reset) ? true : false;
00171 }
00172 
00173 
00174 bool    SCA_PropertySensor::CheckPropertyCondition()
00175 {
00176 
00177     m_recentresult=false;
00178     bool result=false;
00179     bool reverse = false;
00180     switch (m_checktype)
00181     {
00182     case KX_PROPSENSOR_NOTEQUAL:
00183         reverse = true;
00184     case KX_PROPSENSOR_EQUAL:
00185         {
00186             CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00187             if (!orgprop->IsError())
00188             {
00189                 const STR_String& testprop = orgprop->GetText();
00190                 // Force strings to upper case, to avoid confusion in
00191                 // bool tests. It's stupid the prop's identity is lost
00192                 // on the way here...
00193                 if ((&testprop == &CBoolValue::sTrueString) || (&testprop == &CBoolValue::sFalseString)) {
00194                     m_checkpropval.Upper();
00195                 }
00196                 result = (testprop == m_checkpropval);
00197                 
00198                 /* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000"
00199                  * this could be made into a generic Value class function for comparing values with a string.
00200                  */
00201                 if(result==false && dynamic_cast<CFloatValue *>(orgprop) != NULL) {
00202                     float f;
00203                     
00204                     if(EOF == sscanf(m_checkpropval.ReadPtr(), "%f", &f))
00205                     {
00206                         //error
00207                     } 
00208                     else {
00209                         result = (f == ((CFloatValue *)orgprop)->GetFloat());
00210                     }
00211                 }
00212                 /* end patch */
00213             }
00214             orgprop->Release();
00215 
00216             if (reverse)
00217                 result = !result;
00218             break;
00219 
00220         }
00221 
00222     case KX_PROPSENSOR_EXPRESSION:
00223         {
00224             /*
00225             if (m_rightexpr)
00226             {
00227                 CValue* resultval = m_rightexpr->Calculate();
00228                 if (resultval->IsError())
00229                 {
00230                     int i=0;
00231                     STR_String errortest = resultval->GetText();
00232                     printf(errortest);
00233 
00234                 } else
00235                 {
00236                     result = resultval->GetNumber() != 0;
00237                 }
00238             }
00239             */
00240             break;
00241         }
00242     case KX_PROPSENSOR_INTERVAL:
00243         {
00244             //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00245             //if (orgprop)
00246             //{
00247                 if (m_range_expr)
00248                 {
00249                     CValue* vallie = m_range_expr->Calculate();
00250                     if (vallie)
00251                     {
00252                         const STR_String& errtext = vallie->GetText();
00253                         if (&errtext == &CBoolValue::sTrueString)
00254                         {
00255                             result = true;
00256                         } else
00257                         {
00258                             if (vallie->IsError())
00259                             {
00260                                 //printf (errtext.ReadPtr());
00261                             } 
00262                         }
00263                         
00264                         vallie->Release();
00265                     }
00266                 }
00267 
00268                 
00269             //}
00270             
00271         //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
00272 
00273         break;
00274         }
00275     case KX_PROPSENSOR_CHANGED:
00276         {
00277             CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
00278                 
00279             if (!orgprop->IsError())
00280             {
00281                 if (m_previoustext != orgprop->GetText())
00282                 {
00283                     m_previoustext = orgprop->GetText();
00284                     result = true;
00285                 }
00286             }
00287             orgprop->Release();
00288 
00289             //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
00290             break;
00291         }
00292     default:
00293         ; /* error */
00294     }
00295 
00296     //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
00297     //see Game Engine bugtracker [ #3809 ]
00298     if (m_checktype != KX_PROPSENSOR_CHANGED)
00299     {
00300         m_recentresult=result;
00301     } else
00302     {
00303         m_recentresult=result;//true;
00304     }
00305     return result;
00306 }
00307 
00308 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
00309 {
00310     return  GetParent()->FindIdentifier(identifiername);
00311 }
00312 
00313 #ifdef WITH_PYTHON
00314 
00315 /* ------------------------------------------------------------------------- */
00316 /* Python functions                                                          */
00317 /* ------------------------------------------------------------------------- */
00318 
00319 int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*)
00320 {
00321     /*  If someone actually do type checking please make sure the 'max' and 'min'
00322         are checked as well (currently they are calling the PrecalculateRangeExpression
00323         function directly   */
00324 
00325     /*  There is no type checking at this moment, unfortunately...           */
00326     return 0;
00327 }
00328 
00329 int SCA_PropertySensor::validValueForIntervalProperty(void *self, const PyAttributeDef*)
00330 {
00331     SCA_PropertySensor* sensor = reinterpret_cast<SCA_PropertySensor*>(self);
00332 
00333     if (sensor->m_checktype==KX_PROPSENSOR_INTERVAL)
00334     {
00335         sensor->PrecalculateRangeExpression();
00336     }
00337     return 0;
00338 }
00339 
00340 int SCA_PropertySensor::modeChange(void *self, const PyAttributeDef* attrdef)
00341 {
00342     SCA_PropertySensor* sensor = reinterpret_cast<SCA_PropertySensor*>(self);
00343 
00344     if (sensor->m_checktype==KX_PROPSENSOR_INTERVAL)
00345     {
00346         sensor->PrecalculateRangeExpression();
00347     }
00348     return 0;
00349 }
00350 
00351 /* Integration hooks ------------------------------------------------------- */
00352 PyTypeObject SCA_PropertySensor::Type = {
00353     PyVarObject_HEAD_INIT(NULL, 0)
00354     "SCA_PropertySensor",
00355     sizeof(PyObjectPlus_Proxy),
00356     0,
00357     py_base_dealloc,
00358     0,
00359     0,
00360     0,
00361     0,
00362     py_base_repr,
00363     0,0,0,0,0,0,0,0,0,
00364     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00365     0,0,0,0,0,0,0,
00366     Methods,
00367     0,
00368     0,
00369     &SCA_ISensor::Type,
00370     0,0,0,0,0,0,
00371     py_base_new
00372 };
00373 
00374 PyMethodDef SCA_PropertySensor::Methods[] = {
00375     {NULL,NULL} //Sentinel
00376 };
00377 
00378 PyAttributeDef SCA_PropertySensor::Attributes[] = {
00379     KX_PYATTRIBUTE_INT_RW_CHECK("mode",KX_PROPSENSOR_NODEF,KX_PROPSENSOR_MAX-1,false,SCA_PropertySensor,m_checktype,modeChange),
00380     KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,MAX_PROP_NAME,false,SCA_PropertySensor,m_checkpropname,CheckProperty),
00381     KX_PYATTRIBUTE_STRING_RW_CHECK("value",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty),
00382     KX_PYATTRIBUTE_STRING_RW_CHECK("min",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForIntervalProperty),
00383     KX_PYATTRIBUTE_STRING_RW_CHECK("max",0,100,false,SCA_PropertySensor,m_checkpropmaxval,validValueForIntervalProperty),
00384     { NULL }    //Sentinel
00385 };
00386 
00387 #endif // WITH_PYTHON
00388 
00389 /* eof */