Blender  V2.59
PyObjectPlus.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: PyObjectPlus.cpp 38602 2011-07-22 11:21:01Z campbellbarton $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 /*------------------------------
00035  * PyObjectPlus cpp
00036  *
00037  * C++ library routines for Crawl 3.2
00038  *
00039  * Derived from work by
00040  * David Redish
00041  * graduate student
00042  * Computer Science Department 
00043  * Carnegie Mellon University (CMU)
00044  * Center for the Neural Basis of Cognition (CNBC) 
00045  * http://www.python.org/doc/PyCPP.html
00046  *
00047 ------------------------------*/
00048 #include <stdlib.h>
00049 #include <stddef.h>
00050 
00051 #include "PyObjectPlus.h"
00052 #include "STR_String.h"
00053 #include "MT_Vector3.h"
00054 #include "MEM_guardedalloc.h"
00055 
00056 PyObjectPlus::~PyObjectPlus()
00057 {
00058 #ifdef WITH_PYTHON
00059         if(m_proxy) {
00060                 BGE_PROXY_REF(m_proxy)= NULL;
00061                 Py_DECREF(m_proxy);                     /* Remove own reference, python may still have 1 */
00062         }
00063 //      assert(ob_refcnt==0);
00064 #endif
00065 }
00066 
00067 PyObjectPlus::PyObjectPlus() : SG_QList()                               // constructor
00068 {
00069 #ifdef WITH_PYTHON
00070         m_proxy= NULL;
00071 #endif
00072 };
00073 
00074 void PyObjectPlus::ProcessReplica()
00075 {
00076 #ifdef WITH_PYTHON
00077         /* Clear the proxy, will be created again if needed with GetProxy()
00078          * otherwise the PyObject will point to the wrong reference */
00079         m_proxy= NULL;
00080 #endif
00081 }
00082 
00083 /* Sometimes we might want to manually invalidate a BGE type even if
00084  * it hasnt been released by the BGE, say for example when an object
00085  * is removed from a scene, accessing it may cause problems.
00086  *
00087  * In this case the current proxy is made invalid, disowned,
00088  * and will raise an error on access. However if python can get access
00089  * to this class again it will make a new proxy and work as expected.
00090  */
00091 void PyObjectPlus::InvalidateProxy()            // check typename of each parent
00092 {
00093 #ifdef WITH_PYTHON
00094         if(m_proxy) {
00095                 BGE_PROXY_REF(m_proxy)=NULL;
00096                 Py_DECREF(m_proxy);
00097                 m_proxy= NULL;
00098         }
00099 #endif
00100 }
00101 
00102 
00103 #ifdef WITH_PYTHON
00104 
00105 /*------------------------------
00106  * PyObjectPlus Type            -- Every class, even the abstract one should have a Type
00107 ------------------------------*/
00108 
00109 
00110 PyTypeObject PyObjectPlus::Type = {
00111         PyVarObject_HEAD_INIT(NULL, 0)
00112         "PyObjectPlus",                                 /*tp_name*/
00113         sizeof(PyObjectPlus_Proxy),             /*tp_basicsize*/
00114         0,                                                              /*tp_itemsize*/
00115         /* methods */
00116         py_base_dealloc,                                /* tp_dealloc */
00117         0,                                                              /* printfunc tp_print; */
00118         0,                                                              /* getattrfunc tp_getattr; */
00119         0,                                                              /* setattrfunc tp_setattr; */
00120         0,                                                              /* tp_compare */ /* DEPRECATED in python 3.0! */
00121         py_base_repr,                                   /* tp_repr */
00122         0,0,0,0,0,0,0,0,0,                              /* Method suites for standard classes */
00123         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* long tp_flags; */
00124         0,0,0,0,
00125         /* weak reference enabler */
00126 #ifdef USE_WEAKREFS
00127         offsetof(PyObjectPlus_Proxy, in_weakreflist),   /* long tp_weaklistoffset; */
00128 #else
00129         0,
00130 #endif
00131         0,0,
00132         Methods,
00133         0,
00134         0,
00135         NULL // no subtype
00136 };
00137 
00138 PyObject *PyObjectPlus::py_base_repr(PyObject *self)                    // This should be the entry in Type.
00139 {
00140         PyObjectPlus *self_plus= BGE_PROXY_REF(self);
00141         if(self_plus==NULL) {
00142                 PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
00143                 return NULL;
00144         }
00145         return self_plus->py_repr();  
00146 }
00147 
00148 
00149 PyObject * PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
00150 {
00151         PyTypeObject *base_type;
00152         PyObjectPlus_Proxy *base = NULL;
00153 
00154         if (!PyArg_ParseTuple(args, "O:Base PyObjectPlus", &base))
00155                 return NULL;
00156 
00157         /* the 'base' PyObject may be subclassed (multiple times even)
00158          * we need to find the first C++ defined class to check 'type'
00159          * is a subclass of the base arguments type.
00160          *
00161          * This way we can share one tp_new function for every PyObjectPlus
00162          *
00163          * eg.
00164          *
00165          * # CustomOb is called 'type' in this C code
00166          * class CustomOb(GameTypes.KX_GameObject):
00167          *     pass
00168          *
00169          * # this calls py_base_new(...), the type of 'CustomOb' is checked to be a subclass of the 'cont.owner' type
00170          * ob = CustomOb(cont.owner)
00171          *
00172          * */
00173         base_type= Py_TYPE(base);
00174         while(base_type && !BGE_PROXY_CHECK_TYPE(base_type))
00175                 base_type= base_type->tp_base;
00176 
00177         if(base_type==NULL || !BGE_PROXY_CHECK_TYPE(base_type)) {
00178                 PyErr_SetString(PyExc_TypeError, "can't subclass from a blender game type because the argument given is not a game class or subclass");
00179                 return NULL;
00180         }
00181 
00182         /* use base_type rather than Py_TYPE(base) because we could already be subtyped */
00183         if(!PyType_IsSubtype(type, base_type)) {
00184                 PyErr_Format(PyExc_TypeError, "can't subclass blender game type <%s> from <%s> because it is not a subclass", base_type->tp_name, type->tp_name);
00185                 return NULL;
00186         }
00187 
00188         /* invalidate the existing base and return a new subclassed one,
00189          * this is a bit dodgy in that it also attaches its self to the existing object
00190          * which is not really 'correct' python OO but for our use its OK. */
00191 
00192         PyObjectPlus_Proxy *ret = (PyObjectPlus_Proxy *) type->tp_alloc(type, 0); /* starts with 1 ref, used for the return ref' */
00193         ret->ref= base->ref;
00194         ret->ptr= base->ptr;
00195         ret->py_owns= base->py_owns;
00196         ret->py_ref = base->py_ref;
00197 
00198         if (ret->py_ref) {
00199                 base->ref= NULL;                /* invalidate! disallow further access */
00200                 base->ptr = NULL;
00201                 if (ret->ref)
00202                         ret->ref->m_proxy= NULL;
00203                 /* 'base' may be free'd after this func finished but not necessarily
00204                  * there is no reference to the BGE data now so it will throw an error on access */
00205                 Py_DECREF(base);
00206                 if (ret->ref) {
00207                         ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */
00208                         Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */
00209                 }
00210         } else {
00211                 // generic structures don't hold a reference to this proxy, so don't increment ref count
00212                 if (ret->py_owns)
00213                         // but if the proxy owns the structure, there can be only one owner
00214                         base->ptr= NULL;
00215         }
00216 
00217         return (PyObject *)ret;
00218 }
00219 
00223 void PyObjectPlus::py_base_dealloc(PyObject *self)                              // python wrapper
00224 {
00225 #ifdef USE_WEAKREFS
00226         if (BGE_PROXY_WKREF(self) != NULL)
00227                 PyObject_ClearWeakRefs((PyObject *) self);
00228 #endif
00229 
00230         if (BGE_PROXY_PYREF(self)) {
00231                 PyObjectPlus *self_plus= BGE_PROXY_REF(self);
00232                 if(self_plus) {
00233                         if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it  */
00234                                 self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */
00235                                 delete self_plus;
00236                         }
00237                         BGE_PROXY_REF(self)= NULL; // not really needed
00238                 }
00239                 // the generic pointer is not deleted directly, only through self_plus
00240                 BGE_PROXY_PTR(self)= NULL; // not really needed
00241         } else {
00242                 void *ptr= BGE_PROXY_PTR(self);
00243                 if(ptr) {
00244                         if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it  */
00245                                 // generic structure owned by python MUST be created though MEM_alloc
00246                                 MEM_freeN(ptr);
00247                         }
00248                         BGE_PROXY_PTR(self)= NULL; // not really needed
00249                 }
00250         }
00251 #if 0
00252         /* is ok normally but not for subtyping, use tp_free instead. */
00253         PyObject_DEL( self );
00254 #else
00255         Py_TYPE(self)->tp_free(self);
00256 #endif
00257 };
00258 
00259 /*------------------------------
00260  * PyObjectPlus Methods         -- Every class, even the abstract one should have a Methods
00261 ------------------------------*/
00262 PyMethodDef PyObjectPlus::Methods[] = {
00263   {NULL, NULL}          /* Sentinel */
00264 };
00265 
00266 #define attr_invalid (&(PyObjectPlus::Attributes[0]))
00267 PyAttributeDef PyObjectPlus::Attributes[] = {
00268         KX_PYATTRIBUTE_RO_FUNCTION("invalid",           PyObjectPlus, pyattr_get_invalid),
00269         {NULL} //Sentinel
00270 };
00271 
00272 
00273 
00274 PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00275 {
00276         return PyBool_FromLong(self_v ? 0:1);
00277 }
00278 
00279 /* note, this is called as a python 'getset, where the PyAttributeDef is the closure */
00280 PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef)
00281 {
00282         PyObjectPlus *ref= (BGE_PROXY_REF(self_py));
00283         char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref;
00284         if(ptr == NULL || (BGE_PROXY_PYREF(self_py) && (ref==NULL || !ref->py_is_valid()))) {
00285                 if(attrdef == attr_invalid)
00286                         Py_RETURN_TRUE; // dont bother running the function
00287 
00288                 PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
00289                 return NULL;
00290         }
00291 
00292         if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
00293         {
00294                 // fake attribute, ignore
00295                 return NULL;
00296         }
00297         if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION)
00298         {
00299                 // the attribute has no field correspondance, handover processing to function.
00300                 if (attrdef->m_getFunction == NULL)
00301                         return NULL;
00302                 return (*attrdef->m_getFunction)(ptr, attrdef);
00303         }
00304         ptr += attrdef->m_offset;
00305         if (attrdef->m_length > 1)
00306         {
00307                 PyObject* resultlist = PyList_New(attrdef->m_length);
00308                 for (unsigned int i=0; i<attrdef->m_length; i++)
00309                 {
00310                         switch (attrdef->m_type) {
00311                         case KX_PYATTRIBUTE_TYPE_BOOL:
00312                                 {
00313                                         bool *val = reinterpret_cast<bool*>(ptr);
00314                                         ptr += sizeof(bool);
00315                                         PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val));
00316                                         break;
00317                                 }
00318                         case KX_PYATTRIBUTE_TYPE_SHORT:
00319                                 {
00320                                         short int *val = reinterpret_cast<short int*>(ptr);
00321                                         ptr += sizeof(short int);
00322                                         PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val));
00323                                         break;
00324                                 }
00325                         case KX_PYATTRIBUTE_TYPE_ENUM:
00326                                 // enum are like int, just make sure the field size is the same
00327                                 if (sizeof(int) != attrdef->m_size)
00328                                 {
00329                                         Py_DECREF(resultlist);
00330                                         return NULL;
00331                                 }
00332                                 // walkthrough
00333                         case KX_PYATTRIBUTE_TYPE_INT:
00334                                 {
00335                                         int *val = reinterpret_cast<int*>(ptr);
00336                                         ptr += sizeof(int);
00337                                         PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val));
00338                                         break;
00339                                 }
00340                         case KX_PYATTRIBUTE_TYPE_FLOAT:
00341                                 {
00342                                         float *val = reinterpret_cast<float*>(ptr);
00343                                         ptr += sizeof(float);
00344                                         PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(*val));
00345                                         break;
00346                                 }
00347                         default:
00348                                 // no support for array of complex data
00349                                 Py_DECREF(resultlist);
00350                                 return NULL;
00351                         }
00352                 }
00353                 return resultlist;
00354         }
00355         else
00356         {
00357                 switch (attrdef->m_type) {
00358                 case KX_PYATTRIBUTE_TYPE_FLAG:
00359                         {
00360                                 bool bval;
00361                                 switch (attrdef->m_size) {
00362                                 case 1:
00363                                         {
00364                                                 unsigned char *val = reinterpret_cast<unsigned char*>(ptr);
00365                                                 bval = (*val & attrdef->m_imin);
00366                                                 break;
00367                                         }
00368                                 case 2:
00369                                         {
00370                                                 unsigned short *val = reinterpret_cast<unsigned short*>(ptr);
00371                                                 bval = (*val & attrdef->m_imin);
00372                                                 break;
00373                                         }
00374                                 case 4:
00375                                         {
00376                                                 unsigned int *val = reinterpret_cast<unsigned int*>(ptr);
00377                                                 bval = (*val & attrdef->m_imin);
00378                                                 break;
00379                                         }
00380                                 default:
00381                                         return NULL;
00382                                 }
00383                                 if (attrdef->m_imax)
00384                                         bval = !bval;
00385                                 return PyLong_FromSsize_t(bval);
00386                         }
00387                 case KX_PYATTRIBUTE_TYPE_BOOL:
00388                         {
00389                                 bool *val = reinterpret_cast<bool*>(ptr);
00390                                 return PyLong_FromSsize_t(*val);
00391                         }
00392                 case KX_PYATTRIBUTE_TYPE_SHORT:
00393                         {
00394                                 short int *val = reinterpret_cast<short int*>(ptr);
00395                                 return PyLong_FromSsize_t(*val);
00396                         }
00397                 case KX_PYATTRIBUTE_TYPE_ENUM:
00398                         // enum are like int, just make sure the field size is the same
00399                         if (sizeof(int) != attrdef->m_size)
00400                         {
00401                                 return NULL;
00402                         }
00403                         // walkthrough
00404                 case KX_PYATTRIBUTE_TYPE_INT:
00405                         {
00406                                 int *val = reinterpret_cast<int*>(ptr);
00407                                 return PyLong_FromSsize_t(*val);
00408                         }
00409                 case KX_PYATTRIBUTE_TYPE_FLOAT:
00410                         {
00411                                 float *val = reinterpret_cast<float*>(ptr);
00412                                 if (attrdef->m_imin == 0) {
00413                                         if (attrdef->m_imax == 0) {
00414                                                 return PyFloat_FromDouble(*val);
00415                                         } else {
00416                                                 // vector, verify size
00417                                                 if (attrdef->m_size != attrdef->m_imax*sizeof(float)) 
00418                                                 {
00419                                                         return NULL;
00420                                                 }
00421 #ifdef USE_MATHUTILS
00422                                                 return newVectorObject(val, attrdef->m_imax, Py_NEW, NULL);
00423 #else
00424                                                 PyObject* resultlist = PyList_New(attrdef->m_imax);
00425                                                 for (unsigned int i=0; i<attrdef->m_imax; i++)
00426                                                 {
00427                                                         PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(val[i]));
00428                                                 }
00429                                                 return resultlist;
00430 #endif
00431                                         }
00432                                 } else {
00433                                         // matrix case
00434                                         if (attrdef->m_size != attrdef->m_imax*attrdef->m_imin*sizeof(float)) 
00435                                         {
00436                                                 return NULL;
00437                                         }
00438 #ifdef USE_MATHUTILS
00439                                         return newMatrixObject(val, attrdef->m_imin, attrdef->m_imax, Py_WRAP, NULL);
00440 #else
00441                                         PyObject* collist = PyList_New(attrdef->m_imin);
00442                                         for (unsigned int i=0; i<attrdef->m_imin; i++)
00443                                         {
00444                                                 PyObject* col = PyList_New(attrdef->m_imax);
00445                                                 for (unsigned int j=0; j<attrdef->m_imax; j++)
00446                                                 {
00447                                                         PyList_SET_ITEM(col,j,PyFloat_FromDouble(val[j]));
00448                                                 }
00449                                                 PyList_SET_ITEM(collist,i,col);
00450                                                 val += attrdef->m_imax;
00451                                         }
00452                                         return collist;
00453 #endif
00454                                 }
00455                         }
00456                 case KX_PYATTRIBUTE_TYPE_VECTOR:
00457                         {
00458                                 MT_Vector3 *val = reinterpret_cast<MT_Vector3*>(ptr);
00459 #ifdef USE_MATHUTILS
00460                                 float fval[3]= {(*val)[0], (*val)[1], (*val)[2]};
00461                                 return newVectorObject(fval, 3, Py_NEW, NULL);
00462 #else
00463                                 PyObject* resultlist = PyList_New(3);
00464                                 for (unsigned int i=0; i<3; i++)
00465                                 {
00466                                         PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble((*val)[i]));
00467                                 }
00468                                 return resultlist;
00469 #endif
00470                         }
00471                 case KX_PYATTRIBUTE_TYPE_STRING:
00472                         {
00473                                 STR_String *val = reinterpret_cast<STR_String*>(ptr);
00474                                 return PyUnicode_FromString(*val);
00475                         }
00476                 case KX_PYATTRIBUTE_TYPE_CHAR:
00477                         {
00478                                 return PyUnicode_FromString(ptr);
00479                         }
00480                 default:
00481                         return NULL;
00482                 }
00483         }
00484 }
00485 
00486 
00487 static bool py_check_attr_float(float *var, PyObject *value, const PyAttributeDef *attrdef)
00488 {
00489         double val = PyFloat_AsDouble(value);
00490         if (val == -1.0 && PyErr_Occurred())
00491         {
00492                 PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name);
00493                 return false;
00494         }
00495         if (attrdef->m_clamp)
00496         {
00497                 if (val < attrdef->m_fmin)
00498                         val = attrdef->m_fmin;
00499                 else if (val > attrdef->m_fmax)
00500                         val = attrdef->m_fmax;
00501         }
00502         else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
00503         {
00504                 PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
00505                 return false;
00506         }
00507         *var = (float)val;
00508         return true;
00509 }
00510 
00511 /* note, this is called as a python getset */
00512 int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef)
00513 {
00514         PyObjectPlus *ref= (BGE_PROXY_REF(self_py));
00515         char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref;
00516         if(ref==NULL || !ref->py_is_valid() || ptr==NULL) {
00517                 PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
00518                 return PY_SET_ATTR_FAIL;
00519         }
00520 
00521         void *undoBuffer = NULL;
00522         void *sourceBuffer = NULL;
00523         size_t bufferSize = 0;
00524         PyObject *item = NULL;  // to store object that must be dereferenced in case of error
00525         PyObject *list = NULL;  // to store object that must be dereferenced in case of error
00526         
00527         ptr += attrdef->m_offset;
00528         if (attrdef->m_length > 1)
00529         {
00530                 if (!PySequence_Check(value)) 
00531                 {
00532                         PyErr_Format(PyExc_TypeError, "expected a sequence for attribute \"%s\"", attrdef->m_name);
00533                         return PY_SET_ATTR_FAIL;
00534                 }
00535                 if (PySequence_Size(value) != attrdef->m_length)
00536                 {
00537                         PyErr_Format(PyExc_TypeError, "incorrect number of elements in sequence for attribute \"%s\"", attrdef->m_name);
00538                         return PY_SET_ATTR_FAIL;
00539                 }
00540                 switch (attrdef->m_type) 
00541                 {
00542                 case KX_PYATTRIBUTE_TYPE_FUNCTION:
00543                         if (attrdef->m_setFunction == NULL) 
00544                         {
00545                                 PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name);
00546                                 return PY_SET_ATTR_FAIL;
00547                         }
00548                         return (*attrdef->m_setFunction)(ref, attrdef, value);
00549                 case KX_PYATTRIBUTE_TYPE_BOOL:
00550                         bufferSize = sizeof(bool);
00551                         break;
00552                 case KX_PYATTRIBUTE_TYPE_SHORT:
00553                         bufferSize = sizeof(short int);
00554                         break;
00555                 case KX_PYATTRIBUTE_TYPE_ENUM:
00556                 case KX_PYATTRIBUTE_TYPE_INT:
00557                         bufferSize = sizeof(int);
00558                         break;
00559                 case KX_PYATTRIBUTE_TYPE_FLOAT:
00560                         bufferSize = sizeof(float);
00561                         break;
00562                 default:
00563                         // should not happen
00564                         PyErr_Format(PyExc_AttributeError, "Unsupported attribute type for attribute \"%s\", report to blender.org", attrdef->m_name);
00565                         return PY_SET_ATTR_FAIL;
00566                 }
00567                 // let's implement a smart undo method
00568                 bufferSize *= attrdef->m_length;
00569                 undoBuffer = malloc(bufferSize);
00570                 sourceBuffer = ptr;
00571                 if (undoBuffer)
00572                 {
00573                         memcpy(undoBuffer, sourceBuffer, bufferSize);
00574                 }
00575                 for (int i=0; i<attrdef->m_length; i++)
00576                 {
00577                         item = PySequence_GetItem(value, i); /* new ref */
00578                         switch (attrdef->m_type) 
00579                         {
00580                         case KX_PYATTRIBUTE_TYPE_BOOL:
00581                                 {
00582                                         bool *var = reinterpret_cast<bool*>(ptr);
00583                                         ptr += sizeof(bool);
00584                                         if (PyLong_Check(item)) 
00585                                         {
00586                                                 *var = (PyLong_AsSsize_t(item) != 0);
00587                                         } 
00588                                         else if (PyBool_Check(item))
00589                                         {
00590                                                 *var = (item == Py_True);
00591                                         }
00592                                         else
00593                                         {
00594                                                 PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name);
00595                                                 goto UNDO_AND_ERROR;
00596                                         }
00597                                         break;
00598                                 }
00599                         case KX_PYATTRIBUTE_TYPE_SHORT:
00600                                 {
00601                                         short int *var = reinterpret_cast<short int*>(ptr);
00602                                         ptr += sizeof(short int);
00603                                         if (PyLong_Check(item)) 
00604                                         {
00605                                                 long val = PyLong_AsSsize_t(item);
00606                                                 if (attrdef->m_clamp)
00607                                                 {
00608                                                         if (val < attrdef->m_imin)
00609                                                                 val = attrdef->m_imin;
00610                                                         else if (val > attrdef->m_imax)
00611                                                                 val = attrdef->m_imax;
00612                                                 }
00613                                                 else if (val < attrdef->m_imin || val > attrdef->m_imax)
00614                                                 {
00615                                                         PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name);
00616                                                         goto UNDO_AND_ERROR;
00617                                                 }
00618                                                 *var = (short int)val;
00619                                         }
00620                                         else
00621                                         {
00622                                                 PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00623                                                 goto UNDO_AND_ERROR;
00624                                         }
00625                                         break;
00626                                 }
00627                         case KX_PYATTRIBUTE_TYPE_ENUM:
00628                                 // enum are equivalent to int, just make sure that the field size matches:
00629                                 if (sizeof(int) != attrdef->m_size)
00630                                 {
00631                                         PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name);
00632                                         goto UNDO_AND_ERROR;
00633                                 }
00634                                 // walkthrough
00635                         case KX_PYATTRIBUTE_TYPE_INT:
00636                                 {
00637                                         int *var = reinterpret_cast<int*>(ptr);
00638                                         ptr += sizeof(int);
00639                                         if (PyLong_Check(item)) 
00640                                         {
00641                                                 long val = PyLong_AsSsize_t(item);
00642                                                 if (attrdef->m_clamp)
00643                                                 {
00644                                                         if (val < attrdef->m_imin)
00645                                                                 val = attrdef->m_imin;
00646                                                         else if (val > attrdef->m_imax)
00647                                                                 val = attrdef->m_imax;
00648                                                 }
00649                                                 else if (val < attrdef->m_imin || val > attrdef->m_imax)
00650                                                 {
00651                                                         PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name);
00652                                                         goto UNDO_AND_ERROR;
00653                                                 }
00654                                                 *var = (int)val;
00655                                         }
00656                                         else
00657                                         {
00658                                                 PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00659                                                 goto UNDO_AND_ERROR;
00660                                         }
00661                                         break;
00662                                 }
00663                         case KX_PYATTRIBUTE_TYPE_FLOAT:
00664                                 {
00665                                         float *var = reinterpret_cast<float*>(ptr);
00666                                         ptr += sizeof(float);
00667                                         double val = PyFloat_AsDouble(item);
00668                                         if (val == -1.0 && PyErr_Occurred())
00669                                         {
00670                                                 PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name);
00671                                                 goto UNDO_AND_ERROR;
00672                                         }
00673                                         else if (attrdef->m_clamp) 
00674                                         {
00675                                                 if (val < attrdef->m_fmin)
00676                                                         val = attrdef->m_fmin;
00677                                                 else if (val > attrdef->m_fmax)
00678                                                         val = attrdef->m_fmax;
00679                                         }
00680                                         else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
00681                                         {
00682                                                 PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name);
00683                                                 goto UNDO_AND_ERROR;
00684                                         }
00685                                         *var = (float)val;
00686                                         break;
00687                                 }
00688                         default:
00689                                 // should not happen
00690                                 PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name);
00691                                 goto UNDO_AND_ERROR;
00692                         }
00693                         // finished using item, release
00694                         Py_DECREF(item);
00695                         item = NULL;
00696                 }
00697                 // no error, call check function if any
00698                 if (attrdef->m_checkFunction != NULL)
00699                 {
00700                         if ((*attrdef->m_checkFunction)(ref, attrdef) != 0)
00701                         {
00702                                 // if the checing function didnt set an error then set a generic one here so we dont set an error with no exception
00703                                 if (PyErr_Occurred()==0)
00704                                         PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", reasion unknown", attrdef->m_name);
00705                                 
00706                                 // post check returned an error, restore values
00707                         UNDO_AND_ERROR:
00708                                 if (undoBuffer)
00709                                 {
00710                                         memcpy(sourceBuffer, undoBuffer, bufferSize);
00711                                         free(undoBuffer);
00712                                 }
00713                                 if (item)
00714                                         Py_DECREF(item);
00715                                 return PY_SET_ATTR_FAIL;
00716                         }
00717                 }
00718                 if (undoBuffer)
00719                         free(undoBuffer);
00720                 return PY_SET_ATTR_SUCCESS;
00721         }
00722         else    // simple attribute value
00723         {
00724                 if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION)
00725                 {
00726                         if (attrdef->m_setFunction == NULL)
00727                         {
00728                                 PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name);
00729                                 return PY_SET_ATTR_FAIL;
00730                         }
00731                         return (*attrdef->m_setFunction)(ref, attrdef, value);
00732                 }
00733                 if (attrdef->m_checkFunction != NULL || attrdef->m_type == KX_PYATTRIBUTE_TYPE_VECTOR)
00734                 {
00735                         // post check function is provided, prepare undo buffer
00736                         sourceBuffer = ptr;
00737                         switch (attrdef->m_type) 
00738                         {
00739                         case KX_PYATTRIBUTE_TYPE_BOOL:
00740                                 bufferSize = sizeof(bool);
00741                                 break;
00742                         case KX_PYATTRIBUTE_TYPE_SHORT:
00743                                 bufferSize = sizeof(short);
00744                                 break;
00745                         case KX_PYATTRIBUTE_TYPE_ENUM:
00746                         case KX_PYATTRIBUTE_TYPE_FLAG:
00747                         case KX_PYATTRIBUTE_TYPE_CHAR:
00748                                 bufferSize = attrdef->m_size;
00749                                 break;
00750                         case KX_PYATTRIBUTE_TYPE_INT:
00751                                 bufferSize = sizeof(int);
00752                                 break;
00753                         case KX_PYATTRIBUTE_TYPE_FLOAT:
00754                                 bufferSize = sizeof(float);
00755                                 if (attrdef->m_imax)
00756                                         bufferSize *= attrdef->m_imax;
00757                                 if (attrdef->m_imin)
00758                                         bufferSize *= attrdef->m_imin;
00759                                 break;
00760                         case KX_PYATTRIBUTE_TYPE_STRING:
00761                                 sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr();
00762                                 if (sourceBuffer)
00763                                         bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1;
00764                                 break;
00765                         case KX_PYATTRIBUTE_TYPE_VECTOR:
00766                                 bufferSize = sizeof(MT_Vector3);
00767                                 break;
00768                         default:
00769                                 PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name);
00770                                 return PY_SET_ATTR_FAIL;
00771                         }
00772                         if (bufferSize)
00773                         {
00774                                 undoBuffer = malloc(bufferSize);
00775                                 if (undoBuffer)
00776                                 {
00777                                         memcpy(undoBuffer, sourceBuffer, bufferSize);
00778                                 }
00779                         }
00780                 }
00781                         
00782                 switch (attrdef->m_type) 
00783                 {
00784                 case KX_PYATTRIBUTE_TYPE_BOOL:
00785                         {
00786                                 bool *var = reinterpret_cast<bool*>(ptr);
00787                                 if (PyLong_Check(value)) 
00788                                 {
00789                                         *var = (PyLong_AsSsize_t(value) != 0);
00790                                 } 
00791                                 else if (PyBool_Check(value))
00792                                 {
00793                                         *var = (value == Py_True);
00794                                 }
00795                                 else
00796                                 {
00797                                         PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name);
00798                                         goto FREE_AND_ERROR;
00799                                 }
00800                                 break;
00801                         }
00802                 case KX_PYATTRIBUTE_TYPE_FLAG:
00803                         {
00804                                 bool bval;
00805                                 if (PyLong_Check(value)) 
00806                                 {
00807                                         bval = (PyLong_AsSsize_t(value) != 0);
00808                                 } 
00809                                 else if (PyBool_Check(value))
00810                                 {
00811                                         bval = (value == Py_True);
00812                                 }
00813                                 else
00814                                 {
00815                                         PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name);
00816                                         goto FREE_AND_ERROR;
00817                                 }
00818                                 if (attrdef->m_imax)
00819                                         bval = !bval;
00820                                 switch (attrdef->m_size) {
00821                                 case 1:
00822                                         {
00823                                                 unsigned char *val = reinterpret_cast<unsigned char*>(ptr);
00824                                                 *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0);
00825                                                 break;
00826                                         }
00827                                 case 2:
00828                                         {
00829                                                 unsigned short *val = reinterpret_cast<unsigned short*>(ptr);
00830                                                 *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0);
00831                                                 break;
00832                                         }
00833                                 case 4:
00834                                         {
00835                                                 unsigned int *val = reinterpret_cast<unsigned int*>(ptr);
00836                                                 *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0);
00837                                                 break;
00838                                         }
00839                                 default:
00840                                         PyErr_Format(PyExc_TypeError, "internal error: unsupported flag field \"%s\"", attrdef->m_name);
00841                                         goto FREE_AND_ERROR;
00842                                 }
00843                                 break;
00844                         }
00845                 case KX_PYATTRIBUTE_TYPE_SHORT:
00846                         {
00847                                 short int *var = reinterpret_cast<short int*>(ptr);
00848                                 if (PyLong_Check(value)) 
00849                                 {
00850                                         long val = PyLong_AsSsize_t(value);
00851                                         if (attrdef->m_clamp)
00852                                         {
00853                                                 if (val < attrdef->m_imin)
00854                                                         val = attrdef->m_imin;
00855                                                 else if (val > attrdef->m_imax)
00856                                                         val = attrdef->m_imax;
00857                                         }
00858                                         else if (val < attrdef->m_imin || val > attrdef->m_imax)
00859                                         {
00860                                                 PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
00861                                                 goto FREE_AND_ERROR;
00862                                         }
00863                                         *var = (short int)val;
00864                                 }
00865                                 else
00866                                 {
00867                                         PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00868                                         goto FREE_AND_ERROR;
00869                                 }
00870                                 break;
00871                         }
00872                 case KX_PYATTRIBUTE_TYPE_ENUM:
00873                         // enum are equivalent to int, just make sure that the field size matches:
00874                         if (sizeof(int) != attrdef->m_size)
00875                         {
00876                                 PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name);
00877                                 goto FREE_AND_ERROR;
00878                         }
00879                         // walkthrough
00880                 case KX_PYATTRIBUTE_TYPE_INT:
00881                         {
00882                                 int *var = reinterpret_cast<int*>(ptr);
00883                                 if (PyLong_Check(value)) 
00884                                 {
00885                                         long val = PyLong_AsSsize_t(value);
00886                                         if (attrdef->m_clamp)
00887                                         {
00888                                                 if (val < attrdef->m_imin)
00889                                                         val = attrdef->m_imin;
00890                                                 else if (val > attrdef->m_imax)
00891                                                         val = attrdef->m_imax;
00892                                         }
00893                                         else if (val < attrdef->m_imin || val > attrdef->m_imax)
00894                                         {
00895                                                 PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
00896                                                 goto FREE_AND_ERROR;
00897                                         }
00898                                         *var = (int)val;
00899                                 }
00900                                 else
00901                                 {
00902                                         PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00903                                         goto FREE_AND_ERROR;
00904                                 }
00905                                 break;
00906                         }
00907                 case KX_PYATTRIBUTE_TYPE_FLOAT:
00908                         {
00909                                 float *var = reinterpret_cast<float*>(ptr);
00910                                 if (attrdef->m_imin != 0) 
00911                                 {
00912                                         if (attrdef->m_size != attrdef->m_imin*attrdef->m_imax*sizeof(float)) 
00913                                         {
00914                                                 PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name);
00915                                                 goto FREE_AND_ERROR;
00916                                         }
00917                                         if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imin) 
00918                                         {
00919                                                 PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name);
00920                                                 goto FREE_AND_ERROR;
00921                                         }
00922                                         for (int i=0; i<attrdef->m_imin; i++)
00923                                         {
00924                                                 PyObject *list = PySequence_GetItem(value, i); /* new ref */
00925                                                 if (!PySequence_Check(list) || PySequence_Size(list) != attrdef->m_imax) 
00926                                                 {
00927                                                         PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name);
00928                                                         goto RESTORE_AND_ERROR;
00929                                                 }
00930                                                 for (int j=0; j<attrdef->m_imax; j++)
00931                                                 {
00932                                                         item = PySequence_GetItem(list, j); /* new ref */
00933                                                         if (!py_check_attr_float(var, item, attrdef))
00934                                                         {
00935                                                                 PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name);
00936                                                                 goto RESTORE_AND_ERROR;
00937                                                         }
00938                                                         Py_DECREF(item);
00939                                                         item = NULL;
00940                                                         ++var;
00941                                                 }
00942                                                 Py_DECREF(list);
00943                                                 list = NULL;
00944                                         }
00945                                 } 
00946                                 else if (attrdef->m_imax != 0) 
00947                                 {
00948                                         if (attrdef->m_size != attrdef->m_imax*sizeof(float)) 
00949                                         {
00950                                                 PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name);
00951                                                 goto FREE_AND_ERROR;
00952                                         }
00953                                         if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imax) 
00954                                         {
00955                                                 PyErr_Format(PyExc_TypeError, "expected a sequence of [%d] floats for attribute \"%s\"", attrdef->m_imax, attrdef->m_name);
00956                                                 goto FREE_AND_ERROR;
00957                                         }
00958                                         for (int i=0; i<attrdef->m_imax; i++)
00959                                         {
00960                                                 item = PySequence_GetItem(value, i); /* new ref */
00961                                                 if (!py_check_attr_float(var, item, attrdef))
00962                                                 {
00963                                                         goto RESTORE_AND_ERROR;
00964                                                 }
00965                                                 Py_DECREF(item);
00966                                                 item = NULL;
00967                                                 ++var;
00968                                         }
00969                                 } 
00970                                 else
00971                                 {
00972                                         if (!py_check_attr_float(var, value, attrdef))
00973                                                 goto FREE_AND_ERROR;
00974                                 }
00975                                 break;
00976                         }
00977                 case KX_PYATTRIBUTE_TYPE_VECTOR:
00978                         {
00979                                 if (!PySequence_Check(value) || PySequence_Size(value) != 3) 
00980                                 {
00981                                         PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name);
00982                                         goto FREE_AND_ERROR;
00983                                 }
00984                                 MT_Vector3 *var = reinterpret_cast<MT_Vector3*>(ptr);
00985                                 for (int i=0; i<3; i++)
00986                                 {
00987                                         item = PySequence_GetItem(value, i); /* new ref */
00988                                         double val = PyFloat_AsDouble(item);
00989                                         Py_DECREF(item);
00990                                         item = NULL;
00991                                         if (val == -1.0 && PyErr_Occurred())
00992                                         {
00993                                                 PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name);
00994                                                 goto RESTORE_AND_ERROR;
00995                                         }
00996                                         else if (attrdef->m_clamp)
00997                                         {
00998                                                 if (val < attrdef->m_fmin)
00999                                                         val = attrdef->m_fmin;
01000                                                 else if (val > attrdef->m_fmax)
01001                                                         val = attrdef->m_fmax;
01002                                         }
01003                                         else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
01004                                         {
01005                                                 PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
01006                                                 goto RESTORE_AND_ERROR;
01007                                         }
01008                                         (*var)[i] = (MT_Scalar)val;
01009                                 }
01010                                 break;
01011                         }
01012                 case KX_PYATTRIBUTE_TYPE_CHAR:
01013                         {
01014                                 if (PyUnicode_Check(value)) 
01015                                 {
01016                                         Py_ssize_t val_len;
01017                                         char *val = _PyUnicode_AsStringAndSize(value, &val_len);
01018                                         strncpy(ptr, val, attrdef->m_size);
01019                                         ptr[attrdef->m_size-1] = 0;
01020                                 }
01021                                 else
01022                                 {
01023                                         PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name);
01024                                         goto FREE_AND_ERROR;
01025                                 }
01026                                 break;
01027                         }
01028                 case KX_PYATTRIBUTE_TYPE_STRING:
01029                         {
01030                                 STR_String *var = reinterpret_cast<STR_String*>(ptr);
01031                                 if (PyUnicode_Check(value)) 
01032                                 {
01033                                         Py_ssize_t val_len;
01034                                         char *val = _PyUnicode_AsStringAndSize(value, &val_len);
01035                                         if (attrdef->m_clamp)
01036                                         {
01037                                                 if (val_len < attrdef->m_imin)
01038                                                 {
01039                                                         // can't increase the length of the string
01040                                                         PyErr_Format(PyExc_ValueError, "string length too short for attribute \"%s\"", attrdef->m_name);
01041                                                         goto FREE_AND_ERROR;
01042                                                 }
01043                                                 else if (val_len > attrdef->m_imax)
01044                                                 {
01045                                                         // trim the string
01046                                                         char c = val[attrdef->m_imax];
01047                                                         val[attrdef->m_imax] = 0;
01048                                                         *var = val;
01049                                                         val[attrdef->m_imax] = c;
01050                                                         break;
01051                                                 }
01052                                         } else if (val_len < attrdef->m_imin || val_len > attrdef->m_imax)
01053                                         {
01054                                                 PyErr_Format(PyExc_ValueError, "string length out of range for attribute \"%s\"", attrdef->m_name);
01055                                                 goto FREE_AND_ERROR;
01056                                         }
01057                                         *var = val;
01058                                 }
01059                                 else
01060                                 {
01061                                         PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name);
01062                                         goto FREE_AND_ERROR;
01063                                 }
01064                                 break;
01065                         }
01066                 default:
01067                         // should not happen
01068                         PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name);
01069                         goto FREE_AND_ERROR;
01070                 }
01071         }
01072         // check if post processing is needed
01073         if (attrdef->m_checkFunction != NULL)
01074         {
01075                 if ((*attrdef->m_checkFunction)(ref, attrdef) != 0)
01076                 {
01077                         // restore value
01078                 RESTORE_AND_ERROR:
01079                         if (undoBuffer)
01080                         {
01081                                 if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING)
01082                                 {
01083                                         // special case for STR_String: restore the string
01084                                         STR_String *var = reinterpret_cast<STR_String*>(ptr);
01085                                         *var = reinterpret_cast<char*>(undoBuffer);
01086                                 }
01087                                 else
01088                                 {
01089                                         // other field type have direct values
01090                                         memcpy(ptr, undoBuffer, bufferSize);
01091                                 }
01092                         }
01093                 FREE_AND_ERROR:
01094                         if (undoBuffer)
01095                                 free(undoBuffer);
01096                         if (list)
01097                                 Py_DECREF(list);
01098                         if (item)
01099                                 Py_DECREF(item);
01100                         return 1;
01101                 }
01102         }
01103         if (undoBuffer)
01104                 free(undoBuffer);
01105         return 0;       
01106 }
01107 
01108 
01109 
01110 /*------------------------------
01111  * PyObjectPlus repr            -- representations
01112 ------------------------------*/
01113 PyObject *PyObjectPlus::py_repr(void)
01114 {
01115         PyErr_SetString(PyExc_SystemError, "Representation not overridden by object.");  
01116         return NULL;
01117 }
01118 
01119 PyObject *PyObjectPlus::GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr)
01120 {
01121         if (self->m_proxy==NULL)
01122         {
01123                 self->m_proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp);
01124                 BGE_PROXY_PYOWNS(self->m_proxy) = false;
01125                 BGE_PROXY_PYREF(self->m_proxy) = true;
01126 #ifdef USE_WEAKREFS
01127                 BGE_PROXY_WKREF(self->m_proxy) = NULL;
01128 #endif
01129         }
01130         //PyObject_Print(self->m_proxy, stdout, 0);
01131         //printf("ref %d\n", self->m_proxy->ob_refcnt);
01132         
01133         BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */
01134         BGE_PROXY_PTR(self->m_proxy) = ptr;
01135         Py_INCREF(self->m_proxy); /* we own one, thos ones fore the return */
01136         return self->m_proxy;
01137 }
01138 
01139 PyObject *PyObjectPlus::NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns)
01140 {
01141         if (!self) 
01142         {
01143                 // in case of proxy without reference to game object
01144                 PyObject* proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp);
01145                 BGE_PROXY_PYREF(proxy) = false;
01146                 BGE_PROXY_PYOWNS(proxy) = py_owns;
01147                 BGE_PROXY_REF(proxy) = NULL; 
01148                 BGE_PROXY_PTR(proxy) = ptr;
01149 #ifdef USE_WEAKREFS
01150                 BGE_PROXY_WKREF(proxy) = NULL;
01151 #endif
01152                 return proxy;
01153         }
01154         if (self->m_proxy)
01155         {
01156                 if(py_owns)
01157                 {       /* Free */
01158                         BGE_PROXY_REF(self->m_proxy) = NULL;
01159                         Py_DECREF(self->m_proxy);
01160                         self->m_proxy= NULL;
01161                 }
01162                 else {
01163                         Py_INCREF(self->m_proxy);
01164                         return self->m_proxy;
01165                 }
01166                 
01167         }
01168         
01169         GetProxyPlus_Ext(self, tp, ptr);
01170         if(py_owns) {
01171                 BGE_PROXY_PYOWNS(self->m_proxy) = py_owns;
01172                 Py_DECREF(self->m_proxy); /* could avoid thrashing here but for now its ok */
01173         }
01174         return self->m_proxy;
01175 }
01176 
01179 /* deprecation warning management */
01180 
01181 bool PyObjectPlus::m_ignore_deprecation_warnings(false);
01182 void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings)
01183 {
01184         m_ignore_deprecation_warnings = ignoreDeprecationWarnings;
01185 }
01186 
01187 void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* new_way)
01188 {
01189         printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way);
01190         PyC_LineSpit();
01191 }
01192 
01193 void PyObjectPlus::ClearDeprecationWarning()
01194 {
01195         WarnLink *wlink_next;
01196         WarnLink *wlink = GetDeprecationWarningLinkFirst();
01197         
01198         while(wlink)
01199         {
01200                 wlink->warn_done= false; /* no need to NULL the link, its cleared before adding to the list next time round */
01201                 wlink_next= reinterpret_cast<WarnLink *>(wlink->link);
01202                 wlink->link= NULL;
01203                 wlink= wlink_next;
01204         }
01205         NullDeprecationWarning();
01206 }
01207 
01208 WarnLink*               m_base_wlink_first= NULL;
01209 WarnLink*               m_base_wlink_last= NULL;
01210 
01211 WarnLink*               PyObjectPlus::GetDeprecationWarningLinkFirst(void) {return m_base_wlink_first;}
01212 WarnLink*               PyObjectPlus::GetDeprecationWarningLinkLast(void) {return m_base_wlink_last;}
01213 void                    PyObjectPlus::SetDeprecationWarningFirst(WarnLink* wlink) {m_base_wlink_first= wlink;}
01214 void                    PyObjectPlus::SetDeprecationWarningLinkLast(WarnLink* wlink) {m_base_wlink_last= wlink;}
01215 void                    PyObjectPlus::NullDeprecationWarning() {m_base_wlink_first= m_base_wlink_last= NULL;}
01216 
01217 #endif // WITH_PYTHON