code cleanup:
[blender.git] / source / gameengine / Expressions / Value.cpp
1 /** \file gameengine/Expressions/Value.cpp
2  *  \ingroup expressions
3  */
4 // Value.cpp: implementation of the CValue class.
5 // developed at Eindhoven University of Technology, 1997
6 // by the OOPS team
7 //////////////////////////////////////////////////////////////////////
8 /*
9  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
10  *
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.
18  *
19  */
20 #include "Value.h"
21 #include "BoolValue.h"
22 #include "FloatValue.h"
23 #include "IntValue.h"
24 #include "VectorValue.h"
25 #include "VoidValue.h"
26 #include "StringValue.h"
27 #include "ErrorValue.h"
28 #include "ListValue.h"
29
30 //////////////////////////////////////////////////////////////////////
31 // Construction/Destruction
32 //////////////////////////////////////////////////////////////////////
33
34 double CValue::m_sZeroVec[3] = {0.0,0.0,0.0};
35
36 #ifdef WITH_PYTHON
37
38 PyTypeObject CValue::Type = {
39         PyVarObject_HEAD_INIT(NULL, 0)
40         "CValue",
41         sizeof(PyObjectPlus_Proxy),
42         0,
43         py_base_dealloc,
44         0,
45         0,
46         0,
47         0,
48         py_base_repr,
49         0,
50         0,0,0,0,0,
51         NULL,
52         NULL,
53         0,
54         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
55         0,0,0,0,0,0,0,
56         Methods,
57         0,
58         0,
59         &PyObjectPlus::Type,
60         0,0,0,0,0,0,
61         py_base_new
62 };
63
64 PyMethodDef CValue::Methods[] = {
65         {NULL,NULL} //Sentinel
66 };
67 #endif // WITH_PYTHON
68
69
70 /*#define CVALUE_DEBUG*/
71 #ifdef CVALUE_DEBUG
72 int gRefCount;
73 struct SmartCValueRef 
74 {
75         CValue *m_ref;
76         int m_count;
77         SmartCValueRef(CValue *ref)
78         {
79                 m_ref = ref;
80                 m_count = gRefCount++;
81         }
82 };
83
84 #include <vector>
85
86 std::vector<SmartCValueRef> gRefList;
87 #endif
88
89 #ifdef _DEBUG
90 //int gRefCountValue;
91 #endif
92
93 CValue::CValue()
94                 : PyObjectPlus(),
95         
96 m_pNamedPropertyArray(NULL),
97 m_refcount(1)
98 /*
99 pre: false
100 effect: constucts a CValue
101 */
102 {
103         //debug(gRefCountValue++)       // debugging
104 #ifdef _DEBUG
105         //gRefCountValue++;
106 #ifdef CVALUE_DEBUG
107         gRefList.push_back(SmartCValueRef(this));
108 #endif
109 #endif
110 }
111
112
113
114 CValue::~CValue()
115 /*
116 pre:
117 effect: deletes the object
118 */
119 {
120         ClearProperties();
121
122         assertd (m_refcount==0);
123 #ifdef CVALUE_DEBUG
124         std::vector<SmartCValueRef>::iterator it;
125         for (it=gRefList.begin(); it!=gRefList.end(); it++)
126         {
127                 if (it->m_ref == this)
128                 {
129                         *it = gRefList.back();
130                         gRefList.pop_back();
131                         break;
132                 }
133         }
134 #endif
135 }
136
137
138
139
140 #define VALUE_SUB(val1, val2) (val1)->Calc(VALUE_SUB_OPERATOR, val2)
141 #define VALUE_MUL(val1, val2) (val1)->Calc(VALUE_MUL_OPERATOR, val2)
142 #define VALUE_DIV(val1, val2) (val1)->Calc(VALUE_DIV_OPERATOR, val2)
143 #define VALUE_NEG(val1)       (val1)->Calc(VALUE_NEG_OPERATOR, val1)
144 #define VALUE_POS(val1)       (val1)->Calc(VALUE_POS_OPERATOR, val1)
145
146
147 STR_String CValue::op2str(VALUE_OPERATOR op)
148 {
149         //pre:
150         //ret: the stringrepresentation of operator op
151         
152         STR_String opmsg;
153         switch (op) {
154         case VALUE_MOD_OPERATOR:
155                 opmsg = " % ";
156                 break;
157         case VALUE_ADD_OPERATOR:
158                 opmsg = " + ";
159                 break;
160         case VALUE_SUB_OPERATOR:
161                 opmsg = " - ";
162                 break;
163         case VALUE_MUL_OPERATOR:
164                 opmsg = " * ";
165                 break;
166         case VALUE_DIV_OPERATOR:
167                 opmsg = " / ";
168                 break;
169         case VALUE_NEG_OPERATOR:
170                 opmsg = " -";
171                 break;
172         case VALUE_POS_OPERATOR:
173                 opmsg = " +";
174                 break;
175         case VALUE_AND_OPERATOR:
176                 opmsg = " & ";
177                 break;
178         case VALUE_OR_OPERATOR:
179                 opmsg = " | ";
180                 break;
181         case VALUE_EQL_OPERATOR:
182                 opmsg = " = ";
183                 break;
184         case VALUE_NEQ_OPERATOR:
185                 opmsg = " != ";
186                 break;
187         case VALUE_NOT_OPERATOR:
188                 opmsg = " !";
189                 break;
190         default:
191                 opmsg="Error in Errorhandling routine.";
192                 //              AfxMessageBox("Invalid operator");
193                 break;
194         }
195         return opmsg;
196 }
197
198
199
200
201
202 //---------------------------------------------------------------------------------------------------------------------
203 //      Property Management
204 //---------------------------------------------------------------------------------------------------------------------
205
206
207
208 //
209 // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed
210 //
211 void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
212 {
213         if (ioProperty==NULL)
214         {       // Check if somebody is setting an empty property
215                 trace("Warning:trying to set empty property!");
216                 return;
217         }
218
219         if (m_pNamedPropertyArray)
220         {       // Try to replace property (if so -> exit as soon as we replaced it)
221                 CValue* oldval = (*m_pNamedPropertyArray)[name];
222                 if (oldval)
223                         oldval->Release();
224         }
225         else { // Make sure we have a property array
226                 m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
227         }
228         
229         // Add property at end of array
230         (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
231 }
232
233 void CValue::SetProperty(const char* name,CValue* ioProperty)
234 {
235         if (ioProperty==NULL)
236         {       // Check if somebody is setting an empty property
237                 trace("Warning:trying to set empty property!");
238                 return;
239         }
240
241         if (m_pNamedPropertyArray)
242         {       // Try to replace property (if so -> exit as soon as we replaced it)
243                 CValue* oldval = (*m_pNamedPropertyArray)[name];
244                 if (oldval)
245                         oldval->Release();
246         }
247         else { // Make sure we have a property array
248                 m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
249         }
250         
251         // Add property at end of array
252         (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
253 }
254
255 //
256 // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
257 //
258 CValue* CValue::GetProperty(const STR_String & inName)
259 {
260         if (m_pNamedPropertyArray) {
261                 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
262                 if (it != m_pNamedPropertyArray->end())
263                         return (*it).second;
264         }
265         return NULL;
266 }
267
268 CValue* CValue::GetProperty(const char *inName)
269 {
270         if (m_pNamedPropertyArray) {
271                 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
272                 if (it != m_pNamedPropertyArray->end())
273                         return (*it).second;
274         }
275         return NULL;
276 }
277
278 //
279 // Get text description of property with name <inName>, returns an empty string if there is no property named <inName>
280 //
281 const STR_String& CValue::GetPropertyText(const STR_String & inName)
282 {
283         const static STR_String sEmpty("");
284
285         CValue *property = GetProperty(inName);
286         if (property)
287                 return property->GetText();
288         else
289                 return sEmpty;
290 }
291
292 float CValue::GetPropertyNumber(const STR_String& inName,float defnumber)
293 {
294         CValue *property = GetProperty(inName);
295         if (property)
296                 return property->GetNumber(); 
297         else
298                 return defnumber;
299 }
300
301
302
303 //
304 // 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 //
306 bool CValue::RemoveProperty(const char *inName)
307 {
308         // Check if there are properties at all which can be removed
309         if (m_pNamedPropertyArray)
310         {
311                 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
312                 if (it != m_pNamedPropertyArray->end())
313                 {
314                         ((*it).second)->Release();
315                         m_pNamedPropertyArray->erase(it);
316                         return true;
317                 }
318         }
319         
320         return false;
321 }
322
323 //
324 // Get Property Names
325 //
326 vector<STR_String> CValue::GetPropertyNames()
327 {
328         vector<STR_String> result;
329         if (!m_pNamedPropertyArray) return result;
330         result.reserve(m_pNamedPropertyArray->size());
331         
332         std::map<STR_String,CValue*>::iterator it;
333         for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
334         {
335                 result.push_back((*it).first);
336         }
337         return result;
338 }
339
340 //
341 // Clear all properties
342 //
343 void CValue::ClearProperties()
344 {
345         // Check if we have any properties
346         if (m_pNamedPropertyArray == NULL)
347                 return;
348
349         // Remove all properties
350         std::map<STR_String,CValue*>::iterator it;
351         for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
352         {
353                 CValue* tmpval = (*it).second;
354                 //STR_String name = (*it).first;
355                 tmpval->Release();
356         }
357
358         // Delete property array
359         delete m_pNamedPropertyArray;
360         m_pNamedPropertyArray=NULL;
361 }
362
363
364
365 //
366 // Set all properties' modified flag to <inModified>
367 //
368 void CValue::SetPropertiesModified(bool inModified)
369 {
370         if (!m_pNamedPropertyArray) return;
371         std::map<STR_String,CValue*>::iterator it;
372         
373         for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
374                 ((*it).second)->SetModified(inModified);
375 }
376
377
378
379 //
380 // Check if any of the properties in this value have been modified
381 //
382 bool CValue::IsAnyPropertyModified()
383 {
384         if (!m_pNamedPropertyArray) return false;
385         std::map<STR_String,CValue*>::iterator it;
386         
387         for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
388                 if (((*it).second)->IsModified())
389                         return true;
390         
391         return false;
392 }
393
394
395
396 //
397 // Get property number <inIndex>
398 //
399 CValue* CValue::GetProperty(int inIndex)
400 {
401
402         int count=0;
403         CValue* result = NULL;
404
405         if (m_pNamedPropertyArray)
406         {
407                 std::map<STR_String,CValue*>::iterator it;
408                 for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
409                 {
410                         if (count++ == inIndex)
411                         {
412                                 result = (*it).second;
413                                 break;
414                         }
415                 }
416
417         }
418         return result;
419 }
420
421
422
423 //
424 // Get the amount of properties assiocated with this value
425 //
426 int CValue::GetPropertyCount()
427 {
428         if (m_pNamedPropertyArray)
429                 return m_pNamedPropertyArray->size();
430         else
431                 return 0;
432 }
433
434
435 double*         CValue::GetVector3(bool bGetTransformedVec)
436 {
437         assertd(false); // don't get vector from me
438         return m_sZeroVec;//::sZero;
439 }
440
441
442 /*---------------------------------------------------------------------------------------------------------------------
443         Reference Counting
444 ---------------------------------------------------------------------------------------------------------------------*/
445
446
447
448 //
449 // Release a reference to this value (when reference count reaches 0, the value is removed from the heap)
450 //
451
452
453
454 //
455 // Disable reference counting for this value
456 //
457 void CValue::DisableRefCount()
458 {
459         assertd(m_refcount == 1);
460         m_refcount--;
461
462         //debug(gRefCountValue--);
463 #ifdef _DEBUG
464         //gRefCountValue--;
465 #endif
466         m_ValFlags.RefCountDisabled=true;
467 }
468
469
470
471 void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */
472 {
473         m_refcount = 1;
474         
475 #ifdef _DEBUG
476         //gRefCountValue++;
477 #endif
478         PyObjectPlus::ProcessReplica();
479
480         m_ValFlags.RefCountDisabled = false;
481
482         /* copy all props */
483         if (m_pNamedPropertyArray)
484         {
485                 std::map<STR_String,CValue*> *pOldArray = m_pNamedPropertyArray;
486                 m_pNamedPropertyArray=NULL;
487                 std::map<STR_String,CValue*>::iterator it;
488                 for (it= pOldArray->begin(); (it != pOldArray->end()); it++)
489                 {
490                         CValue *val = (*it).second->GetReplica();
491                         SetProperty((*it).first,val);
492                         val->Release();
493                 }
494         }
495 }
496
497 CValue* CValue::FindIdentifier(const STR_String& identifiername)
498 {
499
500         CValue* result = NULL;
501
502         int pos = 0;
503         // if a dot exists, explode the name into pieces to get the subcontext
504         if ((pos=identifiername.Find('.'))>=0)
505         {
506                 const STR_String rightstring = identifiername.Right(identifiername.Length() -1 - pos);
507                 const STR_String leftstring = identifiername.Left(pos);
508                 CValue* tempresult = GetProperty(leftstring);
509                 if (tempresult)
510                 {
511                         result=tempresult->FindIdentifier(rightstring);
512                 } 
513         } else
514         {
515                 result = GetProperty(identifiername);
516                 if (result)
517                         return result->AddRef();
518         }
519         if (!result)
520         {
521                 // warning here !!!
522                 result = new CErrorValue(identifiername+" not found");
523         }
524         return result;
525 }
526
527 #ifdef WITH_PYTHON
528
529 PyAttributeDef CValue::Attributes[] = {
530         KX_PYATTRIBUTE_RO_FUNCTION("name",      CValue, pyattr_get_name),
531         { NULL }        //Sentinel
532 };
533
534 PyObject *CValue::pyattr_get_name(void * self_v, const KX_PYATTRIBUTE_DEF *attrdef)
535 {
536         CValue * self = static_cast<CValue *> (self_v);
537         return PyUnicode_From_STR_String(self->GetName());
538 }
539
540 CValue* CValue::ConvertPythonToValue(PyObject *pyobj, const char *error_prefix)
541 {
542
543         CValue* vallie = NULL;
544         /* refcounting is broking here! - this crashes anyway, just store a python list for KX_GameObject */
545 #if 0
546         if (PyList_Check(pyobj))
547         {
548                 CListValue* listval = new CListValue();
549                 bool error = false;
550
551                 Py_ssize_t i;
552                 Py_ssize_t numitems = PyList_GET_SIZE(pyobj);
553                 for (i=0;i<numitems;i++)
554                 {
555                         PyObject *listitem = PyList_GetItem(pyobj,i); /* borrowed ref */
556                         CValue* listitemval = ConvertPythonToValue(listitem, error_prefix);
557                         if (listitemval)
558                         {
559                                 listval->Add(listitemval);
560                         } else
561                         {
562                                 error = true;
563                         }
564                 }
565                 if (!error)
566                 {
567                         // jippie! could be converted
568                         vallie = listval;
569                 } else
570                 {
571                         // list could not be converted... bad luck
572                         listval->Release();
573                 }
574
575         } else
576 #endif
577         /* note: Boolean check should go before Int check [#34677] */
578         if (PyBool_Check(pyobj))
579         {
580                 vallie = new CBoolValue( (bool)PyLong_AsLongLong(pyobj) );
581         } else
582         if (PyFloat_Check(pyobj))
583         {
584                 vallie = new CFloatValue( (float)PyFloat_AsDouble(pyobj) );
585         } else
586         if (PyLong_Check(pyobj))
587         {
588                 vallie = new CIntValue( (cInt)PyLong_AsLongLong(pyobj) );
589         } else
590         if (PyUnicode_Check(pyobj))
591         {
592                 vallie = new CStringValue(_PyUnicode_AsString(pyobj),"");
593         } else
594         if (PyObject_TypeCheck(pyobj, &CValue::Type)) /* Note, don't let these get assigned to GameObject props, must check elsewhere */
595         {
596                 vallie = (static_cast<CValue *>(BGE_PROXY_REF(pyobj)))->AddRef();
597         } else
598         {
599                 /* return an error value from the caller */
600                 PyErr_Format(PyExc_TypeError, "%scould convert python value to a game engine property", error_prefix);
601         }
602         return vallie;
603
604 }
605
606 PyObject *CValue::ConvertKeysToPython(void)
607 {
608         if (m_pNamedPropertyArray)
609         {
610                 PyObject *pylist= PyList_New(m_pNamedPropertyArray->size());
611                 Py_ssize_t i= 0;
612
613                 std::map<STR_String,CValue*>::iterator it;
614                 for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
615                 {
616                         PyList_SET_ITEM(pylist, i++, PyUnicode_From_STR_String((*it).first));
617                 }
618
619                 return pylist;
620         }
621         else {
622                 return PyList_New(0);
623         }
624 }
625
626 #endif // WITH_PYTHON
627
628
629 ///////////////////////////////////////////////////////////////////////////////////////////////
630 ///////////////////////////////////////////////////////////////////////////////////////////////
631 /* These implementations were moved out of the header */
632
633 void CValue::SetOwnerExpression(class CExpression* expr)
634 {
635         /* intentionally empty */
636 }
637
638 void CValue::SetColorOperator(VALUE_OPERATOR op)
639 {
640         /* intentionally empty */
641 }
642 void CValue::SetValue(CValue* newval)
643
644         // no one should get here
645         assertd(newval->GetNumber() == 10121969);
646 }