BGE: Extend Python API for KX_BlenderMaterial (specular, diffuse…)
authorPorteries Tristan <republicthunderbolt9@gmail.com>
Fri, 3 Jul 2015 09:47:48 +0000 (11:47 +0200)
committerPorteries Tristan <republicthunderbolt9@gmail.com>
Fri, 3 Jul 2015 09:47:48 +0000 (11:47 +0200)
Add support for material diffuse, specular… in KX_BlenderMaterial python proxy. And use mathutils in KX_BlenderMaterial for the specular and diffuse color in KX_BlenderMaterial.

Reviewers: sybren, brita_, kupoman, agoose77, dfelinto, moguri, campbellbarton, hg1

Reviewed By: moguri, campbellbarton, hg1

Subscribers: dfelinto

Projects: #game_engine

Differential Revision: https://developer.blender.org/D1298

doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst
source/gameengine/Ketsji/KX_BlenderMaterial.cpp
source/gameengine/Ketsji/KX_BlenderMaterial.h
source/gameengine/Ketsji/KX_PyMath.cpp
source/gameengine/Ketsji/KX_PyMath.h
source/gameengine/Ketsji/KX_PythonInitTypes.cpp

index 80450526c9a947502ae26aa57b70e33ce4685658..17f54031ec30235a6298754122206983701203d2 100644 (file)
@@ -89,6 +89,48 @@ base class --- :class:`PyObjectPlus`
       :return: the material's shader
       :rtype: :class:`BL_Shader`
 
+   .. attribute:: alpha
+
+      The material's alpha transparency.
+
+      :type: float between 0.0 and 1.0 inclusive
+
+   .. attribute:: hardness
+
+      How hard (sharp) the material's specular reflection is.
+
+      :type: integer between 1 and 511 inclusive
+
+   .. attribute:: emit
+
+      Amount of light to emit.
+
+      :type: float between 0.0 and 2.0 inclusive
+
+   .. attribute:: specularIntensity
+
+      How intense (bright) the material's specular reflection is.
+
+      :type: float between 0.0 and 1.0 inclusive
+
+   .. attribute:: diffuseIntensity
+
+      The material's amount of diffuse reflection.
+
+      :type: float between 0.0 and 1.0 inclusive
+
+   .. attribute:: specularColor
+
+      The material's specular color.
+
+      :type: :class:`mathutils.Color`
+
+   .. attribute:: diffuseColor
+
+      The material's diffuse color.
+
+      :type: :class:`mathutils.Color`
+
    .. method:: setBlending(src, dest)
 
       Set the pixel color arithmetic functions.
index 7ec2673bf1f5d082d126ff7f0e8d9bd37efbc82b..abe565f8e2f4f4f69f9c1ef8d4ea65a71e0b626c 100644 (file)
@@ -30,6 +30,7 @@
 #include "KX_Light.h"
 #include "KX_GameObject.h"
 #include "KX_MeshProxy.h"
+#include "KX_PyMath.h"
 
 #include "MT_Vector3.h"
 #include "MT_Vector4.h"
@@ -52,6 +53,7 @@
 #include "BKE_mesh.h"
 // ------------------------------------
 #include "BLI_utildefines.h"
+#include "BLI_math.h"
 
 #define spit(x) std::cout << x << std::endl;
 
@@ -844,6 +846,11 @@ void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val)
        OnConstruction();
 }
 
+BL_Material *KX_BlenderMaterial::GetBLMaterial()
+{
+       return mMaterial;
+}
+
 void KX_BlenderMaterial::SetBlenderGLSLShader()
 {
        if (!mBlenderShader)
@@ -855,6 +862,111 @@ void KX_BlenderMaterial::SetBlenderGLSLShader()
        }
 }
 
