[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [18203] trunk/blender/source/gameengine: BGE API cleanup: introduction of a generic framework to link Python attributes to logic brick class member .

Benoit Bolsee benoit.bolsee at online.be
Wed Dec 31 21:35:23 CET 2008


Revision: 18203
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=18203
Author:   ben2610
Date:     2008-12-31 21:35:20 +0100 (Wed, 31 Dec 2008)

Log Message:
-----------
BGE API cleanup: introduction of a generic framework to link Python attributes to logic brick class member. See KX_PYATTRIBUTE macros in PyObjectPlus.h.

Modified Paths:
--------------
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.h
    trunk/blender/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_JoystickSensor.h
    trunk/blender/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_MouseSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_MouseSensor.h

Modified: trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
===================================================================
--- trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp	2008-12-31 18:52:15 UTC (rev 18202)
+++ trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp	2008-12-31 20:35:20 UTC (rev 18203)
@@ -131,6 +131,449 @@
 	return 1;
 }
 
+PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr)
+{
+	const PyAttributeDef *attrdef;
+	for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
+	{
+		if (attr == attrdef->m_name) 
+		{
+			if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
+			{
+				// fake attribute, ignore
+				return NULL;
+			}
+			char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
+			if (attrdef->m_length > 1)
+			{
+				PyObject* resultlist = PyList_New(attrdef->m_length);
+				for (int i=0; i<attrdef->m_length; i++)
+				{
+					switch (attrdef->m_type) {
+					case KX_PYATTRIBUTE_TYPE_BOOL:
+						{
+							bool *val = reinterpret_cast<bool*>(ptr);
+							ptr += sizeof(bool);
+							PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
+							break;
+						}
+					case KX_PYATTRIBUTE_TYPE_SHORT:
+						{
+							short int *val = reinterpret_cast<short int*>(ptr);
+							ptr += sizeof(short int);
+							PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
+							break;
+						}
+					case KX_PYATTRIBUTE_TYPE_INT:
+						{
+							int *val = reinterpret_cast<int*>(ptr);
+							ptr += sizeof(int);
+							PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
+							break;
+						}
+					case KX_PYATTRIBUTE_TYPE_FLOAT:
+						{
+							float *val = reinterpret_cast<float*>(ptr);
+							ptr += sizeof(float);
+							PyList_SetItem(resultlist,i,PyFloat_FromDouble(*val));
+							break;
+						}
+					default:
+						// no support for array of complex data
+						return NULL;
+					}
+				}
+				return resultlist;
+			}
+			else
+			{
+				switch (attrdef->m_type) {
+				case KX_PYATTRIBUTE_TYPE_BOOL:
+					{
+						bool *val = reinterpret_cast<bool*>(ptr);
+						return PyInt_FromLong(*val);
+					}
+				case KX_PYATTRIBUTE_TYPE_SHORT:
+					{
+						short int *val = reinterpret_cast<short int*>(ptr);
+						return PyInt_FromLong(*val);
+					}
+				case KX_PYATTRIBUTE_TYPE_INT:
+					{
+						int *val = reinterpret_cast<int*>(ptr);
+						return PyInt_FromLong(*val);
+					}
+				case KX_PYATTRIBUTE_TYPE_FLOAT:
+					{
+						float *val = reinterpret_cast<float*>(ptr);
+						return PyFloat_FromDouble(*val);
+					}
+				case KX_PYATTRIBUTE_TYPE_STRING:
+					{
+						STR_String *val = reinterpret_cast<STR_String*>(ptr);
+						return PyString_FromString(*val);
+					}
+				default:
+					return NULL;
+				}
+			}
+		}
+	}
+	return NULL;
+}
+
+int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr, PyObject *value)
+{
+	const PyAttributeDef *attrdef;
+	void *undoBuffer = NULL;
+	void *sourceBuffer = NULL;
+	size_t bufferSize = 0;
+
+	for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
+	{
+		if (attr == attrdef->m_name) 
+		{
+			if (attrdef->m_access == KX_PYATTRIBUTE_RO ||
+				attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
+			{
+				PyErr_SetString(PyExc_AttributeError, "property is read-only");
+				return 1;
+			}
+			char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
+			if (attrdef->m_length > 1)
+			{
+				if (!PySequence_Check(value)) 
+				{
+					PyErr_SetString(PyExc_TypeError, "expected a sequence");
+					return 1;
+				}
+				if (PySequence_Size(value) != attrdef->m_length)
+				{
+					PyErr_SetString(PyExc_TypeError, "incorrect number of elements in sequence");
+					return 1;
+				}
+				switch (attrdef->m_type) 
+				{
+				case KX_PYATTRIBUTE_TYPE_BOOL:
+					bufferSize = sizeof(bool);
+					break;
+				case KX_PYATTRIBUTE_TYPE_SHORT:
+					bufferSize = sizeof(short int);
+					break;
+				case KX_PYATTRIBUTE_TYPE_INT:
+					bufferSize = sizeof(int);
+					break;
+				case KX_PYATTRIBUTE_TYPE_FLOAT:
+					bufferSize = sizeof(float);
+					break;
+				default:
+					// should not happen
+					PyErr_SetString(PyExc_AttributeError, "Unsupported attribute type, report to blender.org");
+					return 1;
+				}
+				// let's implement a smart undo method
+				bufferSize *= attrdef->m_length;
+				undoBuffer = malloc(bufferSize);
+				sourceBuffer = ptr;
+				if (undoBuffer)
+				{
+					memcpy(undoBuffer, sourceBuffer, bufferSize);
+				}
+				for (int i=0; i<attrdef->m_length; i++)
+				{
+					PyObject *item = PySequence_GetItem(value, i); /* new ref */
+					// we can decrement the reference immediately, the reference count
+					// is at least 1 because the item is part of an array
+					Py_DECREF(item);
+					switch (attrdef->m_type) 
+					{
+					case KX_PYATTRIBUTE_TYPE_BOOL:
+						{
+							bool *var = reinterpret_cast<bool*>(ptr);
+							ptr += sizeof(bool);
+							if (PyInt_Check(item)) 
+							{
+								*var = (PyInt_AsLong(item) != 0);
+							} 
+							else if (PyBool_Check(item))
+							{
+								*var = (item == Py_True);
+							}
+							else
+							{
+								PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
+								goto UNDO_AND_ERROR;
+							}
+							break;
+						}
+					case KX_PYATTRIBUTE_TYPE_SHORT:
+						{
+							short int *var = reinterpret_cast<short int*>(ptr);
+							ptr += sizeof(short int);
+							if (PyInt_Check(item)) 
+							{
+								long val = PyInt_AsLong(item);
+								if (val < attrdef->m_imin || val > attrdef->m_imax)
+								{
+									PyErr_SetString(PyExc_ValueError, "item value out of range");
+									goto UNDO_AND_ERROR;
+								}
+								*var = (short int)val;
+							}
+							else
+							{
+								PyErr_SetString(PyExc_TypeError, "expected an integer");
+								goto UNDO_AND_ERROR;
+							}
+							break;
+						}
+					case KX_PYATTRIBUTE_TYPE_INT:
+						{
+							int *var = reinterpret_cast<int*>(ptr);
+							ptr += sizeof(int);
+							if (PyInt_Check(item)) 
+							{
+								long val = PyInt_AsLong(item);
+								if (val < attrdef->m_imin || val > attrdef->m_imax)
+								{
+									PyErr_SetString(PyExc_ValueError, "item value out of range");
+									goto UNDO_AND_ERROR;
+								}
+								*var = (int)val;
+							}
+							else
+							{
+								PyErr_SetString(PyExc_TypeError, "expected an integer");
+								goto UNDO_AND_ERROR;
+							}
+							break;
+						}
+					case KX_PYATTRIBUTE_TYPE_FLOAT:
+						{
+							float *var = reinterpret_cast<float*>(ptr);
+							ptr += sizeof(float);
+							if (PyFloat_Check(item)) 
+							{
+								double val = PyFloat_AsDouble(item);
+								if (val < attrdef->m_fmin || val > attrdef->m_fmax)
+								{
+									PyErr_SetString(PyExc_ValueError, "item value out of range");
+									goto UNDO_AND_ERROR;
+								}
+								*var = (float)val;
+							}
+							else
+							{
+								PyErr_SetString(PyExc_TypeError, "expected a float");
+								goto UNDO_AND_ERROR;
+							}
+							break;
+						}
+					default:
+						// should not happen
+						PyErr_SetString(PyExc_AttributeError, "attribute type check error, report to blender.org");
+						goto UNDO_AND_ERROR;
+					}
+				}
+				// no error, call check function if any
+				if (attrdef->m_function != NULL)
+				{
+					if ((*attrdef->m_function)(self) != 0)
+					{
+						// post check returned an error, restore values
+					UNDO_AND_ERROR:
+						if (undoBuffer)
+						{
+							memcpy(sourceBuffer, undoBuffer, bufferSize);
+							free(undoBuffer);
+						}
+						return 1;
+					}
+				}
+				if (undoBuffer)
+					free(undoBuffer);
+				return 0;
+			}
+			else	// simple attribute value
+			{
+
+				if (attrdef->m_function != NULL)
+				{
+					// post check function is provided, prepare undo buffer
+					sourceBuffer = ptr;
+					switch (attrdef->m_type) 
+					{
+					case KX_PYATTRIBUTE_TYPE_BOOL:
+						bufferSize = sizeof(bool);
+						break;
+					case KX_PYATTRIBUTE_TYPE_SHORT:
+						bufferSize = sizeof(short);
+						break;
+					case KX_PYATTRIBUTE_TYPE_INT:
+						bufferSize = sizeof(int);
+						break;
+					case KX_PYATTRIBUTE_TYPE_FLOAT:
+						bufferSize = sizeof(float);
+						break;
+					case KX_PYATTRIBUTE_TYPE_STRING:
+						sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr();
+						if (sourceBuffer)
+							bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1;
+						break;
+					default:
+						PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org");
+						return 1;
+					}
+					if (bufferSize)
+					{
+						undoBuffer = malloc(bufferSize);
+						if (undoBuffer)
+						{
+							memcpy(undoBuffer, sourceBuffer, bufferSize);
+						}
+					}
+				}
+					
+				switch (attrdef->m_type) 
+				{
+				case KX_PYATTRIBUTE_TYPE_BOOL:
+					{
+						bool *var = reinterpret_cast<bool*>(ptr);
+						if (PyInt_Check(value)) 
+						{
+							*var = (PyInt_AsLong(value) != 0);
+						} 
+						else if (PyBool_Check(value))
+						{
+							*var = (value == Py_True);
+						}
+						else
+						{
+							PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
+							goto FREE_AND_ERROR;
+						}
+						break;
+					}
+				case KX_PYATTRIBUTE_TYPE_SHORT:
+					{
+						short int *var = reinterpret_cast<short int*>(ptr);
+						if (PyInt_Check(value)) 
+						{
+							long val = PyInt_AsLong(value);
+							if (val < attrdef->m_imin || val > attrdef->m_imax)
+							{
+								PyErr_SetString(PyExc_ValueError, "value out of range");
+								goto FREE_AND_ERROR;
+							}
+							*var = (short int)val;
+						}
+						else
+						{
+							PyErr_SetString(PyExc_TypeError, "expected an integer");
+							goto FREE_AND_ERROR;
+						}
+						break;
+					}
+				case KX_PYATTRIBUTE_TYPE_INT:
+					{
+						int *var = reinterpret_cast<int*>(ptr);
+						if (PyInt_Check(value)) 
+						{
+							long val = PyInt_AsLong(value);
+							if (val < attrdef->m_imin || val > attrdef->m_imax)
+							{
+								PyErr_SetString(PyExc_ValueError, "value out of range");
+								goto FREE_AND_ERROR;
+							}
+							*var = (int)val;
+						}
+						else
+						{
+							PyErr_SetString(PyExc_TypeError, "expected an integer");
+							goto FREE_AND_ERROR;
+						}
+						break;
+					}
+				case KX_PYATTRIBUTE_TYPE_FLOAT:
+					{
+						float *var = reinterpret_cast<float*>(ptr);
+						if (PyFloat_Check(value)) 
+						{
+							double val = PyFloat_AsDouble(value);
+							if (val < attrdef->m_fmin || val > attrdef->m_fmax)
+							{

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list