BGE patch 18368: Modulus (ie %) expression controller in BGE. Implement a cache for the expression for better performance.

This commit is contained in:
Benoit Bolsee 2009-03-11 22:11:52 +00:00
parent 0ac3e70160
commit a37cec2802
12 changed files with 68 additions and 15 deletions

@ -127,6 +127,9 @@ ret: a new object containing the result of applying operator op to val and
{
switch (op)
{
case VALUE_MOD_OPERATOR:
ret = new CFloatValue(fmod(((CIntValue *) val)->GetInt(), m_float));
break;
case VALUE_ADD_OPERATOR:
ret = new CFloatValue(((CIntValue *) val)->GetInt() + m_float);
break;
@ -171,6 +174,9 @@ ret: a new object containing the result of applying operator op to val and
{
switch (op)
{
case VALUE_MOD_OPERATOR:
ret = new CFloatValue(fmod(((CFloatValue *) val)->GetFloat(), m_float));
break;
case VALUE_ADD_OPERATOR:
ret = new CFloatValue(((CFloatValue *) val)->GetFloat() + m_float);
break;

@ -175,6 +175,9 @@ void CParser::NextSym()
case ',':
sym = commasym; NextCh();
break;
case '%' :
sym = opsym; opkind = OPmodulus; NextCh();
break;
case '+' :
sym = opsym; opkind = OPplus; NextCh();
break;
@ -370,6 +373,7 @@ int CParser::Priority(int optorkind) {
case OPunequal: return 3;
case OPplus:
case OPminus: return 4;
case OPmodulus:
case OPtimes:
case OPdivide: return 5;
}
@ -390,6 +394,7 @@ CExpression *CParser::Ex(int i) {
NextSym();
e2 = Ex(i + 1);
switch(opkind2) {
case OPmodulus: e1 = new COperator2Expr(VALUE_MOD_OPERATOR,e1, e2); break;
case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break;
case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break;
case OPtimes: e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break;

@ -49,6 +49,7 @@ private:
}; // all kinds of symbols
enum optype {
OPmodulus,
OPplus,
OPminus,
OPtimes,

@ -125,6 +125,9 @@ this object
case VALUE_INT_TYPE:
{
switch (op) {
case VALUE_MOD_OPERATOR:
ret = new CIntValue (((CIntValue *) val)->GetInt() % m_int);
break;
case VALUE_ADD_OPERATOR:
ret = new CIntValue (((CIntValue *) val)->GetInt() + m_int);
break;
@ -181,6 +184,9 @@ this object
case VALUE_FLOAT_TYPE:
{
switch (op) {
case VALUE_MOD_OPERATOR:
ret = new CFloatValue(fmod(((CFloatValue *) val)->GetFloat(), m_int));
break;
case VALUE_ADD_OPERATOR:
ret = new CFloatValue (((CFloatValue *) val)->GetFloat() + m_int);
break;

@ -52,6 +52,10 @@ PyObject* cvalue_div(PyObject*v, PyObject*w)
{
return ((CValue*)v)->Calc(VALUE_DIV_OPERATOR,(CValue*)w);
}
PyObject* cvalue_mod(PyObject*v, PyObject*w)
{
return ((CValue*)v)->Calc(VALUE_MOD_OPERATOR,(CValue*)w);
}
PyObject* cvalue_neg(PyObject*v)
{
return ((CValue*)v)->Calc(VALUE_NEG_OPERATOR,(CValue*)v);
@ -112,7 +116,7 @@ static PyNumberMethods cvalue_as_number = {
(binaryfunc)cvalue_sub, /*nb_subtract*/
(binaryfunc)cvalue_mul, /*nb_multiply*/
(binaryfunc)cvalue_div, /*nb_divide*/
0,//(binaryfunc)cvalue_remainder, /*nb_remainder*/
(binaryfunc)cvalue_mod, /*nb_remainder*/
0,//(binaryfunc)cvalue_divmod, /*nb_divmod*/
0,//0,//0,//0,//(ternaryfunc)cvalue_pow, /*nb_power*/
(unaryfunc)cvalue_neg, /*nb_negative*/
@ -257,6 +261,9 @@ STR_String CValue::op2str (VALUE_OPERATOR op)
STR_String opmsg;
switch (op) {
case VALUE_MOD_OPERATOR:
opmsg = " % ";
break;
case VALUE_ADD_OPERATOR:
opmsg = " + ";
break;

@ -75,6 +75,7 @@
enum VALUE_OPERATOR {
VALUE_MOD_OPERATOR, // %
VALUE_ADD_OPERATOR, // +
VALUE_SUB_OPERATOR, // -
VALUE_MUL_OPERATOR, // *

@ -49,7 +49,8 @@ SCA_ExpressionController::SCA_ExpressionController(SCA_IObject* gameobj,
const STR_String& exprtext,
PyTypeObject* T)
:SCA_IController(gameobj,T),
m_exprText(exprtext)
m_exprText(exprtext),
m_exprCache(NULL)
{
}
@ -57,6 +58,8 @@ SCA_ExpressionController::SCA_ExpressionController(SCA_IObject* gameobj,
SCA_ExpressionController::~SCA_ExpressionController()
{
if (m_exprCache)
m_exprCache->Release();
}
@ -65,6 +68,7 @@ CValue* SCA_ExpressionController::GetReplica()
{
SCA_ExpressionController* replica = new SCA_ExpressionController(*this);
replica->m_exprText = m_exprText;
replica->m_exprCache = NULL;
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
@ -72,18 +76,32 @@ CValue* SCA_ExpressionController::GetReplica()
}
// Forced deletion of precalculated expression to break reference loop
// Use this function when you know that you won't use the sensor anymore
void SCA_ExpressionController::Delete()
{
if (m_exprCache)
{
m_exprCache->Release();
m_exprCache = NULL;
}
Release();
}
void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr)
{
bool expressionresult = false;
CParser parser;
parser.SetContext(this->AddRef());
CExpression* expr = parser.ProcessText(m_exprText);
if (expr)
if (!m_exprCache)
{
CValue* value = expr->Calculate();
CParser parser;
parser.SetContext(this->AddRef());
m_exprCache = parser.ProcessText(m_exprText);
}
if (m_exprCache)
{
CValue* value = m_exprCache->Calculate();
if (value)
{
if (value->IsError())
@ -97,7 +115,8 @@ void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr)
value->Release();
}
expr->Release();
//m_exprCache->Release();
//m_exprCache = NULL;
}
/*

@ -38,6 +38,7 @@ class SCA_ExpressionController : public SCA_IController
{
// Py_Header;
STR_String m_exprText;
CExpression* m_exprCache;
public:
SCA_ExpressionController(SCA_IObject* gameobj,
@ -48,6 +49,11 @@ public:
virtual CValue* GetReplica();
virtual void Trigger(SCA_LogicManager* logicmgr);
virtual CValue* FindIdentifier(const STR_String& identifiername);
/**
* used to release the expression cache
* so that self references are removed before the controller itself is released
*/
virtual void Delete();
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */

@ -62,6 +62,7 @@ public:
SCA_IObject* GetParent();
virtual void ReParent(SCA_IObject* parent);
virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual void Delete() { Release(); }
// act as a BoolValue (with value IsPositiveTrigger)
virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);

@ -59,7 +59,9 @@ SCA_IObject::~SCA_IObject()
SCA_ControllerList::iterator itc;
for (itc = m_controllers.begin(); !(itc == m_controllers.end()); ++itc)
{
((CValue*)(*itc))->Release();
//Use Delete for controller to ensure proper cleaning (expression controller)
(*itc)->Delete();
//((CValue*)(*itc))->Release();
}
SCA_ActuatorList::iterator ita;
for (ita = m_registeredActuators.begin(); !(ita==m_registeredActuators.end()); ++ita)

@ -105,11 +105,6 @@ public:
bool negmode,
int freq);
/** Release sensor
* For property sensor, it is used to release the pre-calculated expression
* so that self references are removed before the sensor itself is released
*/
virtual void Delete() { Release(); }
/** Set inversion of pulses on or off. */
void SetInvert(bool inv);
/** set the level detection on or off */

@ -70,6 +70,10 @@ public:
KX_PROPSENSOR_TYPE checktype,
PyTypeObject* T=&Type );
/**
* For property sensor, it is used to release the pre-calculated expression
* so that self references are removed before the sensor itself is released
*/
virtual void Delete();
virtual ~SCA_PropertySensor();
virtual CValue* GetReplica();