Revision: 18267
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=18267
Author:   ben2610
Date:     2009-01-02 18:43:56 +0100 (Fri, 02 Jan 2009)

Log Message:
-----------
BGE API Cleanup: update the python attribute definition framework.

* Value clamping to min/max is now supported as an option for integer, float 
  and string attribute (for string clamping=trim to max length)
* Post check function now take PyAttributeDef parameter so that more 
  generic function can be written.
* Definition of SCA_ILogicBrick::CheckProperty() function to check that
  a string attribute contains a valid property name of the parent game object.
* Definition of enum attribute vi KX_PYATTRIBUTE_ENUM... macros. 
  Enum are handled just like integer but to be totally paranoid, the sizeof()
  of the enum member is check at run time to match integer size.
* More bricks updated to use the framework.

Modified Paths:
--------------
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.h
    trunk/blender/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_ActuatorSensor.h
    trunk/blender/source/gameengine/GameLogic/SCA_DelaySensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_ILogicBrick.h
    trunk/blender/source/gameengine/GameLogic/SCA_ISensor.cpp
    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
    trunk/blender/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_PropertySensor.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_PropertySensor.h
    trunk/blender/source/gameengine/GameLogic/SCA_RandomActuator.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_RandomActuator.h

Modified: trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
===================================================================
--- trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp        
2009-01-02 16:58:09 UTC (rev 18266)
+++ trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp        
2009-01-02 17:43:56 UTC (rev 18267)
@@ -164,6 +164,14 @@
                                                        
PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
                                                        break;
                                                }
+                                       case KX_PYATTRIBUTE_TYPE_ENUM:
+                                               // enum are like int, just make 
sure the field size is the same
+                                               if (sizeof(int) != 
attrdef->m_size)
+                                               {
+                                                       Py_DECREF(resultlist);
+                                                       return NULL;
+                                               }
+                                               // walkthrough
                                        case KX_PYATTRIBUTE_TYPE_INT:
                                                {
                                                        int *val = 
reinterpret_cast<int*>(ptr);
@@ -180,6 +188,7 @@
                                                }
                                        default:
                                                // no support for array of 
complex data
+                                               Py_DECREF(resultlist);
                                                return NULL;
                                        }
                                }
@@ -198,6 +207,13 @@
                                                short int *val = 
reinterpret_cast<short int*>(ptr);
                                                return PyInt_FromLong(*val);
                                        }
+                               case KX_PYATTRIBUTE_TYPE_ENUM:
+                                       // enum are like int, just make sure 
the field size is the same
+                                       if (sizeof(int) != attrdef->m_size)
+                                       {
+                                               return NULL;
+                                       }
+                                       // walkthrough
                                case KX_PYATTRIBUTE_TYPE_INT:
                                        {
                                                int *val = 
reinterpret_cast<int*>(ptr);
@@ -260,6 +276,7 @@
                                case KX_PYATTRIBUTE_TYPE_SHORT:
                                        bufferSize = sizeof(short int);
                                        break;
+                               case KX_PYATTRIBUTE_TYPE_ENUM:
                                case KX_PYATTRIBUTE_TYPE_INT:
                                        bufferSize = sizeof(int);
                                        break;
@@ -313,8 +330,15 @@
                                                        if (PyInt_Check(item)) 
                                                        {
                                                                long val = 
PyInt_AsLong(item);
-                                                               if (val < 
attrdef->m_imin || val > attrdef->m_imax)
+                                                               if 
(attrdef->m_clamp)
                                                                {
+                                                                       if (val 
< attrdef->m_imin)
+                                                                               
val = attrdef->m_imin;
+                                                                       else if 
(val > attrdef->m_imax)
+                                                                               
val = attrdef->m_imax;
+                                                               }
+                                                               else if (val < 
attrdef->m_imin || val > attrdef->m_imax)
+                                                               {
                                                                        
PyErr_SetString(PyExc_ValueError, "item value out of range");
                                                                        goto 
UNDO_AND_ERROR;
                                                                }
@@ -327,6 +351,14 @@
                                                        }
                                                        break;
                                                }
