|
Blender
V2.59
|
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