1 /** \file gameengine/Expressions/Value.cpp
4 // Value.cpp: implementation of the CValue class.
5 // developed at Eindhoven University of Technology, 1997
7 //////////////////////////////////////////////////////////////////////
9 * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
11 * Permission to use, copy, modify, distribute and sell this software
12 * and its documentation for any purpose is hereby granted without fee,
13 * provided that the above copyright notice appear in all copies and
14 * that both that copyright notice and this permission notice appear
15 * in supporting documentation. Erwin Coumans makes no
16 * representations about the suitability of this software for any
17 * purpose. It is provided "as is" without express or implied warranty.
21 #include "FloatValue.h"
23 #include "VectorValue.h"
24 #include "VoidValue.h"
25 #include "StringValue.h"
26 #include "ErrorValue.h"
27 #include "ListValue.h"
29 //////////////////////////////////////////////////////////////////////
30 // Construction/Destruction
31 //////////////////////////////////////////////////////////////////////
33 double CValue::m_sZeroVec[3] = {0.0,0.0,0.0};
37 PyTypeObject CValue::Type = {
38 PyVarObject_HEAD_INIT(NULL, 0)
40 sizeof(PyObjectPlus_Proxy),
53 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
63 PyMethodDef CValue::Methods[] = {
64 {NULL,NULL} //Sentinel
69 /*#define CVALUE_DEBUG*/
76 SmartCValueRef(CValue *ref)
79 m_count = gRefCount++;
85 std::vector<SmartCValueRef> gRefList;
95 m_pNamedPropertyArray(NULL),
99 effect: constucts a CValue
102 //debug(gRefCountValue++) // debugging
106 gRefList.push_back(SmartCValueRef(this));
116 effect: deletes the object
121 assertd (m_refcount==0);
123 std::vector<SmartCValueRef>::iterator it;
124 for (it=gRefList.begin(); it!=gRefList.end(); it++)
126 if (it->m_ref == this)
128 *it = gRefList.back();
139 #define VALUE_SUB(val1, val2) (val1)->Calc(VALUE_SUB_OPERATOR, val2)
140 #define VALUE_MUL(val1, val2) (val1)->Calc(VALUE_MUL_OPERATOR, val2)
141 #define VALUE_DIV(val1, val2) (val1)->Calc(VALUE_DIV_OPERATOR, val2)
142 #define VALUE_NEG(val1) (val1)->Calc(VALUE_NEG_OPERATOR, val1)
143 #define VALUE_POS(val1) (val1)->Calc(VALUE_POS_OPERATOR, val1)
146 STR_String CValue::op2str (VALUE_OPERATOR op)
149 //ret: the stringrepresentation of operator op
153 case VALUE_MOD_OPERATOR:
156 case VALUE_ADD_OPERATOR:
159 case VALUE_SUB_OPERATOR:
162 case VALUE_MUL_OPERATOR:
165 case VALUE_DIV_OPERATOR:
168 case VALUE_NEG_OPERATOR:
171 case VALUE_POS_OPERATOR:
174 case VALUE_AND_OPERATOR:
177 case VALUE_OR_OPERATOR:
180 case VALUE_EQL_OPERATOR:
183 case VALUE_NEQ_OPERATOR:
186 case VALUE_NOT_OPERATOR:
190 opmsg="Error in Errorhandling routine.";
191 // AfxMessageBox("Invalid operator");
201 //---------------------------------------------------------------------------------------------------------------------
202 // Property Management
203 //---------------------------------------------------------------------------------------------------------------------
208 // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed
210 void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
212 if (ioProperty==NULL)
213 { // Check if somebody is setting an empty property
214 trace("Warning:trying to set empty property!");
218 if (m_pNamedPropertyArray)
219 { // Try to replace property (if so -> exit as soon as we replaced it)
220 CValue* oldval = (*m_pNamedPropertyArray)[name];
224 else { // Make sure we have a property array
225 m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
228 // Add property at end of array
229 (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
232 void CValue::SetProperty(const char* name,CValue* ioProperty)
234 if (ioProperty==NULL)
235 { // Check if somebody is setting an empty property
236 trace("Warning:trying to set empty property!");
240 if (m_pNamedPropertyArray)
241 { // Try to replace property (if so -> exit as soon as we replaced it)
242 CValue* oldval = (*m_pNamedPropertyArray)[name];
246 else { // Make sure we have a property array
247 m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
250 // Add property at end of array
251 (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
255 // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
257 CValue* CValue::GetProperty(const STR_String & inName)
259 if (m_pNamedPropertyArray) {
260 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
261 if (it != m_pNamedPropertyArray->end())
267 CValue* CValue::GetProperty(const char *inName)
269 if (m_pNamedPropertyArray) {
270 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
271 if (it != m_pNamedPropertyArray->end())
278 // Get text description of property with name <inName>, returns an empty string if there is no property named <inName>
280 const STR_String& CValue::GetPropertyText(const STR_String & inName)
282 const static STR_String sEmpty("");
284 CValue *property = GetProperty(inName);
286 return property->GetText();
291 float CValue::GetPropertyNumber(const STR_String& inName,float defnumber)
293 CValue *property = GetProperty(inName);
295 return property->GetNumber();
303 // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed
305 bool CValue::RemoveProperty(const char *inName)
307 // Check if there are properties at all which can be removed
308 if (m_pNamedPropertyArray)
310 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
311 if (it != m_pNamedPropertyArray->end())
313 ((*it).second)->Release();
314 m_pNamedPropertyArray->erase(it);
323 // Get Property Names
325 vector<STR_String> CValue::GetPropertyNames()
327 vector<STR_String> result;
328 if(!m_pNamedPropertyArray) return result;
329 result.reserve(m_pNamedPropertyArray->size());
331 std::map<STR_String,CValue*>::iterator it;
332 for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
334 result.push_back((*it).first);
340 // Clear all properties
342 void CValue::ClearProperties()
344 // Check if we have any properties
345 if (m_pNamedPropertyArray == NULL)
348 // Remove all properties
349 std::map<STR_String,CValue*>::iterator it;
350 for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
352 CValue* tmpval = (*it).second;
353 //STR_String name = (*it).first;
357 // Delete property array
358 delete m_pNamedPropertyArray;
359 m_pNamedPropertyArray=NULL;
365 // Set all properties' modified flag to <inModified>
367 void CValue::SetPropertiesModified(bool inModified)
369 if(!m_pNamedPropertyArray) return;
370 std::map<STR_String,CValue*>::iterator it;
372 for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
373 ((*it).second)->SetModified(inModified);
379 // Check if any of the properties in this value have been modified
381 bool CValue::IsAnyPropertyModified()
383 if(!m_pNamedPropertyArray) return false;
384 std::map<STR_String,CValue*>::iterator it;
386 for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
387 if (((*it).second)->IsModified())
396 // Get property number <inIndex>
398 CValue* CValue::GetProperty(int inIndex)
402 CValue* result = NULL;
404 if (m_pNamedPropertyArray)
406 std::map<STR_String,CValue*>::iterator it;
407 for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
409 if (count++==inIndex)
411 result = (*it).second;
423 // Get the amount of properties assiocated with this value
425 int CValue::GetPropertyCount()
427 if (m_pNamedPropertyArray)
428 return m_pNamedPropertyArray->size();
434 double* CValue::GetVector3(bool bGetTransformedVec)
436 assertd(false); // don;t get vector from me
437 return m_sZeroVec;//::sZero;
441 /*---------------------------------------------------------------------------------------------------------------------
443 ---------------------------------------------------------------------------------------------------------------------*/
448 // Release a reference to this value (when reference count reaches 0, the value is removed from the heap)
454 // Disable reference counting for this value
456 void CValue::DisableRefCount()
458 assertd(m_refcount == 1);
461 //debug(gRefCountValue--);
465 m_ValFlags.RefCountDisabled=true;
470 void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */
477 PyObjectPlus::ProcessReplica();
479 m_ValFlags.RefCountDisabled = false;
482 if (m_pNamedPropertyArray)
484 std::map<STR_String,CValue*> *pOldArray = m_pNamedPropertyArray;
485 m_pNamedPropertyArray=NULL;
486 std::map<STR_String,CValue*>::iterator it;
487 for (it= pOldArray->begin(); (it != pOldArray->end()); it++)
489 CValue *val = (*it).second->GetReplica();
490 SetProperty((*it).first,val);
496 CValue* CValue::FindIdentifier(const STR_String& identifiername)
499 CValue* result = NULL;
502 // if a dot exists, explode the name into pieces to get the subcontext
503 if ((pos=identifiername.Find('.'))>=0)
505 const STR_String rightstring = identifiername.Right(identifiername.Length() -1 - pos);
506 const STR_String leftstring = identifiername.Left(pos);
507 CValue* tempresult = GetProperty(leftstring);
510 result=tempresult->FindIdentifier(rightstring);
514 result = GetProperty(identifiername);
516 return result->AddRef();
521 result = new CErrorValue(identifiername+" not found");
528 PyAttributeDef CValue::Attributes[] = {
529 KX_PYATTRIBUTE_RO_FUNCTION("name", CValue, pyattr_get_name),
533 PyObject * CValue::pyattr_get_name(void * self_v, const KX_PYATTRIBUTE_DEF * attrdef) {
534 CValue * self = static_cast<CValue *> (self_v);
535 return PyUnicode_FromString(self->GetName());
538 CValue* CValue::ConvertPythonToValue(PyObject* pyobj, const char *error_prefix)
541 CValue* vallie = NULL;
542 /* refcounting is broking here! - this crashes anyway, just store a python list for KX_GameObject */
544 if (PyList_Check(pyobj))
546 CListValue* listval = new CListValue();
550 Py_ssize_t numitems = PyList_GET_SIZE(pyobj);
551 for (i=0;i<numitems;i++)
553 PyObject* listitem = PyList_GetItem(pyobj,i); /* borrowed ref */
554 CValue* listitemval = ConvertPythonToValue(listitem, error_prefix);
557 listval->Add(listitemval);
565 // jippie! could be converted
569 // list could not be converted... bad luck
575 if (PyFloat_Check(pyobj))
577 vallie = new CFloatValue( (float)PyFloat_AsDouble(pyobj) );
579 if (PyLong_Check(pyobj))
581 vallie = new CIntValue( (cInt)PyLong_AsLongLong(pyobj) );
583 if (PyUnicode_Check(pyobj))
585 vallie = new CStringValue(_PyUnicode_AsString(pyobj),"");
587 if (PyObject_TypeCheck(pyobj, &CValue::Type)) /* Note, dont let these get assigned to GameObject props, must check elsewhere */
589 vallie = (static_cast<CValue *>(BGE_PROXY_REF(pyobj)))->AddRef();
592 /* return an error value from the caller */
593 PyErr_Format(PyExc_TypeError, "%scould convert python value to a game engine property", error_prefix);
599 PyObject* CValue::ConvertKeysToPython( void )
601 PyObject *pylist = PyList_New( 0 );
604 if (m_pNamedPropertyArray)
606 std::map<STR_String,CValue*>::iterator it;
607 for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
609 pystr = PyUnicode_FromString( (*it).first );
610 PyList_Append(pylist, pystr);
617 #endif // WITH_PYTHON
620 ///////////////////////////////////////////////////////////////////////////////////////////////
621 ///////////////////////////////////////////////////////////////////////////////////////////////
622 /* These implementations were moved out of the header */
624 void CValue::SetOwnerExpression(class CExpression* expr)
626 /* intentionally empty */
629 void CValue::SetColorOperator(VALUE_OPERATOR op)
631 /* intentionally empty */
633 void CValue::SetValue(CValue* newval)
635 // no one should get here
636 assertd(newval->GetNumber() == 10121969);