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