Misc warnings
[blender.git] / source / gameengine / Expressions / Value.cpp
1 // Value.cpp: implementation of the CValue class.
2 // developed at Eindhoven University of Technology, 1997
3 // by the OOPS team
4 //////////////////////////////////////////////////////////////////////
5 /*
6  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
7  *
8  * Permission to use, copy, modify, distribute and sell this software
9  * and its documentation for any purpose is hereby granted without fee,
10  * provided that the above copyright notice appear in all copies and
11  * that both that copyright notice and this permission notice appear
12  * in supporting documentation.  Erwin Coumans makes no
13  * representations about the suitability of this software for any
14  * purpose.  It is provided "as is" without express or implied warranty.
15  *
16  */
17 #include "Value.h"
18 #include "FloatValue.h"
19 #include "IntValue.h"
20 #include "VectorValue.h"
21 #include "VoidValue.h"
22 #include "StringValue.h"
23 #include "ErrorValue.h"
24 #include "ListValue.h"
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 //////////////////////////////////////////////////////////////////////
31 // Construction/Destruction
32 //////////////////////////////////////////////////////////////////////
33
34 double CValue::m_sZeroVec[3] = {0.0,0.0,0.0};
35
36 #ifndef NO_EXP_PYTHON_EMBEDDING
37
38 PyTypeObject CValue::Type = {
39 #if (PY_VERSION_HEX >= 0x02060000)
40         PyVarObject_HEAD_INIT(NULL, 0)
41 #else
42         /* python 2.5 and below */
43         PyObject_HEAD_INIT( NULL )  /* required py macro */
44         0,                          /* ob_size */
45 #endif
46         "CValue",
47         sizeof(PyObjectPlus_Proxy),
48         0,
49         py_base_dealloc,
50         0,
51         0,
52         0,
53         0,
54         py_base_repr,
55         0,
56         0,0,0,0,0,
57         py_base_getattro,
58         py_base_setattro,
59         0,0,0,0,0,0,0,0,0,
60         Methods
61 };
62
63 PyParentObject CValue::Parents[] = {
64         &CValue::Type,
65                 NULL
66 };
67
68 PyMethodDef CValue::Methods[] = {
69         { "getName", (PyCFunction) CValue::sPyGetName, METH_NOARGS},
70         {NULL,NULL} //Sentinel
71 };
72
73 PyObject* CValue::PyGetName()
74 {
75         ShowDeprecationWarning("getName()", "the name property");
76         
77         return PyString_FromString(this->GetName());
78 }
79
80 /*#define CVALUE_DEBUG*/
81 #ifdef CVALUE_DEBUG
82 int gRefCount;
83 struct SmartCValueRef 
84 {
85         CValue *m_ref;
86         int m_count;
87         SmartCValueRef(CValue *ref)
88         {
89                 m_ref = ref;
90                 m_count = gRefCount++;
91         }
92 };
93
94 #include <vector>
95
96 std::vector<SmartCValueRef> gRefList;
97 #endif
98
99 #ifdef _DEBUG
100 //int gRefCountValue;
101 #endif
102
103 CValue::CValue(PyTypeObject *T)
104                 : PyObjectPlus(T),
105 #else
106 CValue::CValue()
107
108 #endif //NO_EXP_PYTHON_EMBEDDING
109         
110 m_pNamedPropertyArray(NULL),
111 m_refcount(1)
112 /*
113 pre: false
114 effect: constucts a CValue
115 */
116 {
117         //debug(gRefCountValue++)       // debugging
118 #ifdef _DEBUG
119         //gRefCountValue++;
120 #ifdef CVALUE_DEBUG
121         gRefList.push_back(SmartCValueRef(this));
122 #endif
123 #endif
124 }
125
126
127
128 CValue::~CValue()
129 /*
130 pre:
131 effect: deletes the object
132 */
133 {
134         ClearProperties();
135
136         assertd (m_refcount==0);
137 #ifdef CVALUE_DEBUG
138         std::vector<SmartCValueRef>::iterator it;
139         for (it=gRefList.begin(); it!=gRefList.end(); it++)
140         {
141                 if (it->m_ref == this)
142                 {
143                         *it = gRefList.back();
144                         gRefList.pop_back();
145                         break;
146                 }
147         }
148 #endif
149 }
150
151
152
153
154 #define VALUE_SUB(val1, val2) (val1)->Calc(VALUE_SUB_OPERATOR, val2)
155 #define VALUE_MUL(val1, val2) (val1)->Calc(VALUE_MUL_OPERATOR, val2)
156 #define VALUE_DIV(val1, val2) (val1)->Calc(VALUE_DIV_OPERATOR, val2)
157 #define VALUE_NEG(val1)       (val1)->Calc(VALUE_NEG_OPERATOR, val1)
158 #define VALUE_POS(val1)       (val1)->Calc(VALUE_POS_OPERATOR, val1)
159
160
161 STR_String CValue::op2str (VALUE_OPERATOR op)
162 {
163         //pre:
164         //ret: the stringrepresentation of operator op
165         
166         STR_String opmsg;
167         switch (op) {
168         case VALUE_MOD_OPERATOR:
169                 opmsg = " % ";
170                 break;
171         case VALUE_ADD_OPERATOR:
172                 opmsg = " + ";
173                 break;
174         case VALUE_SUB_OPERATOR:
175                 opmsg = " - ";
176                 break;
177         case VALUE_MUL_OPERATOR:
178                 opmsg = " * ";
179                 break;
180         case VALUE_DIV_OPERATOR:
181                 opmsg = " / ";
182                 break;
183         case VALUE_NEG_OPERATOR:
184                 opmsg = " -";
185                 break;
186         case VALUE_POS_OPERATOR:
187                 opmsg = " +";
188                 break;
189         case VALUE_AND_OPERATOR:
190                 opmsg = " & ";
191                 break;
192         case VALUE_OR_OPERATOR:
193                 opmsg = " | ";
194                 break;
195         case VALUE_EQL_OPERATOR:
196                 opmsg = " = ";
197                 break;
198         case VALUE_NEQ_OPERATOR:
199                 opmsg = " != ";
200                 break;
201         case VALUE_NOT_OPERATOR:
202                 opmsg = " !";
203                 break;
204         default:
205                 opmsg="Error in Errorhandling routine.";
206                 //              AfxMessageBox("Invalid operator");
207                 break;
208         }
209         return opmsg;
210 }
211
212
213
214
215
216 //---------------------------------------------------------------------------------------------------------------------
217 //      Property Management
218 //---------------------------------------------------------------------------------------------------------------------
219
220
221
222 //
223 // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed
224 //
225 void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
226 {
227         if (ioProperty==NULL)
228         {       // Check if somebody is setting an empty property
229                 trace("Warning:trying to set empty property!");
230                 return;
231         }
232
233         if (m_pNamedPropertyArray)
234         {       // Try to replace property (if so -> exit as soon as we replaced it)
235                 CValue* oldval = (*m_pNamedPropertyArray)[name];
236                 if (oldval)
237                         oldval->Release();
238         }
239         else { // Make sure we have a property array
240                 m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
241         }
242         
243         // Add property at end of array
244         (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
245 }
246
247 void CValue::SetProperty(const char* name,CValue* ioProperty)
248 {
249         if (ioProperty==NULL)
250         {       // Check if somebody is setting an empty property
251                 trace("Warning:trying to set empty property!");
252                 return;
253         }
254
255         if (m_pNamedPropertyArray)
256         {       // Try to replace property (if so -> exit as soon as we replaced it)
257                 CValue* oldval = (*m_pNamedPropertyArray)[name];
258                 if (oldval)
259                         oldval->Release();
260         }
261         else { // Make sure we have a property array
262                 m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
263         }
264         
265         // Add property at end of array
266         (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
267 }
268
269 //
270 // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
271 //
272 CValue* CValue::GetProperty(const STR_String & inName)
273 {
274         if (m_pNamedPropertyArray) {
275                 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
276                 if (it != m_pNamedPropertyArray->end())
277                         return (*it).second;
278         }
279         return NULL;
280 }
281
282 CValue* CValue::GetProperty(const char *inName)
283 {
284         if (m_pNamedPropertyArray) {
285                 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
286                 if (it != m_pNamedPropertyArray->end())
287                         return (*it).second;
288         }
289         return NULL;
290 }
291
292 //
293 // Get text description of property with name <inName>, returns an empty string if there is no property named <inName>
294 //
295 const STR_String& CValue::GetPropertyText(const STR_String & inName)
296 {
297         const static STR_String sEmpty("");
298
299         CValue *property = GetProperty(inName);
300         if (property)
301                 return property->GetText();
302         else
303                 return sEmpty;
304 }
305
306 float CValue::GetPropertyNumber(const STR_String& inName,float defnumber)
307 {
308         CValue *property = GetProperty(inName);
309         if (property)
310                 return property->GetNumber(); 
311         else
312                 return defnumber;
313 }
314
315
316
317 //
318 // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed
319 //
320 bool CValue::RemoveProperty(const char *inName)
321 {
322         // Check if there are properties at all which can be removed
323         if (m_pNamedPropertyArray)
324         {
325                 std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
326                 if (it != m_pNamedPropertyArray->end())
327                 {
328                         ((*it).second)->Release();
329                         m_pNamedPropertyArray->erase(it);
330                         return true;
331                 }
332         }
333         
334         return false;
335 }
336
337 //
338 // Get Property Names
339 //
340 vector<STR_String> CValue::GetPropertyNames()
341 {
342         vector<STR_String> result;
343         if(!m_pNamedPropertyArray) return result;
344         result.reserve(m_pNamedPropertyArray->size());
345         
346         std::map<STR_String,CValue*>::iterator it;
347         for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
348         {
349                 result.push_back((*it).first);
350         }
351         return result;
352 }
353
354 //
355 // Clear all properties
356 //
357 void CValue::ClearProperties()
358 {               
359         // Check if we have any properties
360         if (m_pNamedPropertyArray == NULL)
361                 return;
362
363         // Remove all properties
364         std::map<STR_String,CValue*>::iterator it;
365         for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
366         {
367                 CValue* tmpval = (*it).second;
368                 //STR_String name = (*it).first;
369                 tmpval->Release();
370         }
371
372         // Delete property array
373         delete m_pNamedPropertyArray;
374         m_pNamedPropertyArray=NULL;
375 }
376
377
378
379 //
380 // Set all properties' modified flag to <inModified>
381 //
382 void CValue::SetPropertiesModified(bool inModified)
383 {
384         if(!m_pNamedPropertyArray) return;
385         std::map<STR_String,CValue*>::iterator it;
386         
387         for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
388                 ((*it).second)->SetModified(inModified);
389 }
390
391
392
393 //
394 // Check if any of the properties in this value have been modified
395 //
396 bool CValue::IsAnyPropertyModified()
397 {
398         if(!m_pNamedPropertyArray) return false;
399         std::map<STR_String,CValue*>::iterator it;
400         
401         for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
402                 if (((*it).second)->IsModified())
403                         return true;
404         
405         return false;
406 }
407
408
409
410 //
411 // Get property number <inIndex>
412 //
413 CValue* CValue::GetProperty(int inIndex)
414 {
415
416         int count=0;
417         CValue* result = NULL;
418
419         if (m_pNamedPropertyArray)
420         {
421                 std::map<STR_String,CValue*>::iterator it;
422                 for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
423                 {
424                         if (count++==inIndex)
425                         {
426                                 result = (*it).second;
427                                 break;
428                         }
429                 }
430
431         }
432         return result;
433 }
434
435
436
437 //
438 // Get the amount of properties assiocated with this value
439 //
440 int CValue::GetPropertyCount()
441 {
442         if (m_pNamedPropertyArray)
443                 return m_pNamedPropertyArray->size();
444         else
445                 return 0;
446 }
447
448
449 double*         CValue::GetVector3(bool bGetTransformedVec)
450 {
451         assertd(false); // don;t get vector from me
452         return m_sZeroVec;//::sZero;
453 }
454
455
456 /*---------------------------------------------------------------------------------------------------------------------
457         Reference Counting
458 ---------------------------------------------------------------------------------------------------------------------*/
459
460
461
462 //
463 // Release a reference to this value (when reference count reaches 0, the value is removed from the heap)
464 //
465
466
467
468 //
469 // Disable reference counting for this value
470 //
471 void CValue::DisableRefCount()
472 {
473         assertd(m_refcount == 1);
474         m_refcount--;
475
476         //debug(gRefCountValue--);
477 #ifdef _DEBUG
478         //gRefCountValue--;
479 #endif
480         m_ValFlags.RefCountDisabled=true;
481 }
482
483
484
485 void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */
486 {
487         m_refcount = 1;
488         
489 #ifdef _DEBUG
490         //gRefCountValue++;
491 #endif
492         PyObjectPlus::ProcessReplica();
493
494         m_ValFlags.RefCountDisabled = false;
495
496         /* copy all props */
497         if (m_pNamedPropertyArray)
498         {
499                 std::map<STR_String,CValue*> *pOldArray = m_pNamedPropertyArray;
500                 m_pNamedPropertyArray=NULL;
501                 std::map<STR_String,CValue*>::iterator it;
502                 for (it= pOldArray->begin(); (it != pOldArray->end()); it++)
503                 {
504                         CValue *val = (*it).second->GetReplica();
505                         SetProperty((*it).first,val);
506                         val->Release();
507                 }
508         }
509 }
510
511 CValue* CValue::FindIdentifier(const STR_String& identifiername)
512 {
513
514         CValue* result = NULL;
515
516         int pos = 0;
517         // if a dot exists, explode the name into pieces to get the subcontext
518         if ((pos=identifiername.Find('.'))>=0)
519         {
520                 const STR_String rightstring = identifiername.Right(identifiername.Length() -1 - pos);
521                 const STR_String leftstring = identifiername.Left(pos);
522                 CValue* tempresult = GetProperty(leftstring);
523                 if (tempresult)
524                 {
525                         result=tempresult->FindIdentifier(rightstring);
526                 } 
527         } else
528         {
529                 result = GetProperty(identifiername);
530                 if (result)
531                         return result->AddRef();
532         }
533         if (!result)
534         {
535                 // warning here !!!
536                 result = new CErrorValue(identifiername+" not found");
537         }
538         return result;
539 }
540
541
542 #ifndef NO_EXP_PYTHON_EMBEDDING
543
544
545 static PyMethodDef      CValueMethods[] = 
546 {
547         //{ "new", CValue::PyMake , METH_VARARGS},
548         { NULL,NULL}    // Sentinel
549 };
550
551 PyAttributeDef CValue::Attributes[] = {
552         KX_PYATTRIBUTE_RO_FUNCTION("name",      CValue, pyattr_get_name),
553         { NULL }        //Sentinel
554 };
555
556
557 PyObject*       CValue::py_getattro(PyObject *attr)
558 {
559         char *attr_str= PyString_AsString(attr);
560         CValue* resultattr = GetProperty(attr_str);
561         if (resultattr)
562         {
563                 PyObject* pyconvert = resultattr->ConvertValueToPython();
564         
565                 if (pyconvert)
566                         return pyconvert;
567                 else
568                         return resultattr->GetProxy();
569         }
570         py_getattro_up(PyObjectPlus);
571 }
572
573 PyObject* CValue::py_getattro_dict() {
574         py_getattro_dict_up(PyObjectPlus);
575 }
576
577 PyObject * CValue::pyattr_get_name(void * self_v, const KX_PYATTRIBUTE_DEF * attrdef) {
578         CValue * self = static_cast<CValue *> (self_v);
579         return PyString_FromString(self->GetName());
580 }
581
582 CValue* CValue::ConvertPythonToValue(PyObject* pyobj, const char *error_prefix)
583 {
584
585         CValue* vallie = NULL;
586         /* refcounting is broking here! - this crashes anyway, just store a python list for KX_GameObject */
587 #if 0
588         if (PyList_Check(pyobj))
589         {
590                 CListValue* listval = new CListValue();
591                 bool error = false;
592
593                 int i;
594                 int numitems = PyList_Size(pyobj);
595                 for (i=0;i<numitems;i++)
596                 {
597                         PyObject* listitem = PyList_GetItem(pyobj,i); /* borrowed ref */
598                         CValue* listitemval = ConvertPythonToValue(listitem, error_prefix);
599                         if (listitemval)
600                         {
601                                 listval->Add(listitemval);
602                         } else
603                         {
604                                 error = true;
605                         }
606                 }
607                 if (!error)
608                 {
609                         // jippie! could be converted
610                         vallie = listval;
611                 } else
612                 {
613                         // list could not be converted... bad luck
614                         listval->Release();
615                 }
616
617         } else
618 #endif
619         if (PyFloat_Check(pyobj))
620         {
621                 vallie = new CFloatValue( (float)PyFloat_AsDouble(pyobj) );
622         } else
623         if (PyInt_Check(pyobj))
624         {
625                 vallie = new CIntValue( (cInt)PyInt_AS_LONG(pyobj) );
626         } else
627         if (PyLong_Check(pyobj))
628         {
629                 vallie = new CIntValue( (cInt)PyLong_AsLongLong(pyobj) );
630         } else
631         if (PyString_Check(pyobj))
632         {
633                 vallie = new CStringValue(PyString_AsString(pyobj),"");
634         } else
635         if (BGE_PROXY_CHECK_TYPE(pyobj)) /* Note, dont let these get assigned to GameObject props, must check elsewhere */
636         {
637                 if (BGE_PROXY_REF(pyobj) && (BGE_PROXY_REF(pyobj))->isA(&CValue::Type))
638                 {
639                         vallie = (static_cast<CValue *>(BGE_PROXY_REF(pyobj)))->AddRef();
640                 } else {
641                         
642                         if(BGE_PROXY_REF(pyobj))        /* this is not a CValue */
643                                 PyErr_Format(PyExc_TypeError, "%sgame engine python type cannot be used as a property", error_prefix);
644                         else                                            /* PyObjectPlus_Proxy has been removed, cant use */
645                                 PyErr_Format(PyExc_SystemError, "%s"BGE_PROXY_ERROR_MSG, error_prefix);
646                 }
647         } else
648         {
649                 /* return an error value from the caller */
650                 PyErr_Format(PyExc_TypeError, "%scould convert python value to a game engine property", error_prefix);
651         }
652         return vallie;
653
654 }
655
656 int     CValue::py_delattro(PyObject *attr)
657 {
658         char *attr_str= PyString_AsString(attr);
659         if (RemoveProperty(attr_str))
660                 return 0;
661         
662         PyErr_Format(PyExc_AttributeError, "attribute \"%s\" dosnt exist", attr_str);
663         return PY_SET_ATTR_MISSING;
664 }
665
666 int     CValue::py_setattro(PyObject *attr, PyObject* pyobj)
667 {
668         char *attr_str= PyString_AsString(attr);
669         CValue* oldprop = GetProperty(attr_str);        
670         CValue* vallie;
671
672         /* Dissallow python to assign GameObjects, Scenes etc as values */
673         if ((BGE_PROXY_CHECK_TYPE(pyobj)==0) && (vallie = ConvertPythonToValue(pyobj, "cvalue.attr = value: ")))
674         {
675                 if (oldprop)
676                         oldprop->SetValue(vallie);
677                 else
678                         SetProperty(attr_str, vallie);
679                 
680                 vallie->Release();
681         }
682         else {
683                 // ConvertPythonToValue sets the error message
684                 // must return missing so KX_GameObect knows this
685                 // attribute was not a function or bult in attribute,
686                 //
687                 // CValue attributes override internal attributes
688                 // so if it exists as a CValue attribute already,
689                 // assume your trying to set it to a differnt CValue attribute
690                 // otherwise return PY_SET_ATTR_MISSING so children
691                 // classes know they can set it without conflict 
692                 
693                 if (GetProperty(attr_str))
694                         return PY_SET_ATTR_COERCE_FAIL; /* failed to set an existing attribute */
695                 else
696                         return PY_SET_ATTR_MISSING; /* allow the KX_GameObject dict to set */
697         }
698         
699         //PyObjectPlus::py_setattro(attr,value);
700         return PY_SET_ATTR_SUCCESS;
701 };
702
703 PyObject*       CValue::ConvertKeysToPython( void )
704 {
705         PyObject *pylist = PyList_New( 0 );
706         PyObject *pystr;
707         
708         if (m_pNamedPropertyArray)
709         {
710                 std::map<STR_String,CValue*>::iterator it;
711                 for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
712                 {
713                         pystr = PyString_FromString( (*it).first );
714                         PyList_Append(pylist, pystr);
715                         Py_DECREF( pystr );
716                 }
717         }
718         return pylist;
719 }
720
721 /*
722 PyObject*       CValue::PyMake(PyObject* ignored,PyObject* args)
723 {
724
725         //if (!PyArg_ParseTuple(args,"s:make",&name)) return NULL;
726         Py_RETURN_NONE;//new CValue();
727 }
728 */
729
730 #if (PY_VERSION_HEX >= 0x03000000)
731 static struct PyModuleDef CValue_module_def = {
732         {}, /* m_base */
733         "CValue",  /* m_name */
734         0,  /* m_doc */
735         0,  /* m_size */
736         CValueMethods,  /* m_methods */
737         0,  /* m_reload */
738         0,  /* m_traverse */
739         0,  /* m_clear */
740         0,  /* m_free */
741 };
742 #endif
743
744 extern "C" {
745         void initCValue(void)
746         {
747                 PyObject *m;
748                 /* Use existing module where possible
749                  * be careful not to init any runtime vars after this */
750                 m = PyImport_ImportModule( "CValue" );
751                 if(m) {
752                         Py_DECREF(m);
753                         //return m;
754                 }
755                 else {
756                         PyErr_Clear();
757                 
758 #if (PY_VERSION_HEX >= 0x03000000)
759                         PyModule_Create(&CValue_module_def);
760 #else
761                         Py_InitModule("CValue",CValueMethods);
762 #endif
763                 }
764         }
765 }
766
767
768
769 #endif //NO_EXP_PYTHON_EMBEDDING
770
771 ///////////////////////////////////////////////////////////////////////////////////////////////
772 ///////////////////////////////////////////////////////////////////////////////////////////////
773 /* These implementations were moved out of the header */
774
775 void CValue::SetOwnerExpression(class CExpression* expr)
776 {
777         /* intentionally empty */
778 }
779
780 void CValue::SetColorOperator(VALUE_OPERATOR op)
781 {
782         /* intentionally empty */
783 }
784 void CValue::SetValue(CValue* newval)
785
786         // no one should get here
787         assertd(newval->GetNumber() == 10121969);       
788 }