+#ifdef USE_MATHUTILS
+
+#define MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR 1
+#define MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR 2
+
+static unsigned char mathutils_kxblendermaterial_color_cb_index = -1; /* index for our callbacks */
+
+static int mathutils_kxblendermaterial_generic_check(BaseMathObject *bmo)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>BGE_PROXY_REF(bmo->cb_user);
+       if (!self)
+               return -1;
+
+       return 0;
+}
+
+static int mathutils_kxblendermaterial_color_get(BaseMathObject *bmo, int subtype)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial*>BGE_PROXY_REF(bmo->cb_user);
+       if (!self)
+               return -1;
+
+       switch (subtype) {
+               case MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR:
+               {
+                       copy_v3_v3(bmo->data, self->GetBLMaterial()->matcolor);
+                       break;
+               }
+               case MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR:
+               {
+                       copy_v3_v3(bmo->data, self->GetBLMaterial()->speccolor);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int mathutils_kxblendermaterial_color_set(BaseMathObject *bmo, int subtype)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>BGE_PROXY_REF(bmo->cb_user);
+       if (!self)
+               return -1;
+
+       switch (subtype) {
+               case MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR:
+               {
+                       BL_Material *mat = self->GetBLMaterial();
+                       copy_v3_v3(mat->matcolor, bmo->data);
+                       mat->material->r = bmo->data[0];
+                       mat->material->g = bmo->data[1];
+                       mat->material->b = bmo->data[2];
+                       break;
+               }
+               case MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR:
+               {
+                       BL_Material *mat = self->GetBLMaterial();
+                       copy_v3_v3(mat->speccolor, bmo->data);
+                       mat->material->specr = bmo->data[0];
+                       mat->material->specg = bmo->data[1];
+                       mat->material->specb = bmo->data[2];
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int mathutils_kxblendermaterial_color_get_index(BaseMathObject *bmo, int subtype, int index)
+{
+       /* lazy, avoid repeteing the case statement */
+       if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1)
+               return -1;
+       return 0;
+}
+
+static int mathutils_kxblendermaterial_color_set_index(BaseMathObject *bmo, int subtype, int index)
+{
+       float f = bmo->data[index];
+
+       /* lazy, avoid repeateing the case statement */
+       if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1)
+               return -1;
+
+       bmo->data[index] = f;
+       return mathutils_kxblendermaterial_color_set(bmo, subtype);
+}
+
+static Mathutils_Callback mathutils_kxblendermaterial_color_cb = {
+       mathutils_kxblendermaterial_generic_check,
+       mathutils_kxblendermaterial_color_get,
+       mathutils_kxblendermaterial_color_set,
+       mathutils_kxblendermaterial_color_get_index,
+       mathutils_kxblendermaterial_color_set_index
+};
+
+
+void KX_BlenderMaterial_Mathutils_Callback_Init()
+{
+       // register mathutils callbacks, ok to run more than once.
+       mathutils_kxblendermaterial_color_cb_index = Mathutils_RegisterCallback(&mathutils_kxblendermaterial_color_cb);
+}
+
+#endif // USE_MATHUTILS
+
 #ifdef WITH_PYTHON
 
 PyMethodDef KX_BlenderMaterial::Methods[] = 
@@ -869,6 +981,14 @@ PyAttributeDef KX_BlenderMaterial::Attributes[] = {
        KX_PYATTRIBUTE_RO_FUNCTION("shader", KX_BlenderMaterial, pyattr_get_shader),
        KX_PYATTRIBUTE_RO_FUNCTION("material_index", KX_BlenderMaterial, pyattr_get_materialIndex),
        KX_PYATTRIBUTE_RW_FUNCTION("blending", KX_BlenderMaterial, pyattr_get_blending, pyattr_set_blending),
+       KX_PYATTRIBUTE_RW_FUNCTION("alpha", KX_BlenderMaterial, pyattr_get_alpha, pyattr_set_alpha),
+       KX_PYATTRIBUTE_RW_FUNCTION("hardness", KX_BlenderMaterial, pyattr_get_hardness, pyattr_set_hardness),
+       KX_PYATTRIBUTE_RW_FUNCTION("specularIntensity", KX_BlenderMaterial, pyattr_get_specular_intensity, pyattr_set_specular_intensity),
+       KX_PYATTRIBUTE_RW_FUNCTION("specularColor", KX_BlenderMaterial, pyattr_get_specular_color, pyattr_set_specular_color),
+       KX_PYATTRIBUTE_RW_FUNCTION("diffuseIntensity", KX_BlenderMaterial, pyattr_get_diffuse_intensity, pyattr_set_diffuse_intensity),
+       KX_PYATTRIBUTE_RW_FUNCTION("diffuseColor", KX_BlenderMaterial, pyattr_get_diffuse_color, pyattr_set_diffuse_color),
+       KX_PYATTRIBUTE_RW_FUNCTION("emit", KX_BlenderMaterial, pyattr_get_emit, pyattr_set_emit),
+
        { NULL }        //Sentinel
 };
 
@@ -913,6 +1033,170 @@ PyObject *KX_BlenderMaterial::pyattr_get_blending(void *self_v, const KX_PYATTRI
        return Py_BuildValue("(ll)", (long int)bfunc[0], (long int)bfunc[1]);
 }
 
+PyObject *KX_BlenderMaterial::pyattr_get_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       return PyFloat_FromDouble(self->GetBLMaterial()->alpha);
+}
+
+int KX_BlenderMaterial::pyattr_set_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       float val = PyFloat_AsDouble(value);
+
+       if (val == -1 && PyErr_Occurred()) {
+               PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name);
+               return PY_SET_ATTR_FAIL;
+       }
+
+       CLAMP(val, 0.0f, 1.0f);
+
+       BL_Material *mat = self->GetBLMaterial();
+       mat->alpha = mat->material->alpha = val;
+       return PY_SET_ATTR_SUCCESS;
+}
+PyObject *KX_BlenderMaterial::pyattr_get_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       return PyLong_FromLong(self->GetBLMaterial()->hard);
+}
+
+int KX_BlenderMaterial::pyattr_set_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       int val = PyLong_AsLong(value);
+
+       if (val == -1 && PyErr_Occurred()) {
+               PyErr_Format(PyExc_AttributeError, "material.%s = int: KX_BlenderMaterial, expected a int", attrdef->m_name);
+               return PY_SET_ATTR_FAIL;
+       }
+
+       CLAMP(val, 1, 511);
+
+       BL_Material *mat = self->GetBLMaterial();
+       mat->hard = mat->material->har = val;
+       return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_BlenderMaterial::pyattr_get_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       return PyFloat_FromDouble(self->GetBLMaterial()->spec_f);
+}
+
+int KX_BlenderMaterial::pyattr_set_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       float val = PyFloat_AsDouble(value);
+
+       if (val == -1 && PyErr_Occurred()) {
+               PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name);
+               return PY_SET_ATTR_FAIL;
+       }
+
+       CLAMP(val, 0.0f, 1.0f);
+
+       BL_Material *mat = self->GetBLMaterial();
+       mat->spec_f = mat->material->spec = val;
+       return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_BlenderMaterial::pyattr_get_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+#ifdef USE_MATHUTILS
+       return Color_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR);
+#else
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       return PyColorFromVector(MT_Vector3(self->GetBLMaterial()->speccolor));
+#endif
+}
+
+int KX_BlenderMaterial::pyattr_set_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       MT_Vector3 color;
+       if (!PyVecTo(value, color))
+               return PY_SET_ATTR_FAIL;
+
+       BL_Material *mat = self->GetBLMaterial();
+       color.getValue(mat->speccolor);
+       mat->material->specr = color[0];
+       mat->material->specg = color[1];
+       mat->material->specb = color[2];
+       return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_BlenderMaterial::pyattr_get_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       return PyFloat_FromDouble(self->GetBLMaterial()->ref);
+}
+
+int KX_BlenderMaterial::pyattr_set_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       float val = PyFloat_AsDouble(value);
+
+       if (val == -1 && PyErr_Occurred()) {
+               PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name);
+               return PY_SET_ATTR_FAIL;
+       }
+
+       CLAMP(val, 0.0f, 1.0f);
+
+       BL_Material *mat = self->GetBLMaterial();
+       mat->ref = mat->material->ref = val;
+       return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_BlenderMaterial::pyattr_get_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+#ifdef USE_MATHUTILS
+       return Color_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR);
+#else
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       return PyColorFromVector(MT_Vector3(self->GetBLMaterial()->matcolor));
+#endif
+}
+
+int KX_BlenderMaterial::pyattr_set_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       MT_Vector3 color;
+       if (!PyVecTo(value, color))
+               return PY_SET_ATTR_FAIL;
+
+       BL_Material *mat = self->GetBLMaterial();
+       color.getValue(mat->matcolor);
+       mat->material->r = color[0];
+       mat->material->g = color[1];
+       mat->material->b = color[2];
+       return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_BlenderMaterial::pyattr_get_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       return PyFloat_FromDouble(self->GetBLMaterial()->emit);
+}
+
+int KX_BlenderMaterial::pyattr_set_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v);
+       float val = PyFloat_AsDouble(value);
+
+       if (val == -1 && PyErr_Occurred()) {
+               PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name);
+               return PY_SET_ATTR_FAIL;
+       }
+
+       CLAMP(val, 0.0f, 2.0f);
+
+       BL_Material *mat = self->GetBLMaterial();
+       mat->emit = mat->material->emit = val;
+       return PY_SET_ATTR_SUCCESS;
+}
+
 int KX_BlenderMaterial::pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
 {
        KX_BlenderMaterial* self = static_cast<KX_BlenderMaterial*>(self_v);
index 23921588d6a9323d290b184418fb03e5ff6045c6..0448236b10c4ce9f75656e41a9c7b81bd38aac65 100644 (file)
 struct MTFace;
 class KX_Scene;
 
+
+#ifdef USE_MATHUTILS
+void KX_BlenderMaterial_Mathutils_Callback_Init(void);
+#endif
+
 class KX_BlenderMaterial :  public PyObjectPlus, public RAS_IPolyMaterial
 {
        Py_Header
@@ -99,6 +104,8 @@ public:
        
        virtual void Replace_IScene(SCA_IScene *val);
 
+       BL_Material *GetBLMaterial();
+
 #ifdef WITH_PYTHON
        // --------------------------------
        virtual PyObject *py_repr(void) { return PyUnicode_From_STR_String(mMaterial->matname); }
@@ -107,6 +114,20 @@ public:
        static PyObject *pyattr_get_materialIndex(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static PyObject *pyattr_get_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static int       pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject *pyattr_get_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int       pyattr_set_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject *pyattr_get_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int       pyattr_set_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject *pyattr_get_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int       pyattr_set_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject *pyattr_get_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int       pyattr_set_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject *pyattr_get_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int       pyattr_set_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject *pyattr_get_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int       pyattr_set_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject *pyattr_get_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int       pyattr_set_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
 
        KX_PYMETHOD_DOC(KX_BlenderMaterial, getShader);
        KX_PYMETHOD_DOC(KX_BlenderMaterial, getMaterialIndex);
index 76332e7520419879e447abd2d27ab5705b540585..798e93a12e9fe20a1d9e713d086c6f8a582746ac 100644 (file)
@@ -197,4 +197,19 @@ PyObject *PyObjectFrom(const MT_Tuple2 &vec)
 #endif
 }
 
+PyObject *PyColorFromVector(const MT_Vector3 &vec)
+{
+#ifdef USE_MATHUTILS
+       float fvec[3];
+       vec.getValue(fvec);
+       return Color_CreatePyObject(fvec, NULL);
+#else
+       PyObject *list = PyList_New(3);
+       PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0]));
+       PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1]));
+       PyList_SET_ITEM(list, 2, PyFloat_FromDouble(vec[2]));
+       return list;
+#endif
+}
+
 #endif // WITH_PYTHON
index 159506946e84d37f197f7d61392a5a4ec80d204a..63a37806fb67ed74ebb36faa7e56da1f6ac37a0f 100644 (file)
@@ -273,4 +273,9 @@ PyObject *PyObjectFrom(const MT_Tuple4 &pos);
 
 #endif
 
+/**
+ * Converts an MT_Vector3 to a python color object.
+ */
+PyObject *PyColorFromVector(const MT_Vector3 &vec);
+
 #endif  /* WITH_PYTHON */
index b3511e4e61ac8db1ecca667738e2434f81a0ae80..ef6ad4712a5c5acc39c62af27071b9378857d9a5 100644 (file)
@@ -282,6 +282,7 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
        KX_GameObject_Mathutils_Callback_Init();
        KX_ObjectActuator_Mathutils_Callback_Init();
        KX_WorldInfo_Mathutils_Callback_Init();
+       KX_BlenderMaterial_Mathutils_Callback_Init();
 #endif
 
        return m;