+                                       case KX_PYATTRIBUTE_TYPE_ENUM:
+                                               // enum are equivalent to int, 
just make sure that the field size matches:
+                                               if (sizeof(int) != 
attrdef->m_size)
+                                               {
+                                                       
PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to 
blender.org");
+                                                       goto UNDO_AND_ERROR;
+                                               }
+                                               // walkthrough
                                        case KX_PYATTRIBUTE_TYPE_INT:
                                                {
                                                        int *var = 
reinterpret_cast<int*>(ptr);
@@ -334,8 +366,15 @@
                                                        if (PyInt_Check(item)) 
                                                        {
                                                                long val = 
PyInt_AsLong(item);
-                                                               if (val < 
attrdef->m_imin || val > attrdef->m_imax)
+                                                               if 
(attrdef->m_clamp)
                                                                {
+                                                                       if (val 
< attrdef->m_imin)
+                                                                               
val = attrdef->m_imin;
+                                                                       else if 
(val > attrdef->m_imax)
+                                                                               
val = attrdef->m_imax;
+                                                               }
+                                                               else if (val < 
attrdef->m_imin || val > attrdef->m_imax)
+                                                               {
                                                                        
PyErr_SetString(PyExc_ValueError, "item value out of range");
                                                                        goto 
UNDO_AND_ERROR;
                                                                }
@@ -352,21 +391,25 @@
                                                {
                                                        float *var = 
reinterpret_cast<float*>(ptr);
                                                        ptr += sizeof(float);
-                                                       if 
(PyFloat_Check(item)) 
+                                                       double val = 
PyFloat_AsDouble(item);
+                                                       if (val == -1.0 && 
PyErr_Occurred())
                                                        {
-                                                               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;
+                                                               
PyErr_SetString(PyExc_TypeError, "expected a float");
+                                                               goto 
UNDO_AND_ERROR;
                                                        }
-                                                       else
+                                                       else if 
(attrdef->m_clamp) 
                                                        {
-                                                               
PyErr_SetString(PyExc_TypeError, "expected a float");
+                                                               if (val < 
attrdef->m_fmin)
+                                                                       val = 
attrdef->m_fmin;
+                                                               else if (val > 
attrdef->m_fmax)
+                                                                       val = 
attrdef->m_fmax;
+                                                       }
+                                                       else 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;
                                                        break;
                                                }
                                        default:
@@ -378,7 +421,7 @@
                                // no error, call check function if any
                                if (attrdef->m_function != NULL)
                                {
-                                       if ((*attrdef->m_function)(self) != 0)
+                                       if ((*attrdef->m_function)(self, 
attrdef) != 0)
                                        {
                                                // post check returned an 
error, restore values
                                        UNDO_AND_ERROR:
@@ -409,6 +452,7 @@
                                        case KX_PYATTRIBUTE_TYPE_SHORT:
                                                bufferSize = sizeof(short);
                                                break;
+                                       case KX_PYATTRIBUTE_TYPE_ENUM:
                                        case KX_PYATTRIBUTE_TYPE_INT:
                                                bufferSize = sizeof(int);
                                                break;
@@ -460,8 +504,15 @@
                                                if (PyInt_Check(value)) 
                                                {
                                                        long val = 
PyInt_AsLong(value);
-                                                       if (val < 
attrdef->m_imin || val > attrdef->m_imax)
+                                                       if (attrdef->m_clamp)
                                                        {
+                                                               if (val < 
attrdef->m_imin)
+                                                                       val = 
attrdef->m_imin;
+                                                               else if (val > 
attrdef->m_imax)
+                                                                       val = 
attrdef->m_imax;
+                                                       }
+                                                       else if (val < 
attrdef->m_imin || val > attrdef->m_imax)
+                                                       {
                                                                
PyErr_SetString(PyExc_ValueError, "value out of range");
                                                                goto 
FREE_AND_ERROR;
                                                        }
@@ -474,14 +525,29 @@
                                                }
                                                break;
                                        }
+                               case KX_PYATTRIBUTE_TYPE_ENUM:
+                                       // enum are equivalent to int, just 
make sure that the field size matches:
+                                       if (sizeof(int) != attrdef->m_size)
+                                       {
+                                               
PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to 
blender.org");
+                                               goto FREE_AND_ERROR;
+                                       }
+                                       // walkthrough
                                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)
+                                                       if (attrdef->m_clamp)
                                                        {
+                                                               if (val < 
attrdef->m_imin)
+                                                                       val = 
attrdef->m_imin;
+                                                               else if (val > 
attrdef->m_imax)
+                                                                       val = 
attrdef->m_imax;
+                                                       }
+                                                       else if (val < 
attrdef->m_imin || val > attrdef->m_imax)
+                                                       {
                                                                
PyErr_SetString(PyExc_ValueError, "value out of range");
                                                                goto 
FREE_AND_ERROR;
                                                        }
@@ -497,21 +563,25 @@
                                case KX_PYATTRIBUTE_TYPE_FLOAT:
                                        {
                                                float *var = 
reinterpret_cast<float*>(ptr);
-                                               if (PyFloat_Check(value)) 
+                                               double val = 
PyFloat_AsDouble(value);
+                                               if (val == -1.0 && 
PyErr_Occurred())
                                                {
-                                                       double val = 
PyFloat_AsDouble(value);
-                                                       if (val < 
attrdef->m_fmin || val > attrdef->m_fmax)
-                                                       {
-                                                               
PyErr_SetString(PyExc_ValueError, "value out of range");
-                                                               goto 
FREE_AND_ERROR;
-                                                       }
-                                                       *var = (float)val;
+                                                       
PyErr_SetString(PyExc_TypeError, "expected a float");
+                                                       goto FREE_AND_ERROR;
                                                }
-                                               else
+                                               else if (attrdef->m_clamp)
                                                {
-                                                       
PyErr_SetString(PyExc_TypeError, "expected a float");
+                                                       if (val < 
attrdef->m_fmin)
+                                                               val = 
attrdef->m_fmin;
+                                                       else if (val > 
attrdef->m_fmax)
+                                                               val = 
attrdef->m_fmax;
+                                               }
+                                               else if (val < attrdef->m_fmin 
|| val > attrdef->m_fmax)
+                                               {
+                                                       
PyErr_SetString(PyExc_ValueError, "value out of range");
                                                        goto FREE_AND_ERROR;
                                                }
+                                               *var = (float)val;
                                                break;
                                        }
                                case KX_PYATTRIBUTE_TYPE_STRING:
@@ -520,8 +590,25 @@
                                                if (PyString_Check(value)) 
                                                {
                                                        char *val = 
PyString_AsString(value);
-                                                       if (strlen(val) < 
attrdef->m_imin || strlen(val) > attrdef->m_imax)
+                                                       if (attrdef->m_clamp)
                                                        {
+                                                               if (strlen(val) 
< attrdef->m_imin)
+                                                               {
+                                                                       // 
can't increase the length of the string
+                                                                       
PyErr_SetString(PyExc_ValueError, "string length too short");
+                                                                       goto 
FREE_AND_ERROR;
+                                                               }
+                                                               else if 
(strlen(val) > attrdef->m_imax)
+                                                               {
+                                                                       // trim 
the string
+                                                                       char c 
= val[attrdef->m_imax];
+                                                                       
val[attrdef->m_imax] = 0;
+                                                                       *var = 
val;
+                                                                       
val[attrdef->m_imax] = c;
+                                                                       break;
+                                                               }
+                                                       } else if (strlen(val) 
< attrdef->m_imin || strlen(val) > attrdef->m_imax)
+                                                       {
                                                                
PyErr_SetString(PyExc_ValueError, "string length out of range");
                                                                goto 
FREE_AND_ERROR;
                                                        }
@@ -543,9 +630,10 @@
                        // check if post processing is needed
                        if (attrdef->m_function != NULL)
                        {
-                               if ((*attrdef->m_function)(self) != 0)
+                               if ((*attrdef->m_function)(self, attrdef) != 0)
                                {
                                        // restore value
+                               RESTORE_AND_ERROR:
                                        if (undoBuffer)
                                        {
                                                if (attrdef->m_type == 
KX_PYATTRIBUTE_TYPE_STRING)

Modified: trunk/blender/source/gameengine/Expressions/PyObjectPlus.h
===================================================================
--- trunk/blender/source/gameengine/Expressions/PyObjectPlus.h  2009-01-02 
16:58:09 UTC (rev 18266)
+++ trunk/blender/source/gameengine/Expressions/PyObjectPlus.h  2009-01-02 
17:43:56 UTC (rev 18267)
@@ -216,6 +216,7 @@
  */
 enum KX_PYATTRIBUTE_TYPE {
        KX_PYATTRIBUTE_TYPE_BOOL,
+       KX_PYATTRIBUTE_TYPE_ENUM,
        KX_PYATTRIBUTE_TYPE_SHORT,
        KX_PYATTRIBUTE_TYPE_INT,
        KX_PYATTRIBUTE_TYPE_FLOAT,
@@ -228,17 +229,20 @@
        KX_PYATTRIBUTE_RO
 };
 
-typedef int (*KX_PYATTRIBUTE_FUNCTION)(void *self);
+struct KX_PYATTRIBUTE_DEF;
+typedef int (*KX_PYATTRIBUTE_FUNCTION)(void *self, const struct 
KX_PYATTRIBUTE_DEF *attrdef);
 
 typedef struct KX_PYATTRIBUTE_DEF {
        const char *m_name;                             // name of the python 
attribute
        KX_PYATTRIBUTE_TYPE m_type;             // type of value
        KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only
-       int m_imin;                                             // minimum 
value in case of integer attributes
-       int m_imax;                                             // maximum 
value in case of integer attributes
+       int m_imin;                                             // minimum 
value in case of integer attributes (for string: minimum string length)
+       int m_imax;                                             // maximum 
value in case of integer attributes (for string: maximum string length)
        float m_fmin;                                   // minimum value in 
case of float attributes
        float m_fmax;                                   // maximum value in 
case of float attributes
+       bool   m_clamp;                                 // enforce min/max 
value by clamping
        size_t m_offset;                                // position of field in 
structure
+       size_t m_size;                                  // size of field for 
runtime verification (enum only)
        size_t m_length;                                // length of array, 
1=simple attribute
        KX_PYATTRIBUTE_FUNCTION m_function;     // static function to check the 
assignment, returns 0 if no error

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to