Blender V2.61 - r43446
|
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 */