diff options
Diffstat (limited to 'source/blender/python')
80 files changed, 7715 insertions, 3047 deletions
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 955b1c4e4ed..5a2f15405c1 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -90,7 +90,8 @@ void BPY_modules_load_user(struct bContext *C); void BPY_app_handlers_reset(const short do_all); void BPY_driver_reset(void); -float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); +float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, + struct ChannelDriver *driver_orig, const float evaltime); void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr); diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt index e855f3a3756..030576fefd1 100644 --- a/source/blender/python/CMakeLists.txt +++ b/source/blender/python/CMakeLists.txt @@ -18,5 +18,6 @@ add_subdirectory(intern) add_subdirectory(generic) +add_subdirectory(gpu) add_subdirectory(mathutils) add_subdirectory(bmesh) diff --git a/source/blender/python/bmesh/CMakeLists.txt b/source/blender/python/bmesh/CMakeLists.txt index 3b38fead7b9..48213b7eed5 100644 --- a/source/blender/python/bmesh/CMakeLists.txt +++ b/source/blender/python/bmesh/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../../bmesh ../../blenkernel ../../blenlib + ../../depsgraph ../../makesdna ../../../../intern/guardedalloc ) diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c index 5819d7ce2bb..012f7b1232d 100644 --- a/source/blender/python/bmesh/bmesh_py_api.c +++ b/source/blender/python/bmesh/bmesh_py_api.c @@ -113,30 +113,30 @@ static PyObject *bpy_bm_from_edit_mesh(PyObject *UNUSED(self), PyObject *value) } PyDoc_STRVAR(bpy_bm_update_edit_mesh_doc, -".. method:: update_edit_mesh(mesh, tessface=True, destructive=True)\n" +".. method:: update_edit_mesh(mesh, loop_triangles=True, destructive=True)\n" "\n" " Update the mesh after changes to the BMesh in editmode,\n" " optionally recalculating n-gon tessellation.\n" "\n" " :arg mesh: The editmode mesh.\n" " :type mesh: :class:`bpy.types.Mesh`\n" -" :arg tessface: Option to recalculate n-gon tessellation.\n" -" :type tessface: boolean\n" +" :arg loop_triangles: Option to recalculate n-gon tessellation.\n" +" :type loop_triangles: boolean\n" " :arg destructive: Use when geometry has been added or removed.\n" " :type destructive: boolean\n" ); static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - static const char *kwlist[] = {"mesh", "tessface", "destructive", NULL}; + static const char *kwlist[] = {"mesh", "loop_triangles", "destructive", NULL}; PyObject *py_me; Mesh *me; - bool do_tessface = true; + bool do_loop_triangles = true; bool is_destructive = true; if (!PyArg_ParseTupleAndKeywords( args, kw, "O|O&O&:update_edit_mesh", (char **)kwlist, &py_me, - PyC_ParseBool, &do_tessface, + PyC_ParseBool, &do_loop_triangles, PyC_ParseBool, &is_destructive)) { return NULL; @@ -156,13 +156,8 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, { extern void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive); - BMEditMesh *em = me->edit_btmesh; - BMesh *bm = em->bm; - /* python won't ensure matching uv/mtex */ - BM_mesh_cd_validate(bm); - - EDBM_update_generic(me->edit_btmesh, do_tessface, is_destructive); + EDBM_update_generic(me->edit_btmesh, do_loop_triangles, is_destructive); } Py_RETURN_NONE; @@ -208,21 +203,17 @@ PyObject *BPyInit_bmesh(void) /* bmesh.types */ PyModule_AddObject(mod, "types", (submodule = BPyInit_bmesh_types())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); /* bmesh.ops (not a real module, exposes module like access). */ PyModule_AddObject(mod, "ops", (submodule = BPyInit_bmesh_ops())); /* PyDict_SetItemString(sys_modules, PyModule_GetNameObject(submodule), submodule); */ PyDict_SetItemString(sys_modules, "bmesh.ops", submodule); /* fake module */ - Py_INCREF(submodule); PyModule_AddObject(mod, "utils", (submodule = BPyInit_bmesh_utils())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); PyModule_AddObject(mod, "geometry", (submodule = BPyInit_bmesh_geometry())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); return mod; } diff --git a/source/blender/python/bmesh/bmesh_py_ops.c b/source/blender/python/bmesh/bmesh_py_ops.c index ee96c859858..49e71da3bc3 100644 --- a/source/blender/python/bmesh/bmesh_py_ops.c +++ b/source/blender/python/bmesh/bmesh_py_ops.c @@ -75,10 +75,14 @@ static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], c { DynStr *dyn_str = BLI_dynstr_new(); char *ret; + bool quoted; + bool set; int i = 0; while (*slot_types[i].name) { + quoted = false; + set = false; /* cut off '.out' by using a string size arg */ const int name_len = is_out ? (strchr(slot_types[i].name, '.') - slot_types[i].name) : @@ -86,7 +90,19 @@ static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], c const char *value = "<Unknown>"; switch (slot_types[i].type) { case BMO_OP_SLOT_BOOL: value = "False"; break; - case BMO_OP_SLOT_INT: value = "0"; break; + case BMO_OP_SLOT_INT: + if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_ENUM) { + value = slot_types[i].enum_flags[0].identifier; + quoted = true; + } + else if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) { + value = ""; + set = true; + } + else { + value = "0"; + } + break; case BMO_OP_SLOT_FLT: value = "0.0"; break; case BMO_OP_SLOT_PTR: value = "None"; break; case BMO_OP_SLOT_MAT: value = "Matrix()"; break; @@ -95,7 +111,12 @@ static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], c (slot_types[i].subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) ? "None" : "[]"; break; case BMO_OP_SLOT_MAPPING: value = "{}"; break; } - BLI_dynstr_appendf(dyn_str, i ? ", %.*s=%s" : "%.*s=%s", name_len, slot_types[i].name, value); + BLI_dynstr_appendf( + dyn_str, i ? ", %.*s=%s%s%s%s%s" : "%.*s=%s%s%s%s%s", + name_len, slot_types[i].name, + set ? "{" : "", quoted ? "'" : "", + value, + quoted ? "'" : "", set ? "}" : ""); i++; } diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 14e14cd5fe3..ac328e852ac 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -46,6 +46,8 @@ #include "../generic/python_utildefines.h" #include "../generic/py_capi_utils.h" +BLI_STATIC_ASSERT(sizeof(PyC_FlagSet) == sizeof(BMO_FlagSet), "size mismatch"); + static int bpy_bm_op_as_py_error(BMesh *bm) { if (BMO_error_occurred(bm)) { @@ -169,16 +171,46 @@ static int bpy_slot_from_py( } case BMO_OP_SLOT_INT: { - const int param = PyC_Long_AsI32(value); + if (slot->slot_subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_ENUM) { + int enum_val = -1; + PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_flags; + const char *enum_str = _PyUnicode_AsString(value); - if (param == -1 && PyErr_Occurred()) { - PyErr_Format(PyExc_TypeError, - "%.200s: keyword \"%.200s\" expected an int, not %.200s", - opname, slot_name, Py_TYPE(value)->tp_name); - return -1; + if (enum_str == NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s: keyword \"%.200s\" expected a string, not %.200s", + opname, slot_name, Py_TYPE(value)->tp_name); + return -1; + } + + if (PyC_FlagSet_ValueFromID(items, enum_str, &enum_val, slot_name) == -1) { + return -1; + } + + BMO_SLOT_AS_INT(slot) = enum_val; + } + else if (slot->slot_subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) { + int flag = 0; + PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_flags; + + if (PyC_FlagSet_ToBitfield(items, value, &flag, slot_name) == -1) { + return -1; + } + + BMO_SLOT_AS_INT(slot) = flag; } else { - BMO_SLOT_AS_INT(slot) = param; + const int param = PyC_Long_AsI32(value); + + if (param == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + "%.200s: keyword \"%.200s\" expected an int, not %.200s", + opname, slot_name, Py_TYPE(value)->tp_name); + return -1; + } + else { + BMO_SLOT_AS_INT(slot) = param; + } } break; } diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 21239f7494a..d18f660197d 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -34,11 +34,13 @@ #include "DNA_object_types.h" #include "DNA_material_types.h" -#include "BKE_depsgraph.h" #include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_mesh_runtime.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "bmesh.h" @@ -903,10 +905,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args) bm = self->bm; - /* python won't ensure matching uv/mtex */ - BM_mesh_cd_validate(bm); - - BLI_assert(BKE_id_is_in_gobal_main(&me->id)); + BLI_assert(BKE_id_is_in_global_main(&me->id)); BM_mesh_bm_to_me( G_MAIN, /* XXX UGLY! */ bm, me, @@ -916,13 +915,13 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args) /* we could have the user do this but if they forget blender can easy crash * since the references arrays for the objects derived meshes are now invalid */ - DAG_id_tag_update(&me->id, OB_RECALC_DATA); + DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY); Py_RETURN_NONE; } PyDoc_STRVAR(bpy_bmesh_from_object_doc, -".. method:: from_object(object, scene, deform=True, render=False, cage=False, face_normals=True)\n" +".. method:: from_object(object, depsgraph, deform=True, cage=False, face_normals=True)\n" "\n" " Initialize this bmesh from existing object datablock (currently only meshes are supported).\n" "\n" @@ -930,8 +929,6 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc, " :type object: :class:`Object`\n" " :arg deform: Apply deformation modifiers.\n" " :type deform: boolean\n" -" :arg render: Use render settings.\n" -" :type render: boolean\n" " :arg cage: Get the mesh as a deformed cage.\n" " :type cage: boolean\n" " :arg face_normals: Calculate face normals.\n" @@ -939,30 +936,29 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc, ); static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw) { - static const char *kwlist[] = {"object", "scene", "deform", "render", "cage", "face_normals", NULL}; + static const char *kwlist[] = {"object", "depsgraph", "deform", "cage", "face_normals", NULL}; PyObject *py_object; - PyObject *py_scene; - Object *ob; - struct Scene *scene; + PyObject *py_depsgraph; + Object *ob, *ob_eval; + struct Depsgraph *depsgraph; + struct Scene *scene_eval; + Mesh *me_eval; BMesh *bm; bool use_deform = true; - bool use_render = false; bool use_cage = false; bool use_fnorm = true; - DerivedMesh *dm; const int mask = CD_MASK_BMESH; BPY_BM_CHECK_OBJ(self); if (!PyArg_ParseTupleAndKeywords( - args, kw, "OO|O&O&O&O&:from_object", (char **)kwlist, - &py_object, &py_scene, + args, kw, "OO|O&O&O&:from_object", (char **)kwlist, + &py_object, &py_depsgraph, PyC_ParseBool, &use_deform, - PyC_ParseBool, &use_render, PyC_ParseBool, &use_cage, PyC_ParseBool, &use_fnorm) || - !(ob = PyC_RNA_AsPointer(py_object, "Object")) || - !(scene = PyC_RNA_AsPointer(py_scene, "Scene"))) + !(ob = PyC_RNA_AsPointer(py_object, "Object")) || + !(depsgraph = PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))) { return NULL; } @@ -973,52 +969,47 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject return NULL; } + const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER; + scene_eval = DEG_get_evaluated_scene(depsgraph); + ob_eval = DEG_get_evaluated_object(depsgraph, ob); + /* Write the display mesh into the dummy mesh */ if (use_deform) { if (use_render) { if (use_cage) { PyErr_SetString(PyExc_ValueError, - "from_object(...): cage arg is unsupported when (render=True)"); + "from_object(...): cage arg is unsupported when dependency graph evaluation mode is RENDER"); return NULL; } else { - dm = mesh_create_derived_render(scene, ob, mask); + me_eval = mesh_create_eval_final_render(depsgraph, scene_eval, ob_eval, mask); } } else { if (use_cage) { - dm = mesh_get_derived_deform(scene, ob, mask); /* ob->derivedDeform */ + me_eval = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, mask); } else { - dm = mesh_get_derived_final(scene, ob, mask); /* ob->derivedFinal */ + me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, mask); } } } else { /* !use_deform */ - if (use_render) { - if (use_cage) { - PyErr_SetString(PyExc_ValueError, - "from_object(...): cage arg is unsupported when (render=True)"); - return NULL; - } - else { - dm = mesh_create_derived_no_deform_render(scene, ob, NULL, mask); - } + if (use_cage) { + PyErr_SetString(PyExc_ValueError, + "from_object(...): cage arg is unsupported when deform=False"); + return NULL; + } + else if (use_render) { + me_eval = mesh_create_eval_no_deform_render(depsgraph, scene_eval, ob, NULL, mask); } else { - if (use_cage) { - PyErr_SetString(PyExc_ValueError, - "from_object(...): cage arg is unsupported when (deform=False, render=False)"); - return NULL; - } - else { - dm = mesh_create_derived_no_deform(scene, ob, NULL, mask); - } + me_eval = mesh_create_eval_no_deform(depsgraph, scene_eval, ob, NULL, mask); } } - if (dm == NULL) { + if (me_eval == NULL) { PyErr_Format(PyExc_ValueError, "from_object(...): Object '%s' has no usable mesh data", ob->id.name + 2); return NULL; @@ -1026,9 +1017,10 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject bm = self->bm; - DM_to_bmesh_ex(dm, bm, use_fnorm); - - dm->release(dm); + BM_mesh_bm_from_me( + bm, me_eval, (&(struct BMeshFromMeshParams){ + .calc_face_normal = use_fnorm, + })); Py_RETURN_NONE; } @@ -1243,15 +1235,15 @@ static PyObject *bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObjec } } -PyDoc_STRVAR(bpy_bmesh_calc_tessface_doc, -".. method:: calc_tessface()\n" +PyDoc_STRVAR(bpy_bmesh_calc_loop_triangles_doc, +".. method:: calc_loop_triangles()\n" "\n" " Calculate triangle tessellation from quads/ngons.\n" "\n" " :return: The triangulated faces.\n" " :rtype: list of :class:`BMLoop` tuples\n" ); -static PyObject *bpy_bmesh_calc_tessface(BPy_BMElem *self) +static PyObject *bpy_bmesh_calc_loop_triangles(BPy_BMElem *self) { BMesh *bm; @@ -2730,7 +2722,7 @@ static struct PyMethodDef bpy_bmesh_methods[] = { /* calculations */ {"calc_volume", (PyCFunction)bpy_bmesh_calc_volume, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_calc_volume_doc}, - {"calc_tessface", (PyCFunction)bpy_bmesh_calc_tessface, METH_NOARGS, bpy_bmesh_calc_tessface_doc}, + {"calc_loop_triangles", (PyCFunction)bpy_bmesh_calc_loop_triangles, METH_NOARGS, bpy_bmesh_calc_loop_triangles_doc}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index ecf5cce8bd2..f49766c93ab 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -105,9 +105,6 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__bevel_weight_doc, PyDoc_STRVAR(bpy_bmlayeraccess_collection__crease_doc, "Edge crease for subsurf - float in [0 - 1].\n\n:type: :class:`BMLayerCollection`" ); -PyDoc_STRVAR(bpy_bmlayeraccess_collection__tex_doc, -"Accessor for :class:`BMTexPoly` layer (TODO).\n\ntype: :class:`BMLayerCollection`" // TYPE DOESN'T EXIST YET -); PyDoc_STRVAR(bpy_bmlayeraccess_collection__uv_doc, "Accessor for :class:`BMLoopUV` UV (as a 2D Vector).\n\ntype: :class:`BMLayerCollection`" ); @@ -120,6 +117,9 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__skin_doc, PyDoc_STRVAR(bpy_bmlayeraccess_collection__paint_mask_doc, "Accessor for paint mask layer.\n\ntype: :class:`BMLayerCollection`" ); +PyDoc_STRVAR(bpy_bmlayeraccess_collection__face_map_doc, +"FaceMap custom-data layer.\n\ntype: :class:`BMLayerCollection`" +); #ifdef WITH_FREESTYLE PyDoc_STRVAR(bpy_bmlayeraccess_collection__freestyle_edge_doc, "Accessor for Freestyle edge layer.\n\ntype: :class:`BMLayerCollection`" @@ -222,8 +222,7 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = { {(char *)"float", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__float_doc, (void *)CD_PROP_FLT}, {(char *)"int", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT}, {(char *)"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STR}, - - {(char *)"tex", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__tex_doc, (void *)CD_MTEXPOLY}, + {(char *)"face_map", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__face_map_doc, (void *)CD_FACEMAP}, #ifdef WITH_FREESTYLE {(char *)"freestyle", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__freestyle_face_doc, (void *)CD_FREESTYLE_FACE}, @@ -989,6 +988,7 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer) break; } case CD_PROP_INT: + case CD_FACEMAP: { ret = PyLong_FromLong(*(int *)value); break; @@ -999,11 +999,6 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer) ret = PyBytes_FromStringAndSize(mstring->s, mstring->s_len); break; } - case CD_MTEXPOLY: - { - ret = BPy_BMTexPoly_CreatePyObject(value); - break; - } case CD_MLOOPUV: { ret = BPy_BMLoopUV_CreatePyObject(value); @@ -1074,6 +1069,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj break; } case CD_PROP_INT: + case CD_FACEMAP: { int tmp_val = PyC_Long_AsI32(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { @@ -1102,11 +1098,6 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj } break; } - case CD_MTEXPOLY: - { - ret = BPy_BMTexPoly_AssignPyObject(value, py_value); - break; - } case CD_MLOOPUV: { ret = BPy_BMLoopUV_AssignPyObject(value, py_value); diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c index d2ea87dd03f..2a0f3817f35 100644 --- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c @@ -42,103 +42,12 @@ #include "BLI_math_vector.h" #include "BKE_deform.h" -#include "BKE_library.h" #include "bmesh_py_types_meshdata.h" #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" - -/* Mesh BMTexPoly - * ************** */ - -#define BPy_BMTexPoly_Check(v) (Py_TYPE(v) == &BPy_BMTexPoly_Type) - -typedef struct BPy_BMTexPoly { - PyObject_VAR_HEAD - MTexPoly *data; -} BPy_BMTexPoly; - -extern PyObject *pyrna_id_CreatePyObject(ID *id); -extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id); - -PyDoc_STRVAR(bpy_bmtexpoly_image_doc, -"Image or None.\n\n:type: :class:`bpy.types.Image`" -); -static PyObject *bpy_bmtexpoly_image_get(BPy_BMTexPoly *self, void *UNUSED(closure)) -{ - return pyrna_id_CreatePyObject((ID *)self->data->tpage); -} - -static int bpy_bmtexpoly_image_set(BPy_BMTexPoly *self, PyObject *value, void *UNUSED(closure)) -{ - ID *id; - - if (value == Py_None) { - id = NULL; - } - else if (pyrna_id_FromPyObject(value, &id) && id && GS(id->name) == ID_IM) { - /* pass */ - } - else { - PyErr_Format(PyExc_KeyError, "BMTexPoly.image = x" - "expected an image or None, not '%.200s'", - Py_TYPE(value)->tp_name); - return -1; - } - - id_lib_extern(id); - self->data->tpage = (struct Image *)id; - - return 0; -} - -static PyGetSetDef bpy_bmtexpoly_getseters[] = { - /* attributes match rna_def_mtpoly */ - {(char *)"image", (getter)bpy_bmtexpoly_image_get, (setter)bpy_bmtexpoly_image_set, (char *)bpy_bmtexpoly_image_doc, NULL}, - - {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ -}; - -static PyTypeObject BPy_BMTexPoly_Type; /* bm.loops.layers.uv.active */ - -static void bm_init_types_bmtexpoly(void) -{ - BPy_BMTexPoly_Type.tp_basicsize = sizeof(BPy_BMTexPoly); - - BPy_BMTexPoly_Type.tp_name = "BMTexPoly"; - - BPy_BMTexPoly_Type.tp_doc = NULL; // todo - - BPy_BMTexPoly_Type.tp_getset = bpy_bmtexpoly_getseters; - - BPy_BMTexPoly_Type.tp_flags = Py_TPFLAGS_DEFAULT; - - PyType_Ready(&BPy_BMTexPoly_Type); -} - -int BPy_BMTexPoly_AssignPyObject(struct MTexPoly *mtpoly, PyObject *value) -{ - if (UNLIKELY(!BPy_BMTexPoly_Check(value))) { - PyErr_Format(PyExc_TypeError, "expected BMTexPoly, not a %.200s", Py_TYPE(value)->tp_name); - return -1; - } - else { - *((MTexPoly *)mtpoly) = *(((BPy_BMTexPoly *)value)->data); - return 0; - } -} - -PyObject *BPy_BMTexPoly_CreatePyObject(struct MTexPoly *mtpoly) -{ - BPy_BMTexPoly *self = PyObject_New(BPy_BMTexPoly, &BPy_BMTexPoly_Type); - self->data = mtpoly; - return (PyObject *)self; -} - -/* --- End Mesh BMTexPoly --- */ - /* Mesh Loop UV * ************ */ @@ -797,7 +706,6 @@ PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert) /* call to init all types */ void BPy_BM_init_types_meshdata(void) { - bm_init_types_bmtexpoly(); bm_init_types_bmloopuv(); bm_init_types_bmloopcol(); bm_init_types_bmdvert(); diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.h b/source/blender/python/bmesh/bmesh_py_types_meshdata.h index 07d8a46cc65..c8ae2596f99 100644 --- a/source/blender/python/bmesh/bmesh_py_types_meshdata.h +++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.h @@ -40,15 +40,11 @@ typedef struct BPy_BMGenericMeshData { void *data; } BPy_BMGenericMeshData; -struct MTexPoly; struct MLoopUV; struct MLoopCol; struct MDeformVert; struct MVertSkin; -int BPy_BMTexPoly_AssignPyObject(struct MTexPoly *mloopuv, PyObject *value); -PyObject *BPy_BMTexPoly_CreatePyObject(struct MTexPoly *mloopuv); - int BPy_BMLoopUV_AssignPyObject(struct MLoopUV *data, PyObject *value); PyObject *BPy_BMLoopUV_CreatePyObject(struct MLoopUV *data); diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 7b9292827b0..07c0f81b7ca 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -37,6 +37,8 @@ #include "GPU_glew.h" #include "MEM_guardedalloc.h" +#include "../generic/py_capi_utils.h" + #include "bgl.h" @@ -185,11 +187,13 @@ #define GLbitfield_ref(num) &bgl_var##num #define GLbitfield_def(num) /* unsigned */ int GLbitfield_var(num) +#if 0 /* typedef signed char GLbyte; */ #define GLbyte_str "b" #define GLbyte_var(num) bgl_var##num #define GLbyte_ref(num) &bgl_var##num #define GLbyte_def(num) signed char GLbyte_var(num) +#endif /* typedef short GLshort; */ #define GLshort_str "h" @@ -227,11 +231,13 @@ #define GLubyte_ref(num) &bgl_var##num #define GLubyte_def(num) /* unsigned */ char GLubyte_var(num) +#if 0 /* typedef unsigned short GLushort; */ #define GLushort_str "H" #define GLushort_var(num) bgl_var##num #define GLushort_ref(num) &bgl_var##num #define GLushort_def(num) /* unsigned */ short GLushort_var(num) +#endif /* typedef unsigned int GLuint; */ #define GLuint_str "I" @@ -474,29 +480,21 @@ int BGL_typeSize(int type) static int gl_buffer_type_from_py_buffer(Py_buffer *pybuffer) { - char *typestr = pybuffer->format; + const char format = PyC_StructFmt_type_from_str(pybuffer->format); Py_ssize_t itemsize = pybuffer->itemsize; - if (ELEM(typestr[0], '<', '>', '|')) { - typestr += 1; + if (PyC_StructFmt_type_is_float_any(format)) { + if (itemsize == 4) return GL_FLOAT; + if (itemsize == 8) return GL_DOUBLE; } - - switch (typestr[0]) { - case 't': - case 'b': - case 'h': - case 'i': - case 'l': - if (itemsize == 1) return GL_BYTE; - if (itemsize == 2) return GL_SHORT; - if (itemsize == 4) return GL_INT; - break; - case 'f': - case 'd': - if (itemsize == 4) return GL_FLOAT; - if (itemsize == 8) return GL_DOUBLE; - break; + if (PyC_StructFmt_type_is_byte(format) || + PyC_StructFmt_type_is_int_any(format)) + { + if (itemsize == 1) return GL_BYTE; + if (itemsize == 2) return GL_SHORT; + if (itemsize == 4) return GL_INT; } + return -1; /* UNKNOWN */ } @@ -1073,616 +1071,266 @@ static PyObject *Method_##funcname (PyObject *UNUSED(self), PyObject *args) \ ret_ret_##ret; \ } -#define BGLU_Wrap(funcname, ret, arg_list) \ -static PyObject *Method_##funcname (PyObject *UNUSED(self), PyObject *args) \ -{ \ - arg_def arg_list; \ - ret_def_##ret; \ - if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \ - return NULL; \ - } \ - ret_set_##ret glu##funcname (arg_var arg_list); \ - ret_ret_##ret; \ -} - /* GL_VERSION_1_0 */ -BGL_Wrap(Accum, void, (GLenum, GLfloat)) -BGL_Wrap(AlphaFunc, void, (GLenum, GLfloat)) -BGL_Wrap(Begin, void, (GLenum)) -BGL_Wrap(Bitmap, void, (GLsizei, GLsizei, GLfloat, GLfloat, GLfloat, GLfloat, GLubyteP)) -BGL_Wrap(BlendFunc, void, (GLenum, GLenum)) -BGL_Wrap(CallList, void, (GLuint)) -BGL_Wrap(CallLists, void, (GLsizei, GLenum, GLvoidP)) -BGL_Wrap(Clear, void, (GLbitfield)) -BGL_Wrap(ClearAccum, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(ClearColor, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(ClearDepth, void, (GLdouble)) -BGL_Wrap(ClearIndex, void, (GLfloat)) -BGL_Wrap(ClearStencil, void, (GLint)) -BGL_Wrap(ClipPlane, void, (GLenum, GLdoubleP)) -BGL_Wrap(Color3b, void, (GLbyte, GLbyte, GLbyte)) -BGL_Wrap(Color3bv, void, (GLbyteP)) -BGL_Wrap(Color3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Color3dv, void, (GLdoubleP)) -BGL_Wrap(Color3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Color3fv, void, (GLfloatP)) -BGL_Wrap(Color3i, void, (GLint, GLint, GLint)) -BGL_Wrap(Color3iv, void, (GLintP)) -BGL_Wrap(Color3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(Color3sv, void, (GLshortP)) -BGL_Wrap(Color3ub, void, (GLubyte, GLubyte, GLubyte)) -BGL_Wrap(Color3ubv, void, (GLubyteP)) -BGL_Wrap(Color3ui, void, (GLuint, GLuint, GLuint)) -BGL_Wrap(Color3uiv, void, (GLuintP)) -BGL_Wrap(Color3us, void, (GLushort, GLushort, GLushort)) -BGL_Wrap(Color3usv, void, (GLushortP)) -BGL_Wrap(Color4b, void, (GLbyte, GLbyte, GLbyte, GLbyte)) -BGL_Wrap(Color4bv, void, (GLbyteP)) -BGL_Wrap(Color4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Color4dv, void, (GLdoubleP)) -BGL_Wrap(Color4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Color4fv, void, (GLfloatP)) -BGL_Wrap(Color4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(Color4iv, void, (GLintP)) -BGL_Wrap(Color4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(Color4sv, void, (GLshortP)) -BGL_Wrap(Color4ub, void, (GLubyte, GLubyte, GLubyte, GLubyte)) -BGL_Wrap(Color4ubv, void, (GLubyteP)) -BGL_Wrap(Color4ui, void, (GLuint, GLuint, GLuint, GLuint)) -BGL_Wrap(Color4uiv, void, (GLuintP)) -BGL_Wrap(Color4us, void, (GLushort, GLushort, GLushort, GLushort)) -BGL_Wrap(Color4usv, void, (GLushortP)) -BGL_Wrap(ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean)) -BGL_Wrap(ColorMaterial, void, (GLenum, GLenum)) -BGL_Wrap(CopyPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum)) -BGL_Wrap(CullFace, void, (GLenum)) -BGL_Wrap(DeleteLists, void, (GLuint, GLsizei)) -BGL_Wrap(DepthFunc, void, (GLenum)) -BGL_Wrap(DepthMask, void, (GLboolean)) -BGL_Wrap(DepthRange, void, (GLdouble, GLdouble)) -BGL_Wrap(Disable, void, (GLenum)) -BGL_Wrap(DrawBuffer, void, (GLenum)) -BGL_Wrap(DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP)) -BGL_Wrap(EdgeFlag, void, (GLboolean)) -BGL_Wrap(EdgeFlagv, void, (GLbooleanP)) -BGL_Wrap(Enable, void, (GLenum)) -BGL_Wrap(End, void, (void)) -BGL_Wrap(EndList, void, (void)) -BGL_Wrap(EvalCoord1d, void, (GLdouble)) -BGL_Wrap(EvalCoord1dv, void, (GLdoubleP)) -BGL_Wrap(EvalCoord1f, void, (GLfloat)) -BGL_Wrap(EvalCoord1fv, void, (GLfloatP)) -BGL_Wrap(EvalCoord2d, void, (GLdouble, GLdouble)) -BGL_Wrap(EvalCoord2dv, void, (GLdoubleP)) -BGL_Wrap(EvalCoord2f, void, (GLfloat, GLfloat)) -BGL_Wrap(EvalCoord2fv, void, (GLfloatP)) -BGL_Wrap(EvalMesh1, void, (GLenum, GLint, GLint)) -BGL_Wrap(EvalMesh2, void, (GLenum, GLint, GLint, GLint, GLint)) -BGL_Wrap(EvalPoint1, void, (GLint)) -BGL_Wrap(EvalPoint2, void, (GLint, GLint)) -BGL_Wrap(FeedbackBuffer, void, (GLsizei, GLenum, GLfloatP)) -BGL_Wrap(Finish, void, (void)) -BGL_Wrap(Flush, void, (void)) -BGL_Wrap(Fogf, void, (GLenum, GLfloat)) -BGL_Wrap(Fogfv, void, (GLenum, GLfloatP)) -BGL_Wrap(Fogi, void, (GLenum, GLint)) -BGL_Wrap(Fogiv, void, (GLenum, GLintP)) -BGL_Wrap(FrontFace, void, (GLenum)) -BGL_Wrap(Frustum, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(GenLists, GLuint, (GLsizei)) -BGL_Wrap(GetBooleanv, void, (GLenum, GLbooleanP)) -BGL_Wrap(GetClipPlane, void, (GLenum, GLdoubleP)) -BGL_Wrap(GetDoublev, void, (GLenum, GLdoubleP)) -BGL_Wrap(GetError, GLenum, (void)) -BGL_Wrap(GetFloatv, void, (GLenum, GLfloatP)) -BGL_Wrap(GetIntegerv, void, (GLenum, GLintP)) -BGL_Wrap(GetLightfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(GetLightiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(GetMapdv, void, (GLenum, GLenum, GLdoubleP)) -BGL_Wrap(GetMapfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(GetMapiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(GetMaterialfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(GetMaterialiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(GetPixelMapfv, void, (GLenum, GLfloatP)) -BGL_Wrap(GetPixelMapuiv, void, (GLenum, GLuintP)) -BGL_Wrap(GetPixelMapusv, void, (GLenum, GLushortP)) -BGL_Wrap(GetPolygonStipple, void, (GLubyteP)) -BGL_Wrap(GetString, GLstring, (GLenum)) -BGL_Wrap(GetTexEnvfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(GetTexEnviv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(GetTexGendv, void, (GLenum, GLenum, GLdoubleP)) -BGL_Wrap(GetTexGenfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(GetTexGeniv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP)) -BGL_Wrap(GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP)) -BGL_Wrap(GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP)) -BGL_Wrap(GetTexParameterfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(GetTexParameteriv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(Hint, void, (GLenum, GLenum)) -BGL_Wrap(IndexMask, void, (GLuint)) -BGL_Wrap(Indexd, void, (GLdouble)) -BGL_Wrap(Indexdv, void, (GLdoubleP)) -BGL_Wrap(Indexf, void, (GLfloat)) -BGL_Wrap(Indexfv, void, (GLfloatP)) -BGL_Wrap(Indexi, void, (GLint)) -BGL_Wrap(Indexiv, void, (GLintP)) -BGL_Wrap(Indexs, void, (GLshort)) -BGL_Wrap(Indexsv, void, (GLshortP)) -BGL_Wrap(InitNames, void, (void)) -BGL_Wrap(IsEnabled, GLboolean, (GLenum)) -BGL_Wrap(IsList, GLboolean, (GLuint)) -BGL_Wrap(LightModelf, void, (GLenum, GLfloat)) -BGL_Wrap(LightModelfv, void, (GLenum, GLfloatP)) -BGL_Wrap(LightModeli, void, (GLenum, GLint)) -BGL_Wrap(LightModeliv, void, (GLenum, GLintP)) -BGL_Wrap(Lightf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(Lightfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(Lighti, void, (GLenum, GLenum, GLint)) -BGL_Wrap(Lightiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(LineStipple, void, (GLint, GLushort)) -BGL_Wrap(LineWidth, void, (GLfloat)) -BGL_Wrap(ListBase, void, (GLuint)) -BGL_Wrap(LoadIdentity, void, (void)) -BGL_Wrap(LoadMatrixd, void, (GLdoubleP)) -BGL_Wrap(LoadMatrixf, void, (GLfloatP)) -BGL_Wrap(LoadName, void, (GLuint)) -BGL_Wrap(LogicOp, void, (GLenum)) -BGL_Wrap(Map1d, void, (GLenum, GLdouble, GLdouble, GLint, GLint, GLdoubleP)) -BGL_Wrap(Map1f, void, (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloatP)) -BGL_Wrap(Map2d, void, (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdoubleP)) -BGL_Wrap(Map2f, void, (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloatP)) -BGL_Wrap(MapGrid1d, void, (GLint, GLdouble, GLdouble)) -BGL_Wrap(MapGrid1f, void, (GLint, GLfloat, GLfloat)) -BGL_Wrap(MapGrid2d, void, (GLint, GLdouble, GLdouble, GLint, GLdouble, GLdouble)) -BGL_Wrap(MapGrid2f, void, (GLint, GLfloat, GLfloat, GLint, GLfloat, GLfloat)) -BGL_Wrap(Materialf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(Materialfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(Materiali, void, (GLenum, GLenum, GLint)) -BGL_Wrap(Materialiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(MatrixMode, void, (GLenum)) -BGL_Wrap(MultMatrixd, void, (GLdoubleP)) -BGL_Wrap(MultMatrixf, void, (GLfloatP)) -BGL_Wrap(NewList, void, (GLuint, GLenum)) -BGL_Wrap(Normal3b, void, (GLbyte, GLbyte, GLbyte)) -BGL_Wrap(Normal3bv, void, (GLbyteP)) -BGL_Wrap(Normal3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Normal3dv, void, (GLdoubleP)) -BGL_Wrap(Normal3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Normal3fv, void, (GLfloatP)) -BGL_Wrap(Normal3i, void, (GLint, GLint, GLint)) -BGL_Wrap(Normal3iv, void, (GLintP)) -BGL_Wrap(Normal3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(Normal3sv, void, (GLshortP)) -BGL_Wrap(Ortho, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(PassThrough, void, (GLfloat)) -BGL_Wrap(PixelMapfv, void, (GLenum, GLsizei, GLfloatP)) -BGL_Wrap(PixelMapuiv, void, (GLenum, GLsizei, GLuintP)) -BGL_Wrap(PixelMapusv, void, (GLenum, GLsizei, GLushortP)) -BGL_Wrap(PixelStoref, void, (GLenum, GLfloat)) -BGL_Wrap(PixelStorei, void, (GLenum, GLint)) -BGL_Wrap(PixelTransferf, void, (GLenum, GLfloat)) -BGL_Wrap(PixelTransferi, void, (GLenum, GLint)) -BGL_Wrap(PixelZoom, void, (GLfloat, GLfloat)) -BGL_Wrap(PointSize, void, (GLfloat)) -BGL_Wrap(PolygonMode, void, (GLenum, GLenum)) -BGL_Wrap(PolygonStipple, void, (GLubyteP)) -BGL_Wrap(PopAttrib, void, (void)) -BGL_Wrap(PopMatrix, void, (void)) -BGL_Wrap(PopName, void, (void)) -BGL_Wrap(PushAttrib, void, (GLbitfield)) -BGL_Wrap(PushMatrix, void, (void)) -BGL_Wrap(PushName, void, (GLuint)) -BGL_Wrap(RasterPos2d, void, (GLdouble, GLdouble)) -BGL_Wrap(RasterPos2dv, void, (GLdoubleP)) -BGL_Wrap(RasterPos2f, void, (GLfloat, GLfloat)) -BGL_Wrap(RasterPos2fv, void, (GLfloatP)) -BGL_Wrap(RasterPos2i, void, (GLint, GLint)) -BGL_Wrap(RasterPos2iv, void, (GLintP)) -BGL_Wrap(RasterPos2s, void, (GLshort, GLshort)) -BGL_Wrap(RasterPos2sv, void, (GLshortP)) -BGL_Wrap(RasterPos3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(RasterPos3dv, void, (GLdoubleP)) -BGL_Wrap(RasterPos3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(RasterPos3fv, void, (GLfloatP)) -BGL_Wrap(RasterPos3i, void, (GLint, GLint, GLint)) -BGL_Wrap(RasterPos3iv, void, (GLintP)) -BGL_Wrap(RasterPos3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(RasterPos3sv, void, (GLshortP)) -BGL_Wrap(RasterPos4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(RasterPos4dv, void, (GLdoubleP)) -BGL_Wrap(RasterPos4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(RasterPos4fv, void, (GLfloatP)) -BGL_Wrap(RasterPos4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(RasterPos4iv, void, (GLintP)) -BGL_Wrap(RasterPos4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(RasterPos4sv, void, (GLshortP)) -BGL_Wrap(ReadBuffer, void, (GLenum)) -BGL_Wrap(ReadPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoidP)) -BGL_Wrap(Rectd, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Rectdv, void, (GLdoubleP, GLdoubleP)) -BGL_Wrap(Rectf, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Rectfv, void, (GLfloatP, GLfloatP)) -BGL_Wrap(Recti, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(Rectiv, void, (GLintP, GLintP)) -BGL_Wrap(Rects, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(Rectsv, void, (GLshortP, GLshortP)) -BGL_Wrap(RenderMode, GLint, (GLenum)) -BGL_Wrap(Rotated, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Rotatef, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Scaled, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Scalef, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Scissor, void, (GLint, GLint, GLsizei, GLsizei)) -BGL_Wrap(SelectBuffer, void, (GLsizei, GLuintP)) -BGL_Wrap(ShadeModel, void, (GLenum)) -BGL_Wrap(StencilFunc, void, (GLenum, GLint, GLuint)) -BGL_Wrap(StencilMask, void, (GLuint)) -BGL_Wrap(StencilOp, void, (GLenum, GLenum, GLenum)) -BGL_Wrap(TexCoord1d, void, (GLdouble)) -BGL_Wrap(TexCoord1dv, void, (GLdoubleP)) -BGL_Wrap(TexCoord1f, void, (GLfloat)) -BGL_Wrap(TexCoord1fv, void, (GLfloatP)) -BGL_Wrap(TexCoord1i, void, (GLint)) -BGL_Wrap(TexCoord1iv, void, (GLintP)) -BGL_Wrap(TexCoord1s, void, (GLshort)) -BGL_Wrap(TexCoord1sv, void, (GLshortP)) -BGL_Wrap(TexCoord2d, void, (GLdouble, GLdouble)) -BGL_Wrap(TexCoord2dv, void, (GLdoubleP)) -BGL_Wrap(TexCoord2f, void, (GLfloat, GLfloat)) -BGL_Wrap(TexCoord2fv, void, (GLfloatP)) -BGL_Wrap(TexCoord2i, void, (GLint, GLint)) -BGL_Wrap(TexCoord2iv, void, (GLintP)) -BGL_Wrap(TexCoord2s, void, (GLshort, GLshort)) -BGL_Wrap(TexCoord2sv, void, (GLshortP)) -BGL_Wrap(TexCoord3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(TexCoord3dv, void, (GLdoubleP)) -BGL_Wrap(TexCoord3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(TexCoord3fv, void, (GLfloatP)) -BGL_Wrap(TexCoord3i, void, (GLint, GLint, GLint)) -BGL_Wrap(TexCoord3iv, void, (GLintP)) -BGL_Wrap(TexCoord3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(TexCoord3sv, void, (GLshortP)) -BGL_Wrap(TexCoord4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(TexCoord4dv, void, (GLdoubleP)) -BGL_Wrap(TexCoord4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(TexCoord4fv, void, (GLfloatP)) -BGL_Wrap(TexCoord4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(TexCoord4iv, void, (GLintP)) -BGL_Wrap(TexCoord4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(TexCoord4sv, void, (GLshortP)) -BGL_Wrap(TexEnvf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(TexEnvfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(TexEnvi, void, (GLenum, GLenum, GLint)) -BGL_Wrap(TexEnviv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(TexGend, void, (GLenum, GLenum, GLdouble)) -BGL_Wrap(TexGendv, void, (GLenum, GLenum, GLdoubleP)) -BGL_Wrap(TexGenf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(TexGenfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(TexGeni, void, (GLenum, GLenum, GLint)) -BGL_Wrap(TexGeniv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(TexImage1D, void, (GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, GLvoidP)) -BGL_Wrap(TexImage2D, void, (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP)) -BGL_Wrap(TexParameterf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(TexParameterfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(TexParameteri, void, (GLenum, GLenum, GLint)) -BGL_Wrap(TexParameteriv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(Translated, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Translatef, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Vertex2d, void, (GLdouble, GLdouble)) -BGL_Wrap(Vertex2dv, void, (GLdoubleP)) -BGL_Wrap(Vertex2f, void, (GLfloat, GLfloat)) -BGL_Wrap(Vertex2fv, void, (GLfloatP)) -BGL_Wrap(Vertex2i, void, (GLint, GLint)) -BGL_Wrap(Vertex2iv, void, (GLintP)) -BGL_Wrap(Vertex2s, void, (GLshort, GLshort)) -BGL_Wrap(Vertex2sv, void, (GLshortP)) -BGL_Wrap(Vertex3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Vertex3dv, void, (GLdoubleP)) -BGL_Wrap(Vertex3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Vertex3fv, void, (GLfloatP)) -BGL_Wrap(Vertex3i, void, (GLint, GLint, GLint)) -BGL_Wrap(Vertex3iv, void, (GLintP)) -BGL_Wrap(Vertex3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(Vertex3sv, void, (GLshortP)) -BGL_Wrap(Vertex4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(Vertex4dv, void, (GLdoubleP)) -BGL_Wrap(Vertex4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Vertex4fv, void, (GLfloatP)) -BGL_Wrap(Vertex4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(Vertex4iv, void, (GLintP)) -BGL_Wrap(Vertex4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(Vertex4sv, void, (GLshortP)) -BGL_Wrap(Viewport, void, (GLint, GLint, GLsizei, GLsizei)) +BGL_Wrap(BlendFunc, void, (GLenum, GLenum)); +BGL_Wrap(Clear, void, (GLbitfield)); +BGL_Wrap(ClearColor, void, (GLfloat, GLfloat, GLfloat, GLfloat)); +BGL_Wrap(ClearDepth, void, (GLdouble)); +BGL_Wrap(ClearStencil, void, (GLint)); +BGL_Wrap(ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean)); +BGL_Wrap(CullFace, void, (GLenum)); +BGL_Wrap(DepthFunc, void, (GLenum)); +BGL_Wrap(DepthMask, void, (GLboolean)); +BGL_Wrap(DepthRange, void, (GLdouble, GLdouble)); +BGL_Wrap(Disable, void, (GLenum)); +BGL_Wrap(DrawBuffer, void, (GLenum)); +BGL_Wrap(Enable, void, (GLenum)); +BGL_Wrap(Finish, void, (void)); +BGL_Wrap(Flush, void, (void)); +BGL_Wrap(FrontFace, void, (GLenum)); +BGL_Wrap(GetBooleanv, void, (GLenum, GLbooleanP)); +BGL_Wrap(GetDoublev, void, (GLenum, GLdoubleP)); +BGL_Wrap(GetError, GLenum, (void)); +BGL_Wrap(GetFloatv, void, (GLenum, GLfloatP)); +BGL_Wrap(GetIntegerv, void, (GLenum, GLintP)); +BGL_Wrap(GetString, GLstring, (GLenum)); +BGL_Wrap(GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP)); +BGL_Wrap(GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP)); +BGL_Wrap(GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP)); +BGL_Wrap(GetTexParameterfv, void, (GLenum, GLenum, GLfloatP)); +BGL_Wrap(GetTexParameteriv, void, (GLenum, GLenum, GLintP)); +BGL_Wrap(Hint, void, (GLenum, GLenum)); +BGL_Wrap(IsEnabled, GLboolean, (GLenum)); +BGL_Wrap(LineWidth, void, (GLfloat)); +BGL_Wrap(LogicOp, void, (GLenum)); +BGL_Wrap(PixelStoref, void, (GLenum, GLfloat)); +BGL_Wrap(PixelStorei, void, (GLenum, GLint)); +BGL_Wrap(PointSize, void, (GLfloat)); +BGL_Wrap(PolygonMode, void, (GLenum, GLenum)); +BGL_Wrap(ReadBuffer, void, (GLenum)); +BGL_Wrap(ReadPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoidP)); +BGL_Wrap(Scissor, void, (GLint, GLint, GLsizei, GLsizei)); +BGL_Wrap(StencilFunc, void, (GLenum, GLint, GLuint)); +BGL_Wrap(StencilMask, void, (GLuint)); +BGL_Wrap(StencilOp, void, (GLenum, GLenum, GLenum)); +BGL_Wrap(TexImage1D, void, (GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, GLvoidP)); +BGL_Wrap(TexImage2D, void, (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP)); +BGL_Wrap(TexParameterf, void, (GLenum, GLenum, GLfloat)); +BGL_Wrap(TexParameterfv, void, (GLenum, GLenum, GLfloatP)); +BGL_Wrap(TexParameteri, void, (GLenum, GLenum, GLint)); +BGL_Wrap(TexParameteriv, void, (GLenum, GLenum, GLintP)); +BGL_Wrap(Viewport, void, (GLint, GLint, GLsizei, GLsizei)); /* GL_VERSION_1_1 */ -BGL_Wrap(AreTexturesResident, GLboolean, (GLsizei, GLuintP, GLbooleanP)) -BGL_Wrap(ArrayElement, void, (GLint)) -BGL_Wrap(BindTexture, void, (GLenum, GLuint)) -BGL_Wrap(ColorPointer, void, (GLint, GLenum, GLsizei, GLvoidP)) -BGL_Wrap(CopyTexImage1D, void, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint)) -BGL_Wrap(CopyTexImage2D, void, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)) -BGL_Wrap(CopyTexSubImage1D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei)) -BGL_Wrap(CopyTexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) -BGL_Wrap(DeleteTextures, void, (GLsizei, GLuintP)) -BGL_Wrap(DisableClientState, void, (GLenum)) -BGL_Wrap(DrawArrays, void, (GLenum, GLint, GLsizei)) -BGL_Wrap(DrawElements, void, (GLenum, GLsizei, GLenum, GLvoidP)) -BGL_Wrap(EdgeFlagPointer, void, (GLsizei, GLvoidP)) -BGL_Wrap(EnableClientState, void, (GLenum)) -BGL_Wrap(GenTextures, void, (GLsizei, GLuintP)) -BGL_Wrap(GetPointerv, void, (GLenum, GLvoidP)) -BGL_Wrap(IndexPointer, void, (GLenum, GLsizei, GLvoidP)) -BGL_Wrap(Indexub, void, (GLubyte)) -BGL_Wrap(Indexubv, void, (GLubyteP)) -BGL_Wrap(InterleavedArrays, void, (GLenum, GLsizei, GLvoidP)) -BGL_Wrap(IsTexture, GLboolean, (GLuint)) -BGL_Wrap(NormalPointer, void, (GLenum, GLsizei, GLvoidP)) -BGL_Wrap(PolygonOffset, void, (GLfloat, GLfloat)) -BGL_Wrap(PopClientAttrib, void, (void)) -BGL_Wrap(PrioritizeTextures, void, (GLsizei, GLuintP, GLfloatP)) -BGL_Wrap(PushClientAttrib, void, (GLbitfield)) -BGL_Wrap(TexCoordPointer, void, (GLint, GLenum, GLsizei, GLvoidP)) -BGL_Wrap(TexSubImage1D, void, (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, GLvoidP)) -BGL_Wrap(TexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoidP)) -BGL_Wrap(VertexPointer, void, (GLint, GLenum, GLsizei, GLvoidP)) +BGL_Wrap(BindTexture, void, (GLenum, GLuint)); +BGL_Wrap(CopyTexImage1D, void, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint)); +BGL_Wrap(CopyTexImage2D, void, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)); +BGL_Wrap(CopyTexSubImage1D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei)); +BGL_Wrap(CopyTexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)); +BGL_Wrap(DeleteTextures, void, (GLsizei, GLuintP)); +BGL_Wrap(DrawArrays, void, (GLenum, GLint, GLsizei)); +BGL_Wrap(DrawElements, void, (GLenum, GLsizei, GLenum, GLvoidP)); +BGL_Wrap(GenTextures, void, (GLsizei, GLuintP)); +BGL_Wrap(IsTexture, GLboolean, (GLuint)); +BGL_Wrap(PolygonOffset, void, (GLfloat, GLfloat)); +BGL_Wrap(TexSubImage1D, void, (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, GLvoidP)); +BGL_Wrap(TexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoidP)); /* GL_VERSION_1_2 */ -BGL_Wrap(CopyTexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)) -BGL_Wrap(DrawRangeElements, void, (GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoidP)) -BGL_Wrap(TexImage3D, void, (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP)) -BGL_Wrap(TexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, GLvoidP)) +BGL_Wrap(CopyTexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)); +BGL_Wrap(DrawRangeElements, void, (GLenum, GLuint, GLuint, GLsizei, GLenum, GLvoidP)); +BGL_Wrap(TexImage3D, void, (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP)); +BGL_Wrap(TexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, GLvoidP)); /* GL_VERSION_1_3 */ -BGL_Wrap(ActiveTexture, void, (GLenum)) -BGL_Wrap(ClientActiveTexture, void, (GLenum)) -BGL_Wrap(CompressedTexImage1D, void, (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, GLvoidP)) -BGL_Wrap(CompressedTexImage2D, void, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, GLvoidP)) -BGL_Wrap(CompressedTexImage3D, void, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, GLvoidP)) -BGL_Wrap(CompressedTexSubImage1D, void, (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, GLvoidP)) -BGL_Wrap(CompressedTexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, GLvoidP)) -BGL_Wrap(CompressedTexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, GLvoidP)) -BGL_Wrap(GetCompressedTexImage, void, (GLenum, GLint, GLvoidP)) -BGL_Wrap(LoadTransposeMatrixd, void, (GLdoubleP)) -BGL_Wrap(LoadTransposeMatrixf, void, (GLfloatP)) -BGL_Wrap(MultTransposeMatrixd, void, (GLdoubleP)) -BGL_Wrap(MultTransposeMatrixf, void, (GLfloatP)) -BGL_Wrap(MultiTexCoord1d, void, (GLenum, GLdouble)) -BGL_Wrap(MultiTexCoord1dv, void, (GLenum, GLdoubleP)) -BGL_Wrap(MultiTexCoord1f, void, (GLenum, GLfloat)) -BGL_Wrap(MultiTexCoord1fv, void, (GLenum, GLfloatP)) -BGL_Wrap(MultiTexCoord1i, void, (GLenum, GLint)) -BGL_Wrap(MultiTexCoord1iv, void, (GLenum, GLintP)) -BGL_Wrap(MultiTexCoord1s, void, (GLenum, GLshort)) -BGL_Wrap(MultiTexCoord1sv, void, (GLenum, GLshortP)) -BGL_Wrap(MultiTexCoord2d, void, (GLenum, GLdouble, GLdouble)) -BGL_Wrap(MultiTexCoord2dv, void, (GLenum, GLdoubleP)) -BGL_Wrap(MultiTexCoord2f, void, (GLenum, GLfloat, GLfloat)) -BGL_Wrap(MultiTexCoord2fv, void, (GLenum, GLfloatP)) -BGL_Wrap(MultiTexCoord2i, void, (GLenum, GLint, GLint)) -BGL_Wrap(MultiTexCoord2iv, void, (GLenum, GLintP)) -BGL_Wrap(MultiTexCoord2s, void, (GLenum, GLshort, GLshort)) -BGL_Wrap(MultiTexCoord2sv, void, (GLenum, GLshortP)) -BGL_Wrap(MultiTexCoord3d, void, (GLenum, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(MultiTexCoord3dv, void, (GLenum, GLdoubleP)) -BGL_Wrap(MultiTexCoord3f, void, (GLenum, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(MultiTexCoord3fv, void, (GLenum, GLfloatP)) -BGL_Wrap(MultiTexCoord3i, void, (GLenum, GLint, GLint, GLint)) -BGL_Wrap(MultiTexCoord3iv, void, (GLenum, GLintP)) -BGL_Wrap(MultiTexCoord3s, void, (GLenum, GLshort, GLshort, GLshort)) -BGL_Wrap(MultiTexCoord3sv, void, (GLenum, GLshortP)) -BGL_Wrap(MultiTexCoord4d, void, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(MultiTexCoord4dv, void, (GLenum, GLdoubleP)) -BGL_Wrap(MultiTexCoord4f, void, (GLenum, GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(MultiTexCoord4fv, void, (GLenum, GLfloatP)) -BGL_Wrap(MultiTexCoord4i, void, (GLenum, GLint, GLint, GLint, GLint)) -BGL_Wrap(MultiTexCoord4iv, void, (GLenum, GLintP)) -BGL_Wrap(MultiTexCoord4s, void, (GLenum, GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(MultiTexCoord4sv, void, (GLenum, GLshortP)) -BGL_Wrap(SampleCoverage, void, (GLfloat, GLboolean)) +BGL_Wrap(ActiveTexture, void, (GLenum)); +BGL_Wrap(CompressedTexImage1D, void, (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, GLvoidP)); +BGL_Wrap(CompressedTexImage2D, void, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, GLvoidP)); +BGL_Wrap(CompressedTexImage3D, void, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, GLvoidP)); +BGL_Wrap(CompressedTexSubImage1D, void, (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, GLvoidP)); +BGL_Wrap(CompressedTexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, GLvoidP)); +BGL_Wrap(CompressedTexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, GLvoidP)); +BGL_Wrap(GetCompressedTexImage, void, (GLenum, GLint, GLvoidP)); +BGL_Wrap(SampleCoverage, void, (GLfloat, GLboolean)); /* GL_VERSION_1_4 */ -BGL_Wrap(BlendColor, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(BlendEquation, void, (GLenum)) +BGL_Wrap(BlendColor, void, (GLfloat, GLfloat, GLfloat, GLfloat)); +BGL_Wrap(BlendEquation, void, (GLenum)); /* GL_VERSION_1_5 */ -BGL_Wrap(BeginQuery, void, (GLenum, GLuint)) -BGL_Wrap(BindBuffer, void, (GLenum, GLuint)) -BGL_Wrap(BufferData, void, (GLenum, GLsizeiptr, GLvoidP, GLenum)) -BGL_Wrap(BufferSubData, void, (GLenum, GLintptr, GLsizeiptr, GLvoidP)) -BGL_Wrap(DeleteBuffers, void, (GLsizei, GLuintP)) -BGL_Wrap(DeleteQueries, void, (GLsizei, GLuintP)) -BGL_Wrap(EndQuery, void, (GLenum)) -BGL_Wrap(GenBuffers, void, (GLsizei, GLuintP)) -BGL_Wrap(GenQueries, void, (GLsizei, GLuintP)) -BGL_Wrap(GetBufferParameteriv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(GetBufferPointerv, void, (GLenum, GLenum, GLvoidP)) -BGL_Wrap(GetBufferSubData, void, (GLenum, GLintptr, GLsizeiptr, GLvoidP)) -BGL_Wrap(GetQueryObjectiv, void, (GLuint, GLenum, GLintP)) -BGL_Wrap(GetQueryObjectuiv, void, (GLuint, GLenum, GLuintP)) -BGL_Wrap(GetQueryiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(IsBuffer, GLboolean, (GLuint)) -BGL_Wrap(IsQuery, GLboolean, (GLuint)) -BGL_Wrap(MapBuffer, void, (GLenum, GLenum)) -BGL_Wrap(UnmapBuffer, GLboolean, (GLenum)) +BGL_Wrap(BeginQuery, void, (GLenum, GLuint)); +BGL_Wrap(BindBuffer, void, (GLenum, GLuint)); +BGL_Wrap(BufferData, void, (GLenum, GLsizeiptr, GLvoidP, GLenum)); +BGL_Wrap(BufferSubData, void, (GLenum, GLintptr, GLsizeiptr, GLvoidP)); +BGL_Wrap(DeleteBuffers, void, (GLsizei, GLuintP)); +BGL_Wrap(DeleteQueries, void, (GLsizei, GLuintP)); +BGL_Wrap(EndQuery, void, (GLenum)); +BGL_Wrap(GenBuffers, void, (GLsizei, GLuintP)); +BGL_Wrap(GenQueries, void, (GLsizei, GLuintP)); +BGL_Wrap(GetBufferParameteriv, void, (GLenum, GLenum, GLintP)); +BGL_Wrap(GetBufferPointerv, void, (GLenum, GLenum, GLvoidP)); +BGL_Wrap(GetBufferSubData, void, (GLenum, GLintptr, GLsizeiptr, GLvoidP)); +BGL_Wrap(GetQueryObjectiv, void, (GLuint, GLenum, GLintP)); +BGL_Wrap(GetQueryObjectuiv, void, (GLuint, GLenum, GLuintP)); +BGL_Wrap(GetQueryiv, void, (GLenum, GLenum, GLintP)); +BGL_Wrap(IsBuffer, GLboolean, (GLuint)); +BGL_Wrap(IsQuery, GLboolean, (GLuint)); +BGL_Wrap(MapBuffer, void, (GLenum, GLenum)); +BGL_Wrap(UnmapBuffer, GLboolean, (GLenum)); /* GL_VERSION_2_0 */ -BGL_Wrap(AttachShader, void, (GLuint, GLuint)) -BGL_Wrap(BindAttribLocation, void, (GLuint, GLuint, GLstring)) -BGL_Wrap(BlendEquationSeparate, void, (GLenum, GLenum)) -BGL_Wrap(CompileShader, void, (GLuint)) -BGL_Wrap(CreateProgram, GLuint, (void)) -BGL_Wrap(CreateShader, GLuint, (GLenum)) -BGL_Wrap(DeleteProgram, void, (GLuint)) -BGL_Wrap(DeleteShader, void, (GLuint)) -BGL_Wrap(DetachShader, void, (GLuint, GLuint)) -BGL_Wrap(DisableVertexAttribArray, void, (GLuint)) -BGL_Wrap(DrawBuffers, void, (GLsizei, GLenumP)) -BGL_Wrap(EnableVertexAttribArray, void, (GLuint)) -BGL_Wrap(GetActiveAttrib, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLintP, GLenumP, GLcharP)) -BGL_Wrap(GetActiveUniform, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLintP, GLenumP, GLcharP)) -BGL_Wrap(GetAttachedShaders, void, (GLuint, GLsizei, GLsizeiP, GLuintP)) -BGL_Wrap(GetAttribLocation, GLint, (GLuint, GLstring)) -BGL_Wrap(GetProgramInfoLog, void, (GLuint, GLsizei, GLsizeiP, GLcharP)) -BGL_Wrap(GetProgramiv, void, (GLuint, GLenum, GLintP)) -BGL_Wrap(GetShaderInfoLog, void, (GLuint, GLsizei, GLsizeiP, GLcharP)) -BGL_Wrap(GetShaderSource, void, (GLuint, GLsizei, GLsizeiP, GLcharP)) -BGL_Wrap(GetShaderiv, void, (GLuint, GLenum, GLintP)) -BGL_Wrap(GetUniformLocation, GLint, (GLuint, GLstring)) -BGL_Wrap(GetUniformfv, void, (GLuint, GLint, GLfloatP)) -BGL_Wrap(GetUniformiv, void, (GLuint, GLint, GLintP)) -BGL_Wrap(GetVertexAttribPointerv, void, (GLuint, GLenum, GLvoidP)) -BGL_Wrap(GetVertexAttribdv, void, (GLuint, GLenum, GLdoubleP)) -BGL_Wrap(GetVertexAttribfv, void, (GLuint, GLenum, GLfloatP)) -BGL_Wrap(GetVertexAttribiv, void, (GLuint, GLenum, GLintP)) -BGL_Wrap(IsProgram, GLboolean, (GLuint)) -BGL_Wrap(IsShader, GLboolean, (GLuint)) -BGL_Wrap(LinkProgram, void, (GLuint)) -BGL_Wrap(StencilFuncSeparate, void, (GLenum, GLenum, GLint, GLuint)) -BGL_Wrap(StencilMaskSeparate, void, (GLenum, GLuint)) -BGL_Wrap(StencilOpSeparate, void, (GLenum, GLenum, GLenum, GLenum)) -BGL_Wrap(Uniform1f, void, (GLint, GLfloat)) -BGL_Wrap(Uniform1fv, void, (GLint, GLsizei, GLfloatP)) -BGL_Wrap(Uniform1i, void, (GLint, GLint)) -BGL_Wrap(Uniform1iv, void, (GLint, GLsizei, GLintP)) -BGL_Wrap(Uniform2f, void, (GLint, GLfloat, GLfloat)) -BGL_Wrap(Uniform2fv, void, (GLint, GLsizei, GLfloatP)) -BGL_Wrap(Uniform2i, void, (GLint, GLint, GLint)) -BGL_Wrap(Uniform2iv, void, (GLint, GLsizei, GLintP)) -BGL_Wrap(Uniform3f, void, (GLint, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Uniform3fv, void, (GLint, GLsizei, GLfloatP)) -BGL_Wrap(Uniform3i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(Uniform3iv, void, (GLint, GLsizei, GLintP)) -BGL_Wrap(Uniform4f, void, (GLint, GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(Uniform4fv, void, (GLint, GLsizei, GLfloatP)) -BGL_Wrap(Uniform4i, void, (GLint, GLint, GLint, GLint, GLint)) -BGL_Wrap(Uniform4iv, void, (GLint, GLsizei, GLintP)) -BGL_Wrap(UniformMatrix2fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UniformMatrix3fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UniformMatrix4fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UseProgram, void, (GLuint)) -BGL_Wrap(ValidateProgram, void, (GLuint)) -BGL_Wrap(VertexAttrib1d, void, (GLuint, GLdouble)) -BGL_Wrap(VertexAttrib1dv, void, (GLuint, GLdoubleP)) -BGL_Wrap(VertexAttrib1f, void, (GLuint, GLfloat)) -BGL_Wrap(VertexAttrib1fv, void, (GLuint, GLfloatP)) -BGL_Wrap(VertexAttrib1s, void, (GLuint, GLshort)) -BGL_Wrap(VertexAttrib1sv, void, (GLuint, GLshortP)) -BGL_Wrap(VertexAttrib2d, void, (GLuint, GLdouble, GLdouble)) -BGL_Wrap(VertexAttrib2dv, void, (GLuint, GLdoubleP)) -BGL_Wrap(VertexAttrib2f, void, (GLuint, GLfloat, GLfloat)) -BGL_Wrap(VertexAttrib2fv, void, (GLuint, GLfloatP)) -BGL_Wrap(VertexAttrib2s, void, (GLuint, GLshort, GLshort)) -BGL_Wrap(VertexAttrib2sv, void, (GLuint, GLshortP)) -BGL_Wrap(VertexAttrib3d, void, (GLuint, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(VertexAttrib3dv, void, (GLuint, GLdoubleP)) -BGL_Wrap(VertexAttrib3f, void, (GLuint, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(VertexAttrib3fv, void, (GLuint, GLfloatP)) -BGL_Wrap(VertexAttrib3s, void, (GLuint, GLshort, GLshort, GLshort)) -BGL_Wrap(VertexAttrib3sv, void, (GLuint, GLshortP)) -BGL_Wrap(VertexAttrib4Nbv, void, (GLuint, GLbyteP)) -BGL_Wrap(VertexAttrib4Niv, void, (GLuint, GLintP)) -BGL_Wrap(VertexAttrib4Nsv, void, (GLuint, GLshortP)) -BGL_Wrap(VertexAttrib4Nub, void, (GLuint, GLubyte, GLubyte, GLubyte, GLubyte)) -BGL_Wrap(VertexAttrib4Nubv, void, (GLuint, GLubyteP)) -BGL_Wrap(VertexAttrib4Nuiv, void, (GLuint, GLuintP)) -BGL_Wrap(VertexAttrib4Nusv, void, (GLuint, GLushortP)) -BGL_Wrap(VertexAttrib4bv, void, (GLuint, GLbyteP)) -BGL_Wrap(VertexAttrib4d, void, (GLuint, GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(VertexAttrib4dv, void, (GLuint, GLdoubleP)) -BGL_Wrap(VertexAttrib4f, void, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(VertexAttrib4fv, void, (GLuint, GLfloatP)) -BGL_Wrap(VertexAttrib4iv, void, (GLuint, GLintP)) -BGL_Wrap(VertexAttrib4s, void, (GLuint, GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(VertexAttrib4sv, void, (GLuint, GLshortP)) -BGL_Wrap(VertexAttrib4ubv, void, (GLuint, GLubyteP)) -BGL_Wrap(VertexAttrib4uiv, void, (GLuint, GLuintP)) -BGL_Wrap(VertexAttrib4usv, void, (GLuint, GLushortP)) -BGL_Wrap(VertexAttribPointer, void, (GLuint, GLint, GLenum, GLboolean, GLsizei, GLvoidP)) +BGL_Wrap(AttachShader, void, (GLuint, GLuint)); +BGL_Wrap(BindAttribLocation, void, (GLuint, GLuint, GLstring)); +BGL_Wrap(BlendEquationSeparate, void, (GLenum, GLenum)); +BGL_Wrap(CompileShader, void, (GLuint)); +BGL_Wrap(CreateProgram, GLuint, (void)); +BGL_Wrap(CreateShader, GLuint, (GLenum)); +BGL_Wrap(DeleteProgram, void, (GLuint)); +BGL_Wrap(DeleteShader, void, (GLuint)); +BGL_Wrap(DetachShader, void, (GLuint, GLuint)); +BGL_Wrap(DisableVertexAttribArray, void, (GLuint)); +BGL_Wrap(DrawBuffers, void, (GLsizei, GLenumP)); +BGL_Wrap(EnableVertexAttribArray, void, (GLuint)); +BGL_Wrap(GetActiveAttrib, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLintP, GLenumP, GLcharP)); +BGL_Wrap(GetActiveUniform, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLintP, GLenumP, GLcharP)); +BGL_Wrap(GetAttachedShaders, void, (GLuint, GLsizei, GLsizeiP, GLuintP)); +BGL_Wrap(GetAttribLocation, GLint, (GLuint, GLstring)); +BGL_Wrap(GetProgramInfoLog, void, (GLuint, GLsizei, GLsizeiP, GLcharP)); +BGL_Wrap(GetProgramiv, void, (GLuint, GLenum, GLintP)); +BGL_Wrap(GetShaderInfoLog, void, (GLuint, GLsizei, GLsizeiP, GLcharP)); +BGL_Wrap(GetShaderSource, void, (GLuint, GLsizei, GLsizeiP, GLcharP)); +BGL_Wrap(GetShaderiv, void, (GLuint, GLenum, GLintP)); +BGL_Wrap(GetUniformLocation, GLint, (GLuint, GLstring)); +BGL_Wrap(GetUniformfv, void, (GLuint, GLint, GLfloatP)); +BGL_Wrap(GetUniformiv, void, (GLuint, GLint, GLintP)); +BGL_Wrap(GetVertexAttribPointerv, void, (GLuint, GLenum, GLvoidP)); +BGL_Wrap(GetVertexAttribdv, void, (GLuint, GLenum, GLdoubleP)); +BGL_Wrap(GetVertexAttribfv, void, (GLuint, GLenum, GLfloatP)); +BGL_Wrap(GetVertexAttribiv, void, (GLuint, GLenum, GLintP)); +BGL_Wrap(IsProgram, GLboolean, (GLuint)); +BGL_Wrap(IsShader, GLboolean, (GLuint)); +BGL_Wrap(LinkProgram, void, (GLuint)); +BGL_Wrap(StencilFuncSeparate, void, (GLenum, GLenum, GLint, GLuint)); +BGL_Wrap(StencilMaskSeparate, void, (GLenum, GLuint)); +BGL_Wrap(StencilOpSeparate, void, (GLenum, GLenum, GLenum, GLenum)); +BGL_Wrap(Uniform1f, void, (GLint, GLfloat)); +BGL_Wrap(Uniform1fv, void, (GLint, GLsizei, GLfloatP)); +BGL_Wrap(Uniform1i, void, (GLint, GLint)); +BGL_Wrap(Uniform1iv, void, (GLint, GLsizei, GLintP)); +BGL_Wrap(Uniform2f, void, (GLint, GLfloat, GLfloat)); +BGL_Wrap(Uniform2fv, void, (GLint, GLsizei, GLfloatP)); +BGL_Wrap(Uniform2i, void, (GLint, GLint, GLint)); +BGL_Wrap(Uniform2iv, void, (GLint, GLsizei, GLintP)); +BGL_Wrap(Uniform3f, void, (GLint, GLfloat, GLfloat, GLfloat)); +BGL_Wrap(Uniform3fv, void, (GLint, GLsizei, GLfloatP)); +BGL_Wrap(Uniform3i, void, (GLint, GLint, GLint, GLint)); +BGL_Wrap(Uniform3iv, void, (GLint, GLsizei, GLintP)); +BGL_Wrap(Uniform4f, void, (GLint, GLfloat, GLfloat, GLfloat, GLfloat)); +BGL_Wrap(Uniform4fv, void, (GLint, GLsizei, GLfloatP)); +BGL_Wrap(Uniform4i, void, (GLint, GLint, GLint, GLint, GLint)); +BGL_Wrap(Uniform4iv, void, (GLint, GLsizei, GLintP)); +BGL_Wrap(UniformMatrix2fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UniformMatrix3fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UniformMatrix4fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UseProgram, void, (GLuint)); +BGL_Wrap(ValidateProgram, void, (GLuint)); +BGL_Wrap(VertexAttrib1d, void, (GLuint, GLdouble)); +BGL_Wrap(VertexAttrib1dv, void, (GLuint, GLdoubleP)); +BGL_Wrap(VertexAttrib1f, void, (GLuint, GLfloat)); +BGL_Wrap(VertexAttrib1fv, void, (GLuint, GLfloatP)); +BGL_Wrap(VertexAttrib1s, void, (GLuint, GLshort)); +BGL_Wrap(VertexAttrib1sv, void, (GLuint, GLshortP)); +BGL_Wrap(VertexAttrib2d, void, (GLuint, GLdouble, GLdouble)); +BGL_Wrap(VertexAttrib2dv, void, (GLuint, GLdoubleP)); +BGL_Wrap(VertexAttrib2f, void, (GLuint, GLfloat, GLfloat)); +BGL_Wrap(VertexAttrib2fv, void, (GLuint, GLfloatP)); +BGL_Wrap(VertexAttrib2s, void, (GLuint, GLshort, GLshort)); +BGL_Wrap(VertexAttrib2sv, void, (GLuint, GLshortP)); +BGL_Wrap(VertexAttrib3d, void, (GLuint, GLdouble, GLdouble, GLdouble)); +BGL_Wrap(VertexAttrib3dv, void, (GLuint, GLdoubleP)); +BGL_Wrap(VertexAttrib3f, void, (GLuint, GLfloat, GLfloat, GLfloat)); +BGL_Wrap(VertexAttrib3fv, void, (GLuint, GLfloatP)); +BGL_Wrap(VertexAttrib3s, void, (GLuint, GLshort, GLshort, GLshort)); +BGL_Wrap(VertexAttrib3sv, void, (GLuint, GLshortP)); +BGL_Wrap(VertexAttrib4Nbv, void, (GLuint, GLbyteP)); +BGL_Wrap(VertexAttrib4Niv, void, (GLuint, GLintP)); +BGL_Wrap(VertexAttrib4Nsv, void, (GLuint, GLshortP)); +BGL_Wrap(VertexAttrib4Nub, void, (GLuint, GLubyte, GLubyte, GLubyte, GLubyte)); +BGL_Wrap(VertexAttrib4Nubv, void, (GLuint, GLubyteP)); +BGL_Wrap(VertexAttrib4Nuiv, void, (GLuint, GLuintP)); +BGL_Wrap(VertexAttrib4Nusv, void, (GLuint, GLushortP)); +BGL_Wrap(VertexAttrib4bv, void, (GLuint, GLbyteP)); +BGL_Wrap(VertexAttrib4d, void, (GLuint, GLdouble, GLdouble, GLdouble, GLdouble)); +BGL_Wrap(VertexAttrib4dv, void, (GLuint, GLdoubleP)); +BGL_Wrap(VertexAttrib4f, void, (GLuint, GLfloat, GLfloat, GLfloat, GLfloat)); +BGL_Wrap(VertexAttrib4fv, void, (GLuint, GLfloatP)); +BGL_Wrap(VertexAttrib4iv, void, (GLuint, GLintP)); +BGL_Wrap(VertexAttrib4s, void, (GLuint, GLshort, GLshort, GLshort, GLshort)); +BGL_Wrap(VertexAttrib4sv, void, (GLuint, GLshortP)); +BGL_Wrap(VertexAttrib4ubv, void, (GLuint, GLubyteP)); +BGL_Wrap(VertexAttrib4uiv, void, (GLuint, GLuintP)); +BGL_Wrap(VertexAttrib4usv, void, (GLuint, GLushortP)); +BGL_Wrap(VertexAttribPointer, void, (GLuint, GLint, GLenum, GLboolean, GLsizei, GLvoidP)); /* GL_VERSION_2_1 */ -BGL_Wrap(UniformMatrix2x3fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UniformMatrix2x4fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UniformMatrix3x2fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UniformMatrix3x4fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UniformMatrix4x2fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) -BGL_Wrap(UniformMatrix4x3fv, void, (GLint, GLsizei, GLboolean, GLfloatP)) +BGL_Wrap(UniformMatrix2x3fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UniformMatrix2x4fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UniformMatrix3x2fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UniformMatrix3x4fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UniformMatrix4x2fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); +BGL_Wrap(UniformMatrix4x3fv, void, (GLint, GLsizei, GLboolean, GLfloatP)); /* GL_VERSION_3_0 */ -BGL_Wrap(BindVertexArray, void, (GLuint)) -BGL_Wrap(DeleteVertexArrays, void, (GLsizei, GLuintP)) -BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP)) -BGL_Wrap(IsVertexArray, GLboolean, (GLuint)) +BGL_Wrap(BindFramebuffer, void, (GLenum, GLuint)); +BGL_Wrap(BindRenderbuffer, void, (GLenum, GLuint)); +BGL_Wrap(BindVertexArray, void, (GLuint)); +BGL_Wrap(BlitFramebuffer, void, (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)); +BGL_Wrap(CheckFramebufferStatus, GLenum, (GLenum)); +BGL_Wrap(DeleteFramebuffers, void, (GLsizei, GLuintP)); +BGL_Wrap(DeleteRenderbuffers, void, (GLsizei, GLuintP)); +BGL_Wrap(DeleteVertexArrays, void, (GLsizei, GLuintP)); +BGL_Wrap(FramebufferRenderbuffer, void, (GLenum, GLenum, GLenum, GLuint)); +BGL_Wrap(GenFramebuffers, void, (GLsizei, GLuintP)); +BGL_Wrap(GenRenderbuffers, void, (GLsizei, GLuintP)); +BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP)); +BGL_Wrap(GetStringi, GLstring, (GLenum, GLuint)); +BGL_Wrap(IsVertexArray, GLboolean, (GLuint)); +BGL_Wrap(RenderbufferStorage, void, (GLenum, GLenum, GLsizei, GLsizei)); /* GL_VERSION_3_1 */ -BGL_Wrap(BindBufferBase, void, (GLenum, GLuint, GLuint)) -BGL_Wrap(BindBufferRange, void, (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr)) -BGL_Wrap(GetActiveUniformBlockName, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLcharP)) -BGL_Wrap(GetActiveUniformBlockiv, void, (GLuint, GLuint, GLenum, GLintP)) -BGL_Wrap(GetActiveUniformName, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLcharP)) -BGL_Wrap(GetActiveUniformsiv, void, (GLuint, GLsizei, GLuintP, GLenum, GLintP)) -BGL_Wrap(GetIntegeri_v, void, (GLenum, GLuint, GLintP)) -BGL_Wrap(GetUniformBlockIndex, GLuint, (GLuint, GLstring)) -BGL_Wrap(GetUniformIndices, void, (GLuint, GLsizei, GLcharP, GLuintP)) -BGL_Wrap(UniformBlockBinding, void, (GLuint, GLuint, GLuint)) +BGL_Wrap(BindBufferBase, void, (GLenum, GLuint, GLuint)); +BGL_Wrap(BindBufferRange, void, (GLenum, GLuint, GLuint, GLintptr, GLsizeiptr)); +BGL_Wrap(GetActiveUniformBlockName, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLcharP)); +BGL_Wrap(GetActiveUniformBlockiv, void, (GLuint, GLuint, GLenum, GLintP)); +BGL_Wrap(GetActiveUniformName, void, (GLuint, GLuint, GLsizei, GLsizeiP, GLcharP)); +BGL_Wrap(GetActiveUniformsiv, void, (GLuint, GLsizei, GLuintP, GLenum, GLintP)); +BGL_Wrap(GetIntegeri_v, void, (GLenum, GLuint, GLintP)); +BGL_Wrap(GetUniformBlockIndex, GLuint, (GLuint, GLstring)); +BGL_Wrap(GetUniformIndices, void, (GLuint, GLsizei, GLcharP, GLuintP)); +BGL_Wrap(UniformBlockBinding, void, (GLuint, GLuint, GLuint)); /* GL_VERSION_3_2 */ -BGL_Wrap(FramebufferTexture, void, (GLenum, GLenum, GLuint, GLint)) -BGL_Wrap(GetBufferParameteri64v, void, (GLenum, GLenum, GLint64P)) -BGL_Wrap(GetInteger64i_v, void, (GLenum, GLuint, GLint64P)) -BGL_Wrap(GetMultisamplefv, void, (GLenum, GLuint, GLfloatP)) -BGL_Wrap(SampleMaski, void, (GLuint, GLbitfield)) -BGL_Wrap(TexImage2DMultisample, void, (GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLboolean)) -BGL_Wrap(TexImage3DMultisample, void, (GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean)) +BGL_Wrap(FramebufferTexture, void, (GLenum, GLenum, GLuint, GLint)); +BGL_Wrap(GetBufferParameteri64v, void, (GLenum, GLenum, GLint64P)); +BGL_Wrap(GetInteger64i_v, void, (GLenum, GLuint, GLint64P)); +BGL_Wrap(GetMultisamplefv, void, (GLenum, GLuint, GLfloatP)); +BGL_Wrap(SampleMaski, void, (GLuint, GLbitfield)); +BGL_Wrap(TexImage2DMultisample, void, (GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLboolean)); +BGL_Wrap(TexImage3DMultisample, void, (GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean)); /* GL_VERSION_3_3 */ -BGL_Wrap(ColorP3ui, void, (GLenum, GLuint)) -BGL_Wrap(ColorP3uiv, void, (GLenum, GLuintP)) -BGL_Wrap(ColorP4ui, void, (GLenum, GLuint)) -BGL_Wrap(ColorP4uiv, void, (GLenum, GLuintP)) -BGL_Wrap(MultiTexCoordP1ui, void, (GLenum, GLenum, GLuint)) -BGL_Wrap(MultiTexCoordP1uiv, void, (GLenum, GLenum, GLuintP)) -BGL_Wrap(MultiTexCoordP2ui, void, (GLenum, GLenum, GLuint)) -BGL_Wrap(MultiTexCoordP2uiv, void, (GLenum, GLenum, GLuintP)) -BGL_Wrap(MultiTexCoordP3ui, void, (GLenum, GLenum, GLuint)) -BGL_Wrap(MultiTexCoordP3uiv, void, (GLenum, GLenum, GLuintP)) -BGL_Wrap(MultiTexCoordP4ui, void, (GLenum, GLenum, GLuint)) -BGL_Wrap(MultiTexCoordP4uiv, void, (GLenum, GLenum, GLuintP)) -BGL_Wrap(NormalP3ui, void, (GLenum, GLuint)) -BGL_Wrap(NormalP3uiv, void, (GLenum, GLuintP)) -BGL_Wrap(SecondaryColorP3ui, void, (GLenum, GLuint)) -BGL_Wrap(SecondaryColorP3uiv, void, (GLenum, GLuintP)) -BGL_Wrap(TexCoordP1ui, void, (GLenum, GLuint)) -BGL_Wrap(TexCoordP1uiv, void, (GLenum, GLuintP)) -BGL_Wrap(TexCoordP2ui, void, (GLenum, GLuint)) -BGL_Wrap(TexCoordP2uiv, void, (GLenum, GLuintP)) -BGL_Wrap(TexCoordP3ui, void, (GLenum, GLuint)) -BGL_Wrap(TexCoordP3uiv, void, (GLenum, GLuintP)) -BGL_Wrap(TexCoordP4ui, void, (GLenum, GLuint)) -BGL_Wrap(TexCoordP4uiv, void, (GLenum, GLuintP)) -BGL_Wrap(VertexP2ui, void, (GLenum, GLuint)) -BGL_Wrap(VertexP2uiv, void, (GLenum, GLuintP)) -BGL_Wrap(VertexP3ui, void, (GLenum, GLuint)) -BGL_Wrap(VertexP3uiv, void, (GLenum, GLuintP)) -BGL_Wrap(VertexP4ui, void, (GLenum, GLuint)) -BGL_Wrap(VertexP4uiv, void, (GLenum, GLuintP)) - - -BGLU_Wrap(Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGLU_Wrap(LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) -BGLU_Wrap(Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGLU_Wrap(PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP)) -BGLU_Wrap(Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) -BGLU_Wrap(UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) +/* no new functions besides packed immediate mode (not part of core profile) */ /** \} */ @@ -1692,26 +1340,12 @@ BGLU_Wrap(UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdouble /** \name Module Definition * \{ */ -#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, NULL} - -static struct PyMethodDef BGL_methods[] = { - MethodDefu(Perspective), - MethodDefu(LookAt), - MethodDefu(Ortho2D), - MethodDefu(PickMatrix), - MethodDefu(Project), - MethodDefu(UnProject), - {NULL, NULL, 0, NULL} -}; - -#undef MethodDefu - static struct PyModuleDef BGL_module_def = { PyModuleDef_HEAD_INIT, "bgl", /* m_name */ NULL, /* m_doc */ 0, /* m_size */ - BGL_methods, /* m_methods */ + NULL, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ @@ -1745,9 +1379,6 @@ static void py_module_dict_add_method(PyObject *submodule, PyObject *dict, PyMet } } -/* TODO, expose to users */ -static bool use_deprecated = true; - PyObject *BPyInit_bgl(void) { PyObject *submodule, *dict; @@ -1822,268 +1453,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexParameteriv); PY_MOD_ADD_METHOD(Viewport); } - /* adding in GL_VERSION_1_0 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(Accum); - PY_MOD_ADD_METHOD(AlphaFunc); - PY_MOD_ADD_METHOD(Begin); - PY_MOD_ADD_METHOD(Bitmap); - PY_MOD_ADD_METHOD(CallList); - PY_MOD_ADD_METHOD(CallLists); - PY_MOD_ADD_METHOD(ClearAccum); - PY_MOD_ADD_METHOD(ClearIndex); - PY_MOD_ADD_METHOD(ClipPlane); - PY_MOD_ADD_METHOD(Color3b); - PY_MOD_ADD_METHOD(Color3bv); - PY_MOD_ADD_METHOD(Color3d); - PY_MOD_ADD_METHOD(Color3dv); - PY_MOD_ADD_METHOD(Color3f); - PY_MOD_ADD_METHOD(Color3fv); - PY_MOD_ADD_METHOD(Color3i); - PY_MOD_ADD_METHOD(Color3iv); - PY_MOD_ADD_METHOD(Color3s); - PY_MOD_ADD_METHOD(Color3sv); - PY_MOD_ADD_METHOD(Color3ub); - PY_MOD_ADD_METHOD(Color3ubv); - PY_MOD_ADD_METHOD(Color3ui); - PY_MOD_ADD_METHOD(Color3uiv); - PY_MOD_ADD_METHOD(Color3us); - PY_MOD_ADD_METHOD(Color3usv); - PY_MOD_ADD_METHOD(Color4b); - PY_MOD_ADD_METHOD(Color4bv); - PY_MOD_ADD_METHOD(Color4d); - PY_MOD_ADD_METHOD(Color4dv); - PY_MOD_ADD_METHOD(Color4f); - PY_MOD_ADD_METHOD(Color4fv); - PY_MOD_ADD_METHOD(Color4i); - PY_MOD_ADD_METHOD(Color4iv); - PY_MOD_ADD_METHOD(Color4s); - PY_MOD_ADD_METHOD(Color4sv); - PY_MOD_ADD_METHOD(Color4ub); - PY_MOD_ADD_METHOD(Color4ubv); - PY_MOD_ADD_METHOD(Color4ui); - PY_MOD_ADD_METHOD(Color4uiv); - PY_MOD_ADD_METHOD(Color4us); - PY_MOD_ADD_METHOD(Color4usv); - PY_MOD_ADD_METHOD(ColorMaterial); - PY_MOD_ADD_METHOD(CopyPixels); - PY_MOD_ADD_METHOD(DeleteLists); - PY_MOD_ADD_METHOD(DrawPixels); - PY_MOD_ADD_METHOD(EdgeFlag); - PY_MOD_ADD_METHOD(EdgeFlagv); - PY_MOD_ADD_METHOD(End); - PY_MOD_ADD_METHOD(EndList); - PY_MOD_ADD_METHOD(EvalCoord1d); - PY_MOD_ADD_METHOD(EvalCoord1dv); - PY_MOD_ADD_METHOD(EvalCoord1f); - PY_MOD_ADD_METHOD(EvalCoord1fv); - PY_MOD_ADD_METHOD(EvalCoord2d); - PY_MOD_ADD_METHOD(EvalCoord2dv); - PY_MOD_ADD_METHOD(EvalCoord2f); - PY_MOD_ADD_METHOD(EvalCoord2fv); - PY_MOD_ADD_METHOD(EvalMesh1); - PY_MOD_ADD_METHOD(EvalMesh2); - PY_MOD_ADD_METHOD(EvalPoint1); - PY_MOD_ADD_METHOD(EvalPoint2); - PY_MOD_ADD_METHOD(FeedbackBuffer); - PY_MOD_ADD_METHOD(Fogf); - PY_MOD_ADD_METHOD(Fogfv); - PY_MOD_ADD_METHOD(Fogi); - PY_MOD_ADD_METHOD(Fogiv); - PY_MOD_ADD_METHOD(Frustum); - PY_MOD_ADD_METHOD(GenLists); - PY_MOD_ADD_METHOD(GetClipPlane); - PY_MOD_ADD_METHOD(GetLightfv); - PY_MOD_ADD_METHOD(GetLightiv); - PY_MOD_ADD_METHOD(GetMapdv); - PY_MOD_ADD_METHOD(GetMapfv); - PY_MOD_ADD_METHOD(GetMapiv); - PY_MOD_ADD_METHOD(GetMaterialfv); - PY_MOD_ADD_METHOD(GetMaterialiv); - PY_MOD_ADD_METHOD(GetPixelMapfv); - PY_MOD_ADD_METHOD(GetPixelMapuiv); - PY_MOD_ADD_METHOD(GetPixelMapusv); - PY_MOD_ADD_METHOD(GetPolygonStipple); - PY_MOD_ADD_METHOD(GetTexEnvfv); - PY_MOD_ADD_METHOD(GetTexEnviv); - PY_MOD_ADD_METHOD(GetTexGendv); - PY_MOD_ADD_METHOD(GetTexGenfv); - PY_MOD_ADD_METHOD(GetTexGeniv); - PY_MOD_ADD_METHOD(IndexMask); - PY_MOD_ADD_METHOD(Indexd); - PY_MOD_ADD_METHOD(Indexdv); - PY_MOD_ADD_METHOD(Indexf); - PY_MOD_ADD_METHOD(Indexfv); - PY_MOD_ADD_METHOD(Indexi); - PY_MOD_ADD_METHOD(Indexiv); - PY_MOD_ADD_METHOD(Indexs); - PY_MOD_ADD_METHOD(Indexsv); - PY_MOD_ADD_METHOD(InitNames); - PY_MOD_ADD_METHOD(IsList); - PY_MOD_ADD_METHOD(LightModelf); - PY_MOD_ADD_METHOD(LightModelfv); - PY_MOD_ADD_METHOD(LightModeli); - PY_MOD_ADD_METHOD(LightModeliv); - PY_MOD_ADD_METHOD(Lightf); - PY_MOD_ADD_METHOD(Lightfv); - PY_MOD_ADD_METHOD(Lighti); - PY_MOD_ADD_METHOD(Lightiv); - PY_MOD_ADD_METHOD(LineStipple); - PY_MOD_ADD_METHOD(ListBase); - PY_MOD_ADD_METHOD(LoadIdentity); - PY_MOD_ADD_METHOD(LoadMatrixd); - PY_MOD_ADD_METHOD(LoadMatrixf); - PY_MOD_ADD_METHOD(LoadName); - PY_MOD_ADD_METHOD(Map1d); - PY_MOD_ADD_METHOD(Map1f); - PY_MOD_ADD_METHOD(Map2d); - PY_MOD_ADD_METHOD(Map2f); - PY_MOD_ADD_METHOD(MapGrid1d); - PY_MOD_ADD_METHOD(MapGrid1f); - PY_MOD_ADD_METHOD(MapGrid2d); - PY_MOD_ADD_METHOD(MapGrid2f); - PY_MOD_ADD_METHOD(Materialf); - PY_MOD_ADD_METHOD(Materialfv); - PY_MOD_ADD_METHOD(Materiali); - PY_MOD_ADD_METHOD(Materialiv); - PY_MOD_ADD_METHOD(MatrixMode); - PY_MOD_ADD_METHOD(MultMatrixd); - PY_MOD_ADD_METHOD(MultMatrixf); - PY_MOD_ADD_METHOD(NewList); - PY_MOD_ADD_METHOD(Normal3b); - PY_MOD_ADD_METHOD(Normal3bv); - PY_MOD_ADD_METHOD(Normal3d); - PY_MOD_ADD_METHOD(Normal3dv); - PY_MOD_ADD_METHOD(Normal3f); - PY_MOD_ADD_METHOD(Normal3fv); - PY_MOD_ADD_METHOD(Normal3i); - PY_MOD_ADD_METHOD(Normal3iv); - PY_MOD_ADD_METHOD(Normal3s); - PY_MOD_ADD_METHOD(Normal3sv); - PY_MOD_ADD_METHOD(Ortho); - PY_MOD_ADD_METHOD(PassThrough); - PY_MOD_ADD_METHOD(PixelMapfv); - PY_MOD_ADD_METHOD(PixelMapuiv); - PY_MOD_ADD_METHOD(PixelMapusv); - PY_MOD_ADD_METHOD(PixelTransferf); - PY_MOD_ADD_METHOD(PixelTransferi); - PY_MOD_ADD_METHOD(PixelZoom); - PY_MOD_ADD_METHOD(PolygonStipple); - PY_MOD_ADD_METHOD(PopAttrib); - PY_MOD_ADD_METHOD(PopMatrix); - PY_MOD_ADD_METHOD(PopName); - PY_MOD_ADD_METHOD(PushAttrib); - PY_MOD_ADD_METHOD(PushMatrix); - PY_MOD_ADD_METHOD(PushName); - PY_MOD_ADD_METHOD(RasterPos2d); - PY_MOD_ADD_METHOD(RasterPos2dv); - PY_MOD_ADD_METHOD(RasterPos2f); - PY_MOD_ADD_METHOD(RasterPos2fv); - PY_MOD_ADD_METHOD(RasterPos2i); - PY_MOD_ADD_METHOD(RasterPos2iv); - PY_MOD_ADD_METHOD(RasterPos2s); - PY_MOD_ADD_METHOD(RasterPos2sv); - PY_MOD_ADD_METHOD(RasterPos3d); - PY_MOD_ADD_METHOD(RasterPos3dv); - PY_MOD_ADD_METHOD(RasterPos3f); - PY_MOD_ADD_METHOD(RasterPos3fv); - PY_MOD_ADD_METHOD(RasterPos3i); - PY_MOD_ADD_METHOD(RasterPos3iv); - PY_MOD_ADD_METHOD(RasterPos3s); - PY_MOD_ADD_METHOD(RasterPos3sv); - PY_MOD_ADD_METHOD(RasterPos4d); - PY_MOD_ADD_METHOD(RasterPos4dv); - PY_MOD_ADD_METHOD(RasterPos4f); - PY_MOD_ADD_METHOD(RasterPos4fv); - PY_MOD_ADD_METHOD(RasterPos4i); - PY_MOD_ADD_METHOD(RasterPos4iv); - PY_MOD_ADD_METHOD(RasterPos4s); - PY_MOD_ADD_METHOD(RasterPos4sv); - PY_MOD_ADD_METHOD(Rectd); - PY_MOD_ADD_METHOD(Rectdv); - PY_MOD_ADD_METHOD(Rectf); - PY_MOD_ADD_METHOD(Rectfv); - PY_MOD_ADD_METHOD(Recti); - PY_MOD_ADD_METHOD(Rectiv); - PY_MOD_ADD_METHOD(Rects); - PY_MOD_ADD_METHOD(Rectsv); - PY_MOD_ADD_METHOD(RenderMode); - PY_MOD_ADD_METHOD(Rotated); - PY_MOD_ADD_METHOD(Rotatef); - PY_MOD_ADD_METHOD(Scaled); - PY_MOD_ADD_METHOD(Scalef); - PY_MOD_ADD_METHOD(SelectBuffer); - PY_MOD_ADD_METHOD(ShadeModel); - PY_MOD_ADD_METHOD(TexCoord1d); - PY_MOD_ADD_METHOD(TexCoord1dv); - PY_MOD_ADD_METHOD(TexCoord1f); - PY_MOD_ADD_METHOD(TexCoord1fv); - PY_MOD_ADD_METHOD(TexCoord1i); - PY_MOD_ADD_METHOD(TexCoord1iv); - PY_MOD_ADD_METHOD(TexCoord1s); - PY_MOD_ADD_METHOD(TexCoord1sv); - PY_MOD_ADD_METHOD(TexCoord2d); - PY_MOD_ADD_METHOD(TexCoord2dv); - PY_MOD_ADD_METHOD(TexCoord2f); - PY_MOD_ADD_METHOD(TexCoord2fv); - PY_MOD_ADD_METHOD(TexCoord2i); - PY_MOD_ADD_METHOD(TexCoord2iv); - PY_MOD_ADD_METHOD(TexCoord2s); - PY_MOD_ADD_METHOD(TexCoord2sv); - PY_MOD_ADD_METHOD(TexCoord3d); - PY_MOD_ADD_METHOD(TexCoord3dv); - PY_MOD_ADD_METHOD(TexCoord3f); - PY_MOD_ADD_METHOD(TexCoord3fv); - PY_MOD_ADD_METHOD(TexCoord3i); - PY_MOD_ADD_METHOD(TexCoord3iv); - PY_MOD_ADD_METHOD(TexCoord3s); - PY_MOD_ADD_METHOD(TexCoord3sv); - PY_MOD_ADD_METHOD(TexCoord4d); - PY_MOD_ADD_METHOD(TexCoord4dv); - PY_MOD_ADD_METHOD(TexCoord4f); - PY_MOD_ADD_METHOD(TexCoord4fv); - PY_MOD_ADD_METHOD(TexCoord4i); - PY_MOD_ADD_METHOD(TexCoord4iv); - PY_MOD_ADD_METHOD(TexCoord4s); - PY_MOD_ADD_METHOD(TexCoord4sv); - PY_MOD_ADD_METHOD(TexEnvf); - PY_MOD_ADD_METHOD(TexEnvfv); - PY_MOD_ADD_METHOD(TexEnvi); - PY_MOD_ADD_METHOD(TexEnviv); - PY_MOD_ADD_METHOD(TexGend); - PY_MOD_ADD_METHOD(TexGendv); - PY_MOD_ADD_METHOD(TexGenf); - PY_MOD_ADD_METHOD(TexGenfv); - PY_MOD_ADD_METHOD(TexGeni); - PY_MOD_ADD_METHOD(TexGeniv); - PY_MOD_ADD_METHOD(Translated); - PY_MOD_ADD_METHOD(Translatef); - PY_MOD_ADD_METHOD(Vertex2d); - PY_MOD_ADD_METHOD(Vertex2dv); - PY_MOD_ADD_METHOD(Vertex2f); - PY_MOD_ADD_METHOD(Vertex2fv); - PY_MOD_ADD_METHOD(Vertex2i); - PY_MOD_ADD_METHOD(Vertex2iv); - PY_MOD_ADD_METHOD(Vertex2s); - PY_MOD_ADD_METHOD(Vertex2sv); - PY_MOD_ADD_METHOD(Vertex3d); - PY_MOD_ADD_METHOD(Vertex3dv); - PY_MOD_ADD_METHOD(Vertex3f); - PY_MOD_ADD_METHOD(Vertex3fv); - PY_MOD_ADD_METHOD(Vertex3i); - PY_MOD_ADD_METHOD(Vertex3iv); - PY_MOD_ADD_METHOD(Vertex3s); - PY_MOD_ADD_METHOD(Vertex3sv); - PY_MOD_ADD_METHOD(Vertex4d); - PY_MOD_ADD_METHOD(Vertex4dv); - PY_MOD_ADD_METHOD(Vertex4f); - PY_MOD_ADD_METHOD(Vertex4fv); - PY_MOD_ADD_METHOD(Vertex4i); - PY_MOD_ADD_METHOD(Vertex4iv); - PY_MOD_ADD_METHOD(Vertex4s); - PY_MOD_ADD_METHOD(Vertex4sv); - } - /* GL_VERSION_1_1 */ { @@ -2101,27 +1470,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexSubImage1D); PY_MOD_ADD_METHOD(TexSubImage2D); } - /* adding in GL_VERSION_1_1 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(AreTexturesResident); - PY_MOD_ADD_METHOD(ArrayElement); - PY_MOD_ADD_METHOD(ColorPointer); - PY_MOD_ADD_METHOD(DisableClientState); - PY_MOD_ADD_METHOD(EdgeFlagPointer); - PY_MOD_ADD_METHOD(EnableClientState); - PY_MOD_ADD_METHOD(GetPointerv); - PY_MOD_ADD_METHOD(IndexPointer); - PY_MOD_ADD_METHOD(Indexub); - PY_MOD_ADD_METHOD(Indexubv); - PY_MOD_ADD_METHOD(InterleavedArrays); - PY_MOD_ADD_METHOD(NormalPointer); - PY_MOD_ADD_METHOD(PopClientAttrib); - PY_MOD_ADD_METHOD(PrioritizeTextures); - PY_MOD_ADD_METHOD(PushClientAttrib); - PY_MOD_ADD_METHOD(TexCoordPointer); - PY_MOD_ADD_METHOD(VertexPointer); - } - /* GL_VERSION_1_2 */ { @@ -2131,7 +1479,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexSubImage3D); } - /* GL_VERSION_1_3 */ { PY_MOD_ADD_METHOD(ActiveTexture); @@ -2144,47 +1491,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(GetCompressedTexImage); PY_MOD_ADD_METHOD(SampleCoverage); } - /* adding in GL_VERSION_1_3 removed from core profile */ - if (use_deprecated == true) { - PY_MOD_ADD_METHOD(ClientActiveTexture); - PY_MOD_ADD_METHOD(LoadTransposeMatrixd); - PY_MOD_ADD_METHOD(LoadTransposeMatrixf); - PY_MOD_ADD_METHOD(MultTransposeMatrixd); - PY_MOD_ADD_METHOD(MultTransposeMatrixf); - PY_MOD_ADD_METHOD(MultiTexCoord1d); - PY_MOD_ADD_METHOD(MultiTexCoord1dv); - PY_MOD_ADD_METHOD(MultiTexCoord1f); - PY_MOD_ADD_METHOD(MultiTexCoord1fv); - PY_MOD_ADD_METHOD(MultiTexCoord1i); - PY_MOD_ADD_METHOD(MultiTexCoord1iv); - PY_MOD_ADD_METHOD(MultiTexCoord1s); - PY_MOD_ADD_METHOD(MultiTexCoord1sv); - PY_MOD_ADD_METHOD(MultiTexCoord2d); - PY_MOD_ADD_METHOD(MultiTexCoord2dv); - PY_MOD_ADD_METHOD(MultiTexCoord2f); - PY_MOD_ADD_METHOD(MultiTexCoord2fv); - PY_MOD_ADD_METHOD(MultiTexCoord2i); - PY_MOD_ADD_METHOD(MultiTexCoord2iv); - PY_MOD_ADD_METHOD(MultiTexCoord2s); - PY_MOD_ADD_METHOD(MultiTexCoord2sv); - PY_MOD_ADD_METHOD(MultiTexCoord3d); - PY_MOD_ADD_METHOD(MultiTexCoord3dv); - PY_MOD_ADD_METHOD(MultiTexCoord3f); - PY_MOD_ADD_METHOD(MultiTexCoord3fv); - PY_MOD_ADD_METHOD(MultiTexCoord3i); - PY_MOD_ADD_METHOD(MultiTexCoord3iv); - PY_MOD_ADD_METHOD(MultiTexCoord3s); - PY_MOD_ADD_METHOD(MultiTexCoord3sv); - PY_MOD_ADD_METHOD(MultiTexCoord4d); - PY_MOD_ADD_METHOD(MultiTexCoord4dv); - PY_MOD_ADD_METHOD(MultiTexCoord4f); - PY_MOD_ADD_METHOD(MultiTexCoord4fv); - PY_MOD_ADD_METHOD(MultiTexCoord4i); - PY_MOD_ADD_METHOD(MultiTexCoord4iv); - PY_MOD_ADD_METHOD(MultiTexCoord4s); - PY_MOD_ADD_METHOD(MultiTexCoord4sv); - } - /* GL_VERSION_1_4 */ { @@ -2192,7 +1498,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(BlendEquation); } - /* GL_VERSION_1_5 */ { PY_MOD_ADD_METHOD(BeginQuery); @@ -2216,7 +1521,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UnmapBuffer); } - /* GL_VERSION_2_0 */ { PY_MOD_ADD_METHOD(AttachShader); @@ -2314,7 +1618,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(VertexAttribPointer); } - /* GL_VERSION_2_1 */ { PY_MOD_ADD_METHOD(UniformMatrix2x3fv); @@ -2325,16 +1628,25 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UniformMatrix4x3fv); } - /* GL_VERSION_3_0 */ { + PY_MOD_ADD_METHOD(BindFramebuffer); + PY_MOD_ADD_METHOD(BindRenderbuffer); PY_MOD_ADD_METHOD(BindVertexArray); + PY_MOD_ADD_METHOD(BlitFramebuffer); + PY_MOD_ADD_METHOD(CheckFramebufferStatus); + PY_MOD_ADD_METHOD(DeleteFramebuffers); + PY_MOD_ADD_METHOD(DeleteRenderbuffers); PY_MOD_ADD_METHOD(DeleteVertexArrays); + PY_MOD_ADD_METHOD(FramebufferRenderbuffer); + PY_MOD_ADD_METHOD(GenFramebuffers); + PY_MOD_ADD_METHOD(GenRenderbuffers); PY_MOD_ADD_METHOD(GenVertexArrays); + PY_MOD_ADD_METHOD(GetStringi); PY_MOD_ADD_METHOD(IsVertexArray); + PY_MOD_ADD_METHOD(RenderbufferStorage); } - /* GL_VERSION_3_1 */ { PY_MOD_ADD_METHOD(BindBufferBase); @@ -2349,7 +1661,6 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(UniformBlockBinding); } - /* GL_VERSION_3_2 */ { PY_MOD_ADD_METHOD(FramebufferTexture); @@ -2361,39 +1672,8 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(TexImage3DMultisample); } - /* GL_VERSION_3_3 */ { - PY_MOD_ADD_METHOD(ColorP3ui); - PY_MOD_ADD_METHOD(ColorP3uiv); - PY_MOD_ADD_METHOD(ColorP4ui); - PY_MOD_ADD_METHOD(ColorP4uiv); - PY_MOD_ADD_METHOD(MultiTexCoordP1ui); - PY_MOD_ADD_METHOD(MultiTexCoordP1uiv); - PY_MOD_ADD_METHOD(MultiTexCoordP2ui); - PY_MOD_ADD_METHOD(MultiTexCoordP2uiv); - PY_MOD_ADD_METHOD(MultiTexCoordP3ui); - PY_MOD_ADD_METHOD(MultiTexCoordP3uiv); - PY_MOD_ADD_METHOD(MultiTexCoordP4ui); - PY_MOD_ADD_METHOD(MultiTexCoordP4uiv); - PY_MOD_ADD_METHOD(NormalP3ui); - PY_MOD_ADD_METHOD(NormalP3uiv); - PY_MOD_ADD_METHOD(SecondaryColorP3ui); - PY_MOD_ADD_METHOD(SecondaryColorP3uiv); - PY_MOD_ADD_METHOD(TexCoordP1ui); - PY_MOD_ADD_METHOD(TexCoordP1uiv); - PY_MOD_ADD_METHOD(TexCoordP2ui); - PY_MOD_ADD_METHOD(TexCoordP2uiv); - PY_MOD_ADD_METHOD(TexCoordP3ui); - PY_MOD_ADD_METHOD(TexCoordP3uiv); - PY_MOD_ADD_METHOD(TexCoordP4ui); - PY_MOD_ADD_METHOD(TexCoordP4uiv); - PY_MOD_ADD_METHOD(VertexP2ui); - PY_MOD_ADD_METHOD(VertexP2uiv); - PY_MOD_ADD_METHOD(VertexP3ui); - PY_MOD_ADD_METHOD(VertexP3uiv); - PY_MOD_ADD_METHOD(VertexP4ui); - PY_MOD_ADD_METHOD(VertexP4uiv); } #define PY_DICT_ADD_INT(x) py_module_dict_add_int(dict, #x, x) @@ -2511,8 +1791,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_POINT); PY_DICT_ADD_INT(GL_POINTS); PY_DICT_ADD_INT(GL_POINT_SIZE); - PY_DICT_ADD_INT(GL_POINT_SIZE_GRANULARITY); - PY_DICT_ADD_INT(GL_POINT_SIZE_RANGE); PY_DICT_ADD_INT(GL_POLYGON_MODE); PY_DICT_ADD_INT(GL_POLYGON_OFFSET_FACTOR); PY_DICT_ADD_INT(GL_POLYGON_OFFSET_FILL); @@ -2602,338 +1880,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_XOR); PY_DICT_ADD_INT(GL_ZERO); } - /* adding in GL_VERSION_1_1 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_2D); - PY_DICT_ADD_INT(GL_2_BYTES); - PY_DICT_ADD_INT(GL_3D); - PY_DICT_ADD_INT(GL_3D_COLOR); - PY_DICT_ADD_INT(GL_3D_COLOR_TEXTURE); - PY_DICT_ADD_INT(GL_3_BYTES); - PY_DICT_ADD_INT(GL_4D_COLOR_TEXTURE); - PY_DICT_ADD_INT(GL_4_BYTES); - PY_DICT_ADD_INT(GL_ACCUM); - PY_DICT_ADD_INT(GL_ACCUM_ALPHA_BITS); - PY_DICT_ADD_INT(GL_ACCUM_BLUE_BITS); - PY_DICT_ADD_INT(GL_ACCUM_BUFFER_BIT); - PY_DICT_ADD_INT(GL_ACCUM_CLEAR_VALUE); - PY_DICT_ADD_INT(GL_ACCUM_GREEN_BITS); - PY_DICT_ADD_INT(GL_ACCUM_RED_BITS); - PY_DICT_ADD_INT(GL_ADD); - PY_DICT_ADD_INT(GL_ALL_ATTRIB_BITS); - PY_DICT_ADD_INT(GL_ALPHA12); - PY_DICT_ADD_INT(GL_ALPHA16); - PY_DICT_ADD_INT(GL_ALPHA4); - PY_DICT_ADD_INT(GL_ALPHA8); - PY_DICT_ADD_INT(GL_ALPHA_BIAS); - PY_DICT_ADD_INT(GL_ALPHA_BITS); - PY_DICT_ADD_INT(GL_ALPHA_SCALE); - PY_DICT_ADD_INT(GL_ALPHA_TEST); - PY_DICT_ADD_INT(GL_ALPHA_TEST_FUNC); - PY_DICT_ADD_INT(GL_ALPHA_TEST_REF); - PY_DICT_ADD_INT(GL_AMBIENT); - PY_DICT_ADD_INT(GL_AMBIENT_AND_DIFFUSE); - PY_DICT_ADD_INT(GL_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_AUTO_NORMAL); - PY_DICT_ADD_INT(GL_AUX0); - PY_DICT_ADD_INT(GL_AUX1); - PY_DICT_ADD_INT(GL_AUX2); - PY_DICT_ADD_INT(GL_AUX3); - PY_DICT_ADD_INT(GL_AUX_BUFFERS); - PY_DICT_ADD_INT(GL_BITMAP); - PY_DICT_ADD_INT(GL_BITMAP_TOKEN); - PY_DICT_ADD_INT(GL_BLUE_BIAS); - PY_DICT_ADD_INT(GL_BLUE_BITS); - PY_DICT_ADD_INT(GL_BLUE_SCALE); - PY_DICT_ADD_INT(GL_C3F_V3F); - PY_DICT_ADD_INT(GL_C4F_N3F_V3F); - PY_DICT_ADD_INT(GL_C4UB_V2F); - PY_DICT_ADD_INT(GL_C4UB_V3F); - PY_DICT_ADD_INT(GL_CLAMP); - PY_DICT_ADD_INT(GL_CLIENT_ALL_ATTRIB_BITS); - PY_DICT_ADD_INT(GL_CLIENT_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_CLIENT_PIXEL_STORE_BIT); - PY_DICT_ADD_INT(GL_CLIENT_VERTEX_ARRAY_BIT); - PY_DICT_ADD_INT(GL_CLIP_PLANE0); - PY_DICT_ADD_INT(GL_CLIP_PLANE1); - PY_DICT_ADD_INT(GL_CLIP_PLANE2); - PY_DICT_ADD_INT(GL_CLIP_PLANE3); - PY_DICT_ADD_INT(GL_CLIP_PLANE4); - PY_DICT_ADD_INT(GL_CLIP_PLANE5); - PY_DICT_ADD_INT(GL_COEFF); - PY_DICT_ADD_INT(GL_COLOR_ARRAY); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_COLOR_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_COLOR_INDEX); - PY_DICT_ADD_INT(GL_COLOR_INDEXES); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL_FACE); - PY_DICT_ADD_INT(GL_COLOR_MATERIAL_PARAMETER); - PY_DICT_ADD_INT(GL_COMPILE); - PY_DICT_ADD_INT(GL_COMPILE_AND_EXECUTE); - PY_DICT_ADD_INT(GL_CONSTANT_ATTENUATION); - PY_DICT_ADD_INT(GL_COPY_PIXEL_TOKEN); - PY_DICT_ADD_INT(GL_CURRENT_BIT); - PY_DICT_ADD_INT(GL_CURRENT_COLOR); - PY_DICT_ADD_INT(GL_CURRENT_INDEX); - PY_DICT_ADD_INT(GL_CURRENT_NORMAL); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_COLOR); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_DISTANCE); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_INDEX); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION_VALID); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_CURRENT_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_DECAL); - PY_DICT_ADD_INT(GL_DEPTH_BIAS); - PY_DICT_ADD_INT(GL_DEPTH_BITS); - PY_DICT_ADD_INT(GL_DEPTH_SCALE); - PY_DICT_ADD_INT(GL_DIFFUSE); - PY_DICT_ADD_INT(GL_DOMAIN); - PY_DICT_ADD_INT(GL_DRAW_PIXEL_TOKEN); - PY_DICT_ADD_INT(GL_EDGE_FLAG); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_EMISSION); - PY_DICT_ADD_INT(GL_ENABLE_BIT); - PY_DICT_ADD_INT(GL_EVAL_BIT); - PY_DICT_ADD_INT(GL_EXP); - PY_DICT_ADD_INT(GL_EXP2); - PY_DICT_ADD_INT(GL_EYE_LINEAR); - PY_DICT_ADD_INT(GL_EYE_PLANE); - PY_DICT_ADD_INT(GL_FEEDBACK); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_POINTER); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_SIZE); - PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_TYPE); - PY_DICT_ADD_INT(GL_FLAT); - PY_DICT_ADD_INT(GL_FOG); - PY_DICT_ADD_INT(GL_FOG_BIT); - PY_DICT_ADD_INT(GL_FOG_COLOR); - PY_DICT_ADD_INT(GL_FOG_DENSITY); - PY_DICT_ADD_INT(GL_FOG_END); - PY_DICT_ADD_INT(GL_FOG_HINT); - PY_DICT_ADD_INT(GL_FOG_INDEX); - PY_DICT_ADD_INT(GL_FOG_MODE); - PY_DICT_ADD_INT(GL_FOG_START); - PY_DICT_ADD_INT(GL_GREEN_BIAS); - PY_DICT_ADD_INT(GL_GREEN_BITS); - PY_DICT_ADD_INT(GL_GREEN_SCALE); - PY_DICT_ADD_INT(GL_HINT_BIT); - PY_DICT_ADD_INT(GL_INDEX_ARRAY); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_INDEX_BITS); - PY_DICT_ADD_INT(GL_INDEX_CLEAR_VALUE); - PY_DICT_ADD_INT(GL_INDEX_LOGIC_OP); - PY_DICT_ADD_INT(GL_INDEX_MODE); - PY_DICT_ADD_INT(GL_INDEX_OFFSET); - PY_DICT_ADD_INT(GL_INDEX_SHIFT); - PY_DICT_ADD_INT(GL_INDEX_WRITEMASK); - PY_DICT_ADD_INT(GL_INTENSITY); - PY_DICT_ADD_INT(GL_INTENSITY12); - PY_DICT_ADD_INT(GL_INTENSITY16); - PY_DICT_ADD_INT(GL_INTENSITY4); - PY_DICT_ADD_INT(GL_INTENSITY8); - PY_DICT_ADD_INT(GL_LIGHT0); - PY_DICT_ADD_INT(GL_LIGHT1); - PY_DICT_ADD_INT(GL_LIGHT2); - PY_DICT_ADD_INT(GL_LIGHT3); - PY_DICT_ADD_INT(GL_LIGHT4); - PY_DICT_ADD_INT(GL_LIGHT5); - PY_DICT_ADD_INT(GL_LIGHT6); - PY_DICT_ADD_INT(GL_LIGHT7); - PY_DICT_ADD_INT(GL_LIGHTING); - PY_DICT_ADD_INT(GL_LIGHTING_BIT); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_AMBIENT); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_LOCAL_VIEWER); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_TWO_SIDE); - PY_DICT_ADD_INT(GL_LINEAR_ATTENUATION); - PY_DICT_ADD_INT(GL_LINE_BIT); - PY_DICT_ADD_INT(GL_LINE_RESET_TOKEN); - PY_DICT_ADD_INT(GL_LINE_STIPPLE); - PY_DICT_ADD_INT(GL_LINE_STIPPLE_PATTERN); - PY_DICT_ADD_INT(GL_LINE_STIPPLE_REPEAT); - PY_DICT_ADD_INT(GL_LINE_TOKEN); - PY_DICT_ADD_INT(GL_LIST_BASE); - PY_DICT_ADD_INT(GL_LIST_BIT); - PY_DICT_ADD_INT(GL_LIST_INDEX); - PY_DICT_ADD_INT(GL_LIST_MODE); - PY_DICT_ADD_INT(GL_LOAD); - PY_DICT_ADD_INT(GL_LOGIC_OP); - PY_DICT_ADD_INT(GL_LUMINANCE); - PY_DICT_ADD_INT(GL_LUMINANCE12); - PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA12); - PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA4); - PY_DICT_ADD_INT(GL_LUMINANCE16); - PY_DICT_ADD_INT(GL_LUMINANCE16_ALPHA16); - PY_DICT_ADD_INT(GL_LUMINANCE4); - PY_DICT_ADD_INT(GL_LUMINANCE4_ALPHA4); - PY_DICT_ADD_INT(GL_LUMINANCE6_ALPHA2); - PY_DICT_ADD_INT(GL_LUMINANCE8); - PY_DICT_ADD_INT(GL_LUMINANCE8_ALPHA8); - PY_DICT_ADD_INT(GL_LUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_MAP1_COLOR_4); - PY_DICT_ADD_INT(GL_MAP1_GRID_DOMAIN); - PY_DICT_ADD_INT(GL_MAP1_GRID_SEGMENTS); - PY_DICT_ADD_INT(GL_MAP1_INDEX); - PY_DICT_ADD_INT(GL_MAP1_NORMAL); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_1); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_2); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_3); - PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_4); - PY_DICT_ADD_INT(GL_MAP1_VERTEX_3); - PY_DICT_ADD_INT(GL_MAP1_VERTEX_4); - PY_DICT_ADD_INT(GL_MAP2_COLOR_4); - PY_DICT_ADD_INT(GL_MAP2_GRID_DOMAIN); - PY_DICT_ADD_INT(GL_MAP2_GRID_SEGMENTS); - PY_DICT_ADD_INT(GL_MAP2_INDEX); - PY_DICT_ADD_INT(GL_MAP2_NORMAL); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_1); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_2); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_3); - PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_4); - PY_DICT_ADD_INT(GL_MAP2_VERTEX_3); - PY_DICT_ADD_INT(GL_MAP2_VERTEX_4); - PY_DICT_ADD_INT(GL_MAP_COLOR); - PY_DICT_ADD_INT(GL_MAP_STENCIL); - PY_DICT_ADD_INT(GL_MATRIX_MODE); - PY_DICT_ADD_INT(GL_MAX_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_CLIP_PLANES); - PY_DICT_ADD_INT(GL_MAX_EVAL_ORDER); - PY_DICT_ADD_INT(GL_MAX_LIGHTS); - PY_DICT_ADD_INT(GL_MAX_LIST_NESTING); - PY_DICT_ADD_INT(GL_MAX_MODELVIEW_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_NAME_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_PIXEL_MAP_TABLE); - PY_DICT_ADD_INT(GL_MAX_PROJECTION_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MODELVIEW); - PY_DICT_ADD_INT(GL_MODELVIEW_MATRIX); - PY_DICT_ADD_INT(GL_MODELVIEW_STACK_DEPTH); - PY_DICT_ADD_INT(GL_MODULATE); - PY_DICT_ADD_INT(GL_MULT); - PY_DICT_ADD_INT(GL_N3F_V3F); - PY_DICT_ADD_INT(GL_NAME_STACK_DEPTH); - PY_DICT_ADD_INT(GL_NORMALIZE); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_OBJECT_LINEAR); - PY_DICT_ADD_INT(GL_OBJECT_PLANE); - PY_DICT_ADD_INT(GL_ORDER); - PY_DICT_ADD_INT(GL_PASS_THROUGH_TOKEN); - PY_DICT_ADD_INT(GL_PERSPECTIVE_CORRECTION_HINT); - PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A); - PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B); - PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G); - PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R); - PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R); - PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S); - PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S_SIZE); - PY_DICT_ADD_INT(GL_PIXEL_MODE_BIT); - PY_DICT_ADD_INT(GL_POINT_BIT); - PY_DICT_ADD_INT(GL_POINT_SMOOTH); - PY_DICT_ADD_INT(GL_POINT_SMOOTH_HINT); - PY_DICT_ADD_INT(GL_POINT_TOKEN); - PY_DICT_ADD_INT(GL_POLYGON); - PY_DICT_ADD_INT(GL_POLYGON_BIT); - PY_DICT_ADD_INT(GL_POLYGON_STIPPLE); - PY_DICT_ADD_INT(GL_POLYGON_STIPPLE_BIT); - PY_DICT_ADD_INT(GL_POLYGON_TOKEN); - PY_DICT_ADD_INT(GL_POSITION); - PY_DICT_ADD_INT(GL_PROJECTION); - PY_DICT_ADD_INT(GL_PROJECTION_MATRIX); - PY_DICT_ADD_INT(GL_PROJECTION_STACK_DEPTH); - PY_DICT_ADD_INT(GL_Q); - PY_DICT_ADD_INT(GL_QUADRATIC_ATTENUATION); - PY_DICT_ADD_INT(GL_QUADS); - PY_DICT_ADD_INT(GL_QUAD_STRIP); - PY_DICT_ADD_INT(GL_R); - PY_DICT_ADD_INT(GL_RED_BIAS); - PY_DICT_ADD_INT(GL_RED_BITS); - PY_DICT_ADD_INT(GL_RED_SCALE); - PY_DICT_ADD_INT(GL_RENDER); - PY_DICT_ADD_INT(GL_RENDER_MODE); - PY_DICT_ADD_INT(GL_RETURN); - PY_DICT_ADD_INT(GL_RGBA_MODE); - PY_DICT_ADD_INT(GL_S); - PY_DICT_ADD_INT(GL_SCISSOR_BIT); - PY_DICT_ADD_INT(GL_SELECT); - PY_DICT_ADD_INT(GL_SELECTION_BUFFER_POINTER); - PY_DICT_ADD_INT(GL_SELECTION_BUFFER_SIZE); - PY_DICT_ADD_INT(GL_SHADE_MODEL); - PY_DICT_ADD_INT(GL_SHININESS); - PY_DICT_ADD_INT(GL_SMOOTH); - PY_DICT_ADD_INT(GL_SPECULAR); - PY_DICT_ADD_INT(GL_SPHERE_MAP); - PY_DICT_ADD_INT(GL_SPOT_CUTOFF); - PY_DICT_ADD_INT(GL_SPOT_DIRECTION); - PY_DICT_ADD_INT(GL_SPOT_EXPONENT); - PY_DICT_ADD_INT(GL_STACK_OVERFLOW); - PY_DICT_ADD_INT(GL_STACK_UNDERFLOW); - PY_DICT_ADD_INT(GL_STENCIL_BITS); - PY_DICT_ADD_INT(GL_T); - PY_DICT_ADD_INT(GL_T2F_C3F_V3F); - PY_DICT_ADD_INT(GL_T2F_C4F_N3F_V3F); - PY_DICT_ADD_INT(GL_T2F_C4UB_V3F); - PY_DICT_ADD_INT(GL_T2F_N3F_V3F); - PY_DICT_ADD_INT(GL_T2F_V3F); - PY_DICT_ADD_INT(GL_T4F_C4F_N3F_V4F); - PY_DICT_ADD_INT(GL_T4F_V4F); - PY_DICT_ADD_INT(GL_TEXTURE_BIT); - PY_DICT_ADD_INT(GL_TEXTURE_BORDER); - PY_DICT_ADD_INT(GL_TEXTURE_COMPONENTS); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_ENV); - PY_DICT_ADD_INT(GL_TEXTURE_ENV_COLOR); - PY_DICT_ADD_INT(GL_TEXTURE_ENV_MODE); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_MODE); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_Q); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_R); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_S); - PY_DICT_ADD_INT(GL_TEXTURE_GEN_T); - PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_SIZE); - PY_DICT_ADD_INT(GL_TEXTURE_MATRIX); - PY_DICT_ADD_INT(GL_TEXTURE_PRIORITY); - PY_DICT_ADD_INT(GL_TEXTURE_RESIDENT); - PY_DICT_ADD_INT(GL_TEXTURE_STACK_DEPTH); - PY_DICT_ADD_INT(GL_TRANSFORM_BIT); - PY_DICT_ADD_INT(GL_V2F); - PY_DICT_ADD_INT(GL_V3F); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_VIEWPORT_BIT); - PY_DICT_ADD_INT(GL_ZOOM_X); - PY_DICT_ADD_INT(GL_ZOOM_Y); - } - /* GL_VERSION_1_2 */ { @@ -2974,15 +1920,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5); PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5_REV); } - /* adding in GL_VERSION_1_2 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ALIASED_POINT_SIZE_RANGE); - PY_DICT_ADD_INT(GL_LIGHT_MODEL_COLOR_CONTROL); - PY_DICT_ADD_INT(GL_RESCALE_NORMAL); - PY_DICT_ADD_INT(GL_SEPARATE_SPECULAR_COLOR); - PY_DICT_ADD_INT(GL_SINGLE_COLOR); - } - /* GL_VERSION_1_3 */ { @@ -3046,47 +1983,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y); PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z); } - /* adding in GL_VERSION_1_3 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ADD_SIGNED); - PY_DICT_ADD_INT(GL_CLIENT_ACTIVE_TEXTURE); - PY_DICT_ADD_INT(GL_COMBINE); - PY_DICT_ADD_INT(GL_COMBINE_ALPHA); - PY_DICT_ADD_INT(GL_COMBINE_RGB); - PY_DICT_ADD_INT(GL_COMPRESSED_ALPHA); - PY_DICT_ADD_INT(GL_COMPRESSED_INTENSITY); - PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE); - PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_CONSTANT); - PY_DICT_ADD_INT(GL_DOT3_RGB); - PY_DICT_ADD_INT(GL_DOT3_RGBA); - PY_DICT_ADD_INT(GL_INTERPOLATE); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_UNITS); - PY_DICT_ADD_INT(GL_MULTISAMPLE_BIT); - PY_DICT_ADD_INT(GL_NORMAL_MAP); - PY_DICT_ADD_INT(GL_OPERAND0_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND0_RGB); - PY_DICT_ADD_INT(GL_OPERAND1_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND1_RGB); - PY_DICT_ADD_INT(GL_OPERAND2_ALPHA); - PY_DICT_ADD_INT(GL_OPERAND2_RGB); - PY_DICT_ADD_INT(GL_PREVIOUS); - PY_DICT_ADD_INT(GL_PRIMARY_COLOR); - PY_DICT_ADD_INT(GL_REFLECTION_MAP); - PY_DICT_ADD_INT(GL_RGB_SCALE); - PY_DICT_ADD_INT(GL_SOURCE0_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE0_RGB); - PY_DICT_ADD_INT(GL_SOURCE1_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE1_RGB); - PY_DICT_ADD_INT(GL_SOURCE2_ALPHA); - PY_DICT_ADD_INT(GL_SOURCE2_RGB); - PY_DICT_ADD_INT(GL_SUBTRACT); - PY_DICT_ADD_INT(GL_TRANSPOSE_COLOR_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_MODELVIEW_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_PROJECTION_MATRIX); - PY_DICT_ADD_INT(GL_TRANSPOSE_TEXTURE_MATRIX); - } - /* GL_VERSION_1_4 */ { @@ -3116,33 +2012,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_TEXTURE_DEPTH_SIZE); PY_DICT_ADD_INT(GL_TEXTURE_LOD_BIAS); } - /* adding in GL_VERSION_1_4 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COLOR_SUM); - PY_DICT_ADD_INT(GL_COMPARE_R_TO_TEXTURE); - PY_DICT_ADD_INT(GL_CURRENT_FOG_COORDINATE); - PY_DICT_ADD_INT(GL_CURRENT_SECONDARY_COLOR); - PY_DICT_ADD_INT(GL_DEPTH_TEXTURE_MODE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_SOURCE); - PY_DICT_ADD_INT(GL_FRAGMENT_DEPTH); - PY_DICT_ADD_INT(GL_GENERATE_MIPMAP); - PY_DICT_ADD_INT(GL_GENERATE_MIPMAP_HINT); - PY_DICT_ADD_INT(GL_POINT_DISTANCE_ATTENUATION); - PY_DICT_ADD_INT(GL_POINT_SIZE_MAX); - PY_DICT_ADD_INT(GL_POINT_SIZE_MIN); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_SIZE); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_FILTER_CONTROL); - } - /* GL_VERSION_1_5 */ { @@ -3165,7 +2034,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_READ_ONLY); PY_DICT_ADD_INT(GL_READ_WRITE); PY_DICT_ADD_INT(GL_SAMPLES_PASSED); - PY_DICT_ADD_INT(GL_SRC1_ALPHA); PY_DICT_ADD_INT(GL_STATIC_COPY); PY_DICT_ADD_INT(GL_STATIC_DRAW); PY_DICT_ADD_INT(GL_STATIC_READ); @@ -3175,32 +2043,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING); PY_DICT_ADD_INT(GL_WRITE_ONLY); } - /* adding in GL_VERSION_1_5 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COLOR_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_CURRENT_FOG_COORD); - PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD); - PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_POINTER); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_STRIDE); - PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_TYPE); - PY_DICT_ADD_INT(GL_FOG_COORD_SRC); - PY_DICT_ADD_INT(GL_INDEX_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_NORMAL_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_SRC0_ALPHA); - PY_DICT_ADD_INT(GL_SRC0_RGB); - PY_DICT_ADD_INT(GL_SRC1_RGB); - PY_DICT_ADD_INT(GL_SRC2_ALPHA); - PY_DICT_ADD_INT(GL_SRC2_RGB); - PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BUFFER_BINDING); - PY_DICT_ADD_INT(GL_WEIGHT_ARRAY_BUFFER_BINDING); - } - /* GL_VERSION_2_0 */ { @@ -3285,14 +2127,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_POINT_SIZE); PY_DICT_ADD_INT(GL_VERTEX_SHADER); } - /* adding in GL_VERSION_2_0 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COORD_REPLACE); - PY_DICT_ADD_INT(GL_MAX_TEXTURE_COORDS); - PY_DICT_ADD_INT(GL_POINT_SPRITE); - PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_TWO_SIDE); - } - /* GL_VERSION_2_1 */ { @@ -3313,16 +2147,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_SRGB8_ALPHA8); PY_DICT_ADD_INT(GL_SRGB_ALPHA); } - /* adding in GL_VERSION_2_1 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE); - PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE_ALPHA); - PY_DICT_ADD_INT(GL_CURRENT_RASTER_SECONDARY_COLOR); - PY_DICT_ADD_INT(GL_SLUMINANCE); - PY_DICT_ADD_INT(GL_SLUMINANCE8); - PY_DICT_ADD_INT(GL_SLUMINANCE8_ALPHA8); - PY_DICT_ADD_INT(GL_SLUMINANCE_ALPHA); - } /* GL_VERSION_3_0 */ { @@ -3563,14 +2387,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BINDING); PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_INTEGER); } - /* adding in GL_VERSION_3_0 removed from core profile */ - if (use_deprecated == true) { - PY_DICT_ADD_INT(GL_ALPHA_INTEGER); - PY_DICT_ADD_INT(GL_CLAMP_FRAGMENT_COLOR); - PY_DICT_ADD_INT(GL_CLAMP_VERTEX_COLOR); - PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_TYPE); - PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_TYPE); - } /* GL_VERSION_3_1 */ { @@ -3637,7 +2453,6 @@ PyObject *BPyInit_bgl(void) PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_BUFFER); } - /* GL_VERSION_3_2 */ { PY_DICT_ADD_INT(GL_ALREADY_SIGNALED); diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 7d124966334..7337706639f 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -114,6 +114,41 @@ static PyObject *py_blf_aspect(PyObject *UNUSED(self), PyObject *args) } +PyDoc_STRVAR(py_blf_color_doc, +".. function:: color(fontid, r, g, b, a)\n" +"\n" +" Set the color for drawing text.\n" +"\n" +" :arg fontid: The id of the typeface as returned by :func:`blf.load`, for default font use 0.\n" +" :type fontid: int\n" +" :arg r: red channel 0.0 - 1.0.\n" +" :type r: float\n" +" :arg g: green channel 0.0 - 1.0.\n" +" :type g: float\n" +" :arg b: blue channel 0.0 - 1.0.\n" +" :type b: float\n" +" :arg a: alpha channel 0.0 - 1.0.\n" +" :type a: float\n" +); +static PyObject *py_blf_color(PyObject *UNUSED(self), PyObject *args) +{ + int fontid; + float rgba[4]; + + if (!PyArg_ParseTuple( + args, "iffff:blf.color", + &fontid, &rgba[0], &rgba[1], &rgba[2], &rgba[3])) + { + return NULL; + } + + BLF_color4fv(fontid, rgba); + + Py_RETURN_NONE; +} + + +#if BLF_BLUR_ENABLE PyDoc_STRVAR(py_blf_blur_doc, ".. function:: blur(fontid, radius)\n" "\n" @@ -135,6 +170,7 @@ static PyObject *py_blf_blur(PyObject *UNUSED(self), PyObject *args) Py_RETURN_NONE; } +#endif PyDoc_STRVAR(py_blf_draw_doc, @@ -418,7 +454,9 @@ static PyObject *py_blf_unload(PyObject *UNUSED(self), PyObject *args) /*----------------------------MODULE INIT-------------------------*/ static PyMethodDef BLF_methods[] = { {"aspect", (PyCFunction) py_blf_aspect, METH_VARARGS, py_blf_aspect_doc}, +#if BLF_BLUR_ENABLE {"blur", (PyCFunction) py_blf_blur, METH_VARARGS, py_blf_blur_doc}, +#endif {"clipping", (PyCFunction) py_blf_clipping, METH_VARARGS, py_blf_clipping_doc}, {"word_wrap", (PyCFunction) py_blf_word_wrap, METH_VARARGS, py_blf_word_wrap_doc}, {"disable", (PyCFunction) py_blf_disable, METH_VARARGS, py_blf_disable_doc}, @@ -430,6 +468,7 @@ static PyMethodDef BLF_methods[] = { {"shadow", (PyCFunction) py_blf_shadow, METH_VARARGS, py_blf_shadow_doc}, {"shadow_offset", (PyCFunction) py_blf_shadow_offset, METH_VARARGS, py_blf_shadow_offset_doc}, {"size", (PyCFunction) py_blf_size, METH_VARARGS, py_blf_size_doc}, + {"color", (PyCFunction) py_blf_color, METH_VARARGS, py_blf_color_doc}, {"load", (PyCFunction) py_blf_load, METH_VARARGS, py_blf_load_doc}, {"unload", (PyCFunction) py_blf_unload, METH_VARARGS, py_blf_unload_doc}, {NULL, NULL, 0, NULL} diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c index 553f7e43e45..926de79d0ff 100644 --- a/source/blender/python/generic/bpy_internal_import.c +++ b/source/blender/python/generic/bpy_internal_import.c @@ -43,9 +43,9 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_main.h" /* UNUSED */ #include "BKE_text.h" /* txt_to_buf */ -#include "BKE_main.h" #include "py_capi_utils.h" @@ -116,16 +116,6 @@ void bpy_import_main_set(struct Main *maggie) bpy_import_main = maggie; } -void bpy_import_main_extra_add(struct Main *maggie) -{ - BLI_addhead(&bpy_import_main_list, maggie); -} - -void bpy_import_main_extra_remove(struct Main *maggie) -{ - BLI_remlink_safe(&bpy_import_main_list, maggie); -} - /* returns a dummy filename for a textblock so we can tell what file a text block comes from */ void bpy_text_filename_get(char *fn, size_t fn_len, Text *text) { diff --git a/source/blender/python/generic/bpy_internal_import.h b/source/blender/python/generic/bpy_internal_import.h index 29b11fbe8ff..8de1436ed48 100644 --- a/source/blender/python/generic/bpy_internal_import.h +++ b/source/blender/python/generic/bpy_internal_import.h @@ -51,12 +51,7 @@ PyObject *bpy_text_reimport(PyObject *module, int *found); void bpy_text_filename_get(char *fn, size_t fn_len, struct Text *text); -/* The game engine has its own Main struct, if this is set search this rather than G_MAIN */ struct Main *bpy_import_main_get(void); void bpy_import_main_set(struct Main *maggie); -/* This is used for importing text from dynamically loaded libraries in the game engine */ -void bpy_import_main_extra_add(struct Main *maggie); -void bpy_import_main_extra_remove(struct Main *maggie); - #endif /* __BPY_INTERNAL_IMPORT_H__ */ diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 918ec8fa018..072c11b14e5 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -422,11 +422,18 @@ static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob) return IDP_New(IDP_STRING, &val, name); } -static int idp_array_type_from_format_char(char format) +static int idp_array_type_from_formatstr_and_size(const char *typestr, Py_ssize_t itemsize) { - if (format == 'i') return IDP_INT; - if (format == 'f') return IDP_FLOAT; - if (format == 'd') return IDP_DOUBLE; + char format = PyC_StructFmt_type_from_str(typestr); + + if (PyC_StructFmt_type_is_float_any(format)) { + if (itemsize == 4) return IDP_FLOAT; + if (itemsize == 8) return IDP_DOUBLE; + } + if (PyC_StructFmt_type_is_int_any(format)) { + if (itemsize == 4) return IDP_INT; + } + return -1; } @@ -443,13 +450,13 @@ static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffe IDProperty *prop; IDPropertyTemplate val = {0}; - int format = idp_array_type_from_format_char(*buffer->format); - if (format == -1) { + int id_type = idp_array_type_from_formatstr_and_size(buffer->format, buffer->itemsize); + if (id_type == -1) { /* should never happen as the type has been checked before */ return NULL; } else { - val.array.type = format; + val.array.type = id_type; val.array.len = buffer->len / buffer->itemsize; } prop = IDP_New(IDP_ARRAY, &val, name); @@ -533,8 +540,10 @@ static IDProperty *idp_from_PySequence(const char *name, PyObject *ob) if (PyObject_CheckBuffer(ob)) { PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT); - char format = *buffer.format; - if (ELEM(format, 'i', 'f', 'd')) { + char format = PyC_StructFmt_type_from_str(buffer.format); + if (PyC_StructFmt_type_is_float_any(format) || + (PyC_StructFmt_type_is_int_any(format) && buffer.itemsize == 4)) + { use_buffer = true; } else { @@ -1802,7 +1811,6 @@ PyObject *BPyInit_idprop(void) /* idprop.types */ PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); return mod; } diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 62b24618d3f..d158c92baae 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -436,17 +436,24 @@ PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *for if (PyErr_Occurred()) { PyObject *error_type, *error_value, *error_traceback; PyErr_Fetch(&error_type, &error_value, &error_traceback); - PyErr_Format(exception_type_prefix, - "%S, %.200s(%S)", - error_value_prefix, - Py_TYPE(error_value)->tp_name, - error_value - ); + + if (PyUnicode_Check(error_value)) { + PyErr_Format(exception_type_prefix, + "%S, %S", + error_value_prefix, + error_value); + } + else { + PyErr_Format(exception_type_prefix, + "%S, %.200s(%S)", + error_value_prefix, + Py_TYPE(error_value)->tp_name, + error_value); + } } else { PyErr_SetObject(exception_type_prefix, - error_value_prefix - ); + error_value_prefix); } Py_XDECREF(error_value_prefix); @@ -455,6 +462,11 @@ PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *for return NULL; } +PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *str) +{ + return PyC_Err_Format_Prefix(exception_type_prefix, "%s", str); +} + /** * Use for Python callbacks run directly from C, * when we can't use normal methods of raising exceptions. @@ -1327,6 +1339,84 @@ uint32_t PyC_Long_AsU32(PyObject *value) * PyC_Long_AsU64 */ +/* -------------------------------------------------------------------- */ + +/** \name Py_buffer Utils + * + * \{ */ + +char PyC_StructFmt_type_from_str(const char *typestr) +{ + switch (typestr[0]) { + case '!': + case '<': + case '=': + case '>': + case '@': + return typestr[1]; + default: + return typestr[0]; + } +} + +bool PyC_StructFmt_type_is_float_any(char format) +{ + switch (format) { + case 'f': + case 'd': + case 'e': + return true; + default: + return false; + } +} + +bool PyC_StructFmt_type_is_int_any(char format) +{ + switch (format) { + case 'i': + case 'I': + case 'l': + case 'L': + case 'h': + case 'H': + case 'b': + case 'B': + case 'q': + case 'Q': + case 'n': + case 'N': + case 'P': + return true; + default: + return false; + } +} + +bool PyC_StructFmt_type_is_byte(char format) +{ + switch (format) { + case 'c': + case 's': + case 'p': + return true; + default: + return false; + } +} + +bool PyC_StructFmt_type_is_bool(char format) +{ + switch (format) { + case '?': + return true; + default: + return false; + } +} + +/** \} */ + #ifdef __GNUC__ # pragma warning(pop) #endif diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 4cf6d6b26de..43e397153ff 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -38,7 +38,10 @@ PyObject *PyC_ExceptionBuffer(void); PyObject *PyC_ExceptionBuffer_Simple(void); PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); PyObject *PyC_FrozenSetFromStrings(const char **strings); + PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...); +PyObject *PyC_Err_SetString_Prefix(PyObject *exception_type_prefix, const char *str); + void PyC_Err_PrintWithFunc(PyObject *py_func); void PyC_FileAndNum(const char **filename, int *lineno); @@ -76,7 +79,7 @@ PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size); const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */ const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce); -/* name namespace function for bpy & bge */ +/* name namespace function for bpy */ PyObject *PyC_DefaultNameSpace(const char *filename); void PyC_RunQuicky(const char *filepath, int n, ...); bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]); @@ -131,4 +134,11 @@ Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value) { return (int32_t)_PyL Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value) { return (int64_t)PyLong_AsLongLong(value); } Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value) { return (uint64_t)PyLong_AsUnsignedLongLong(value); } +/* utils for format string in `struct` module style syntax */ +char PyC_StructFmt_type_from_str(const char *typestr); +bool PyC_StructFmt_type_is_float_any(char format); +bool PyC_StructFmt_type_is_int_any(char format); +bool PyC_StructFmt_type_is_byte(char format); +bool PyC_StructFmt_type_is_bool(char format); + #endif /* __PY_CAPI_UTILS_H__ */ diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt new file mode 100644 index 00000000000..fcb0b828ffb --- /dev/null +++ b/source/blender/python/gpu/CMakeLists.txt @@ -0,0 +1,62 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Campbell Barton +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../../blenkernel + ../../blenlib + ../../gpu + ../../makesdna + ../../../../intern/guardedalloc + ../../../../intern/glew-mx +) + +set(INC_SYS + ${GLEW_INCLUDE_PATH} + ${PYTHON_INCLUDE_DIRS} +) + +set(SRC + gpu_py_api.c + gpu_py_batch.c + gpu_py_element.c + gpu_py_matrix.c + gpu_py_offscreen.c + gpu_py_select.c + gpu_py_shader.c + gpu_py_types.c + gpu_py_vertex_buffer.c + gpu_py_vertex_format.c + + gpu_py_api.h + gpu_py_batch.h + gpu_py_element.h + gpu_py_matrix.h + gpu_py_offscreen.h + gpu_py_select.h + gpu_py_shader.h + gpu_py_types.h + gpu_py_vertex_buffer.h + gpu_py_vertex_format.h +) + +add_definitions(${GL_DEFINITIONS}) + +blender_add_lib(bf_python_gpu "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c new file mode 100644 index 00000000000..7e999bdcc2d --- /dev/null +++ b/source/blender/python/gpu/gpu_py_api.c @@ -0,0 +1,165 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_api.c + * \ingroup bpygpu + * + * Experimental Python API, not considered public yet (called '_gpu'), + * we may re-expose as public later. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "BLI_utildefines.h" + +#include "../generic/python_utildefines.h" + +#include "GPU_init_exit.h" +#include "GPU_primitive.h" + +#include "gpu_py_matrix.h" +#include "gpu_py_select.h" +#include "gpu_py_types.h" + +#include "gpu_py_api.h" /* own include */ + + +/* -------------------------------------------------------------------- */ + +/** \name Utils to invalidate functions + * \{ */ + +bool bpygpu_is_initialized_or_error(void) +{ + if (!GPU_is_initialized()) { + PyErr_SetString( + PyExc_SystemError, + "GPU functions for drawing are not available in background mode"); + + return false; + } + + return true; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Primitive Type Utils + * \{ */ + +int bpygpu_ParsePrimType(PyObject *o, void *p) +{ + Py_ssize_t mode_id_len; + const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len); + if (mode_id == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } +#define MATCH_ID(id) \ + if (mode_id_len == strlen(STRINGIFY(id))) { \ + if (STREQ(mode_id, STRINGIFY(id))) { \ + mode = GPU_PRIM_##id; \ + goto success; \ + } \ + } ((void)0) + + GPUPrimType mode; + MATCH_ID(POINTS); + MATCH_ID(LINES); + MATCH_ID(TRIS); + MATCH_ID(LINE_STRIP); + MATCH_ID(LINE_LOOP); + MATCH_ID(TRI_STRIP); + MATCH_ID(TRI_FAN); + MATCH_ID(LINE_STRIP_ADJ); + +#undef MATCH_ID + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + mode_id); + return 0; + +success: + (*(GPUPrimType *)p) = mode; + return 1; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name GPU Module + * \{ */ + + +PyDoc_STRVAR(GPU_doc, +"This module provides Python wrappers for the GPU implementation in Blender. " +"Some higher level functions can be found in the `gpu_extras` module. " +"\n\n" +"Submodules:\n" +"\n" +".. toctree::\n" +" :maxdepth: 1\n" +"\n" +" gpu.types.rst\n" +" gpu.shader.rst\n" +" gpu.matrix.rst\n" +" gpu.select.rst\n" +"\n" +); +static struct PyModuleDef GPU_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu", + .m_doc = GPU_doc, +}; + +PyObject *BPyInit_gpu(void) +{ + PyObject *sys_modules = PyImport_GetModuleDict(); + PyObject *submodule; + PyObject *mod; + + mod = PyModule_Create(&GPU_module_def); + + PyModule_AddObject(mod, "types", (submodule = BPyInit_gpu_types())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + + PyModule_AddObject(mod, "matrix", (submodule = BPyInit_gpu_matrix())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + + PyModule_AddObject(mod, "select", (submodule = BPyInit_gpu_select())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + + PyModule_AddObject(mod, "shader", (submodule = BPyInit_gpu_shader())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + + return mod; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_api.h b/source/blender/python/gpu/gpu_py_api.h new file mode 100644 index 00000000000..af08881b723 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_api.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_api.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_API_H__ +#define __GPU_PY_API_H__ + + +int bpygpu_ParsePrimType(PyObject *o, void *p); + +PyObject *BPyInit_gpu(void); + +bool bpygpu_is_initialized_or_error(void); +#define BPYGPU_IS_INIT_OR_ERROR_OBJ if (UNLIKELY(!bpygpu_is_initialized_or_error())) { return NULL; } ((void)0) +#define BPYGPU_IS_INIT_OR_ERROR_INT if (UNLIKELY(!bpygpu_is_initialized_or_error())) { return -1; } ((void)0) + +#endif /* __GPU_PY_API_H__ */ diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c new file mode 100644 index 00000000000..a50ea32b5dd --- /dev/null +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -0,0 +1,386 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2015, Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_batch.c + * \ingroup bpygpu + * + * This file defines the offscreen functionalities of the 'gpu' module + * used for off-screen OpenGL rendering. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_global.h" + +#include "GPU_batch.h" + +#include "../mathutils/mathutils.h" + +#include "../generic/py_capi_utils.h" + +#include "gpu_py_api.h" +#include "gpu_py_shader.h" +#include "gpu_py_vertex_buffer.h" +#include "gpu_py_element.h" +#include "gpu_py_batch.h" /* own include */ + + +/* -------------------------------------------------------------------- */ +/** \name Utility Functions + * \{ */ + +static bool bpygpu_batch_is_program_or_error(BPyGPUBatch *self) +{ + if (!glIsProgram(self->batch->program)) { + PyErr_SetString( + PyExc_RuntimeError, + "batch does not have any program assigned to it"); + return false; + } + return true; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name GPUBatch Type + * \{ */ + +static PyObject *bpygpu_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + BPYGPU_IS_INIT_OR_ERROR_OBJ; + + const char *exc_str_missing_arg = "GPUBatch.__new__() missing required argument '%s' (pos %d)"; + + struct { + GPUPrimType type_id; + BPyGPUVertBuf *py_vertbuf; + BPyGPUIndexBuf *py_indexbuf; + } params = {GPU_PRIM_NONE, NULL, NULL}; + + static const char *_keywords[] = {"type", "buf", "elem", NULL}; + static _PyArg_Parser _parser = {"|$O&O!O!:GPUBatch.__new__", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + bpygpu_ParsePrimType, ¶ms.type_id, + &BPyGPUVertBuf_Type, ¶ms.py_vertbuf, + &BPyGPUIndexBuf_Type, ¶ms.py_indexbuf)) + { + return NULL; + } + + if (params.type_id == GPU_PRIM_NONE) { + PyErr_Format(PyExc_TypeError, + exc_str_missing_arg, _keywords[0], 1); + return NULL; + } + + if (params.py_vertbuf == NULL) { + PyErr_Format(PyExc_TypeError, + exc_str_missing_arg, _keywords[1], 2); + return NULL; + } + + GPUBatch *batch = GPU_batch_create( + params.type_id, + params.py_vertbuf->buf, + params.py_indexbuf ? params.py_indexbuf->elem : NULL); + + BPyGPUBatch *ret = (BPyGPUBatch *)BPyGPUBatch_CreatePyObject(batch); + +#ifdef USE_GPU_PY_REFERENCES + ret->references = PyList_New(params.py_indexbuf ? 2 : 1); + PyList_SET_ITEM(ret->references, 0, (PyObject *)params.py_vertbuf); + Py_INCREF(params.py_vertbuf); + + if (params.py_indexbuf != NULL) { + PyList_SET_ITEM(ret->references, 1, (PyObject *)params.py_indexbuf); + Py_INCREF(params.py_indexbuf); + } + + PyObject_GC_Track(ret); +#endif + + return (PyObject *)ret; +} + +PyDoc_STRVAR(bpygpu_Batch_vertbuf_add_doc, +".. method:: vertbuf_add(buf)\n" +"\n" +" Add another vertex buffer to the Batch.\n" +" It is not possible to add more vertices to the batch using this method.\n" +" Instead it can be used to add more attributes to the existing vertices.\n" +" A good use case would be when you have a separate vertex buffer for vertex positions and vertex normals.\n" +" Current a batch can have at most " STRINGIFY(GPU_BATCH_VBO_MAX_LEN) " vertex buffers.\n" +"\n" +" :param buf: The vertex buffer that will be added to the batch.\n" +" :type buf: :class:`gpu.types.GPUVertBuf`\n" +); +static PyObject *bpygpu_Batch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf) +{ + if (!BPyGPUVertBuf_Check(py_buf)) { + PyErr_Format(PyExc_TypeError, + "Expected a GPUVertBuf, got %s", + Py_TYPE(py_buf)->tp_name); + return NULL; + } + + if (self->batch->verts[0]->vertex_len != py_buf->buf->vertex_len) { + PyErr_Format(PyExc_TypeError, + "Expected %d length, got %d", + self->batch->verts[0]->vertex_len, py_buf->buf->vertex_len); + return NULL; + } + + if (self->batch->verts[GPU_BATCH_VBO_MAX_LEN - 1] != NULL) { + PyErr_SetString( + PyExc_RuntimeError, + "Maximum number of vertex buffers exceeded: " STRINGIFY(GPU_BATCH_VBO_MAX_LEN)); + return NULL; + } + +#ifdef USE_GPU_PY_REFERENCES + /* Hold user */ + PyList_Append(self->references, (PyObject *)py_buf); +#endif + + GPU_batch_vertbuf_add(self->batch, py_buf->buf); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_Batch_program_set_doc, +".. method:: program_set(program)\n" +"\n" +" Assign a shader to this batch that will be used for drawing when not overwritten later.\n" +" Note: This method has to be called in the draw context that the batch will be drawn in.\n" +" This function does not need to be called when you always set the shader when calling `batch.draw`.\n" +"\n" +" :param program: The program/shader the batch will use in future draw calls.\n" +" :type program: :class:`gpu.types.GPUShader`\n" +); +static PyObject *bpygpu_Batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_shader) +{ + if (!BPyGPUShader_Check(py_shader)) { + PyErr_Format(PyExc_TypeError, + "Expected a GPUShader, got %s", + Py_TYPE(py_shader)->tp_name); + return NULL; + } + + GPUShader *shader = py_shader->shader; + GPU_batch_program_set( + self->batch, + GPU_shader_get_program(shader), + GPU_shader_get_interface(shader)); + +#ifdef USE_GPU_PY_REFERENCES + /* Remove existing user (if any), hold new user. */ + int i = PyList_GET_SIZE(self->references); + while (--i != -1) { + PyObject *py_shader_test = PyList_GET_ITEM(self->references, i); + if (BPyGPUShader_Check(py_shader_test)) { + PyList_SET_ITEM(self->references, i, (PyObject *)py_shader); + Py_INCREF(py_shader); + Py_DECREF(py_shader_test); + /* Only ever reference one shader. */ + break; + } + } + if (i != -1) { + PyList_Append(self->references, (PyObject *)py_shader); + } +#endif + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_Batch_draw_doc, +".. method:: draw(program=None)\n" +"\n" +" Run the drawing program with the parameters assigned to the batch.\n" +"\n" +" :param program: Program that performs the drawing operations.\n" +" If ``None`` is passed, the last program setted to this batch will run.\n" +" :type program: :class:`gpu.types.GPUShader`\n" +); +static PyObject *bpygpu_Batch_draw(BPyGPUBatch *self, PyObject *args) +{ + BPyGPUShader *py_program = NULL; + + if (!PyArg_ParseTuple( + args, "|O!:GPUBatch.draw", + &BPyGPUShader_Type, &py_program)) + { + return NULL; + } + else if (py_program == NULL) { + if (!bpygpu_batch_is_program_or_error(self)) { + return NULL; + } + } + else if (self->batch->program != GPU_shader_get_program(py_program->shader)) { + GPU_batch_program_set( + self->batch, + GPU_shader_get_program(py_program->shader), + GPU_shader_get_interface(py_program->shader)); + } + + GPU_batch_draw(self->batch); + Py_RETURN_NONE; +} + +static PyObject *bpygpu_Batch_program_use_begin(BPyGPUBatch *self) +{ + if (!bpygpu_batch_is_program_or_error(self)) { + return NULL; + } + GPU_batch_program_use_begin(self->batch); + Py_RETURN_NONE; +} + +static PyObject *bpygpu_Batch_program_use_end(BPyGPUBatch *self) +{ + if (!bpygpu_batch_is_program_or_error(self)) { + return NULL; + } + GPU_batch_program_use_end(self->batch); + Py_RETURN_NONE; +} + +static struct PyMethodDef bpygpu_Batch_methods[] = { + {"vertbuf_add", (PyCFunction)bpygpu_Batch_vertbuf_add, + METH_O, bpygpu_Batch_vertbuf_add_doc}, + {"program_set", (PyCFunction)bpygpu_Batch_program_set, + METH_O, bpygpu_Batch_program_set_doc}, + {"draw", (PyCFunction) bpygpu_Batch_draw, + METH_VARARGS, bpygpu_Batch_draw_doc}, + {"_program_use_begin", (PyCFunction)bpygpu_Batch_program_use_begin, + METH_NOARGS, ""}, + {"_program_use_end", (PyCFunction)bpygpu_Batch_program_use_end, + METH_NOARGS, ""}, + {NULL, NULL, 0, NULL} +}; + +#ifdef USE_GPU_PY_REFERENCES + +static int bpygpu_Batch_traverse(BPyGPUBatch *self, visitproc visit, void *arg) +{ + Py_VISIT(self->references); + return 0; +} + +static int bpygpu_Batch_clear(BPyGPUBatch *self) +{ + Py_CLEAR(self->references); + return 0; +} + +#endif + +static void bpygpu_Batch_dealloc(BPyGPUBatch *self) +{ + GPU_batch_discard(self->batch); + +#ifdef USE_GPU_PY_REFERENCES + if (self->references) { + PyObject_GC_UnTrack(self); + bpygpu_Batch_clear(self); + Py_XDECREF(self->references); + } +#endif + + Py_TYPE(self)->tp_free(self); +} + +PyDoc_STRVAR(py_gpu_batch_doc, +".. class:: GPUBatch(type, buf, elem=None)\n" +"\n" +" Reusable container for drawable geometry.\n" +"\n" +" :arg type: One of these primitive types: {\n" +" `POINTS`,\n" +" `LINES`,\n" +" `TRIS`,\n" +" `LINE_STRIP`,\n" +" `LINE_LOOP`,\n" +" `TRI_STRIP`,\n" +" `TRI_FAN`,\n" +" `LINES_ADJ`,\n" +" `TRIS_ADJ`,\n" +" `LINE_STRIP_ADJ` }\n" +" :type type: `str`\n" +" :arg buf: Vertex buffer containing all or some of the attributes required for drawing.\n" +" :type buf: :class:`gpu.types.GPUVertBuf`\n" +" :arg elem: An optional index buffer.\n" +" :type elem: :class:`gpu.types.GPUIndexBuf`\n" +); +PyTypeObject BPyGPUBatch_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUBatch", + .tp_basicsize = sizeof(BPyGPUBatch), + .tp_dealloc = (destructor)bpygpu_Batch_dealloc, +#ifdef USE_GPU_PY_REFERENCES + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_doc = py_gpu_batch_doc, + .tp_traverse = (traverseproc)bpygpu_Batch_traverse, + .tp_clear = (inquiry)bpygpu_Batch_clear, +#else + .tp_flags = Py_TPFLAGS_DEFAULT, +#endif + .tp_methods = bpygpu_Batch_methods, + .tp_new = bpygpu_Batch_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Public API +* \{ */ + +PyObject *BPyGPUBatch_CreatePyObject(GPUBatch *batch) +{ + BPyGPUBatch *self; + +#ifdef USE_GPU_PY_REFERENCES + self = (BPyGPUBatch *)_PyObject_GC_New(&BPyGPUBatch_Type); + self->references = NULL; +#else + self = PyObject_New(BPyGPUBatch, &BPyGPUBatch_Type); +#endif + + self->batch = batch; + + return (PyObject *)self; +} + +/** \} */ + +#undef BPY_GPU_BATCH_CHECK_OBJ diff --git a/source/blender/python/gpu/gpu_py_batch.h b/source/blender/python/gpu/gpu_py_batch.h new file mode 100644 index 00000000000..c77574428db --- /dev/null +++ b/source/blender/python/gpu/gpu_py_batch.h @@ -0,0 +1,48 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_batch.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_BATCH_H__ +#define __GPU_PY_BATCH_H__ + +#include "BLI_compiler_attrs.h" + +#define USE_GPU_PY_REFERENCES + +extern PyTypeObject BPyGPUBatch_Type; + +#define BPyGPUBatch_Check(v) (Py_TYPE(v) == &BPyGPUBatch_Type) + +typedef struct BPyGPUBatch { + PyObject_VAR_HEAD + /* The batch is owned, we may support thin wrapped batches later. */ + struct GPUBatch *batch; +#ifdef USE_GPU_PY_REFERENCES + /* Just to keep a user to prevent freeing buf's we're using */ + PyObject *references; +#endif +} BPyGPUBatch; + +PyObject *BPyGPUBatch_CreatePyObject(struct GPUBatch *batch) ATTR_NONNULL(1); + +#endif /* __GPU_PY_BATCH_H__ */ diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c new file mode 100644 index 00000000000..2faf57ac55c --- /dev/null +++ b/source/blender/python/gpu/gpu_py_element.c @@ -0,0 +1,244 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_element.c + * \ingroup bpygpu + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "GPU_element.h" + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "gpu_py_api.h" +#include "gpu_py_element.h" /* own include */ + + +/* -------------------------------------------------------------------- */ + +/** \name IndexBuf Type + * \{ */ + +static PyObject *bpygpu_IndexBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + BPYGPU_IS_INIT_OR_ERROR_OBJ; + + const char *error_prefix = "IndexBuf.__new__"; + bool ok = true; + + struct { + GPUPrimType type_id; + PyObject *seq; + } params; + + uint verts_per_prim; + uint index_len; + GPUIndexBufBuilder builder; + + static const char *_keywords[] = {"type", "seq", NULL}; + static _PyArg_Parser _parser = {"$O&O:IndexBuf.__new__", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + bpygpu_ParsePrimType, ¶ms.type_id, + ¶ms.seq)) + { + return NULL; + } + + verts_per_prim = GPU_indexbuf_primitive_len(params.type_id); + if (verts_per_prim == -1) { + PyErr_Format(PyExc_ValueError, + "The argument 'type' must be " + "'POINTS', 'LINES', 'TRIS' or 'LINES_ADJ'"); + return NULL; + } + + if (PyObject_CheckBuffer(params.seq)) { + Py_buffer pybuffer; + + if (PyObject_GetBuffer(params.seq, &pybuffer, PyBUF_FORMAT | PyBUF_ND) == -1) { + /* PyObject_GetBuffer already handles error messages. */ + return NULL; + } + + if (pybuffer.ndim != 1 && pybuffer.shape[1] != verts_per_prim) { + PyErr_Format(PyExc_ValueError, + "Each primitive must exactly %d indices", + verts_per_prim); + return NULL; + } + + if (pybuffer.itemsize != 4 || + PyC_StructFmt_type_is_float_any(PyC_StructFmt_type_from_str(pybuffer.format))) + { + PyErr_Format(PyExc_ValueError, + "Each index must be an 4-bytes integer value"); + return NULL; + } + + index_len = pybuffer.shape[0]; + if (pybuffer.ndim != 1) { + index_len *= pybuffer.shape[1]; + } + + /* The `vertex_len` parameter is only used for asserts in the Debug build. */ + /* Not very useful in python since scripts are often tested in Release build. */ + /* Use `INT_MAX` instead of the actual number of vertices. */ + GPU_indexbuf_init( + &builder, params.type_id, index_len, INT_MAX); + +#if 0 + uint *buf = pybuffer.buf; + for (uint i = index_len; i--; buf++) { + GPU_indexbuf_add_generic_vert(&builder, *buf); + } +#else + memcpy(builder.data, pybuffer.buf, index_len * sizeof(*builder.data)); + builder.index_len = index_len; +#endif + PyBuffer_Release(&pybuffer); + } + else { + PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix); + + if (seq_fast == NULL) { + return false; + } + + const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast); + + PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast); + + index_len = seq_len * verts_per_prim; + + /* The `vertex_len` parameter is only used for asserts in the Debug build. */ + /* Not very useful in python since scripts are often tested in Release build. */ + /* Use `INT_MAX` instead of the actual number of vertices. */ + GPU_indexbuf_init( + &builder, params.type_id, index_len, INT_MAX); + + if (verts_per_prim == 1) { + for (uint i = 0; i < seq_len; i++) { + GPU_indexbuf_add_generic_vert( + &builder, PyC_Long_AsU32(seq_items[i])); + } + } + else { + int values[4]; + for (uint i = 0; i < seq_len; i++) { + PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix); + if (seq_fast_item == NULL) { + PyErr_Format(PyExc_TypeError, + "%s: expected a sequence, got %s", + error_prefix, Py_TYPE(seq_items[i])->tp_name); + ok = false; + goto finally; + } + + ok = PyC_AsArray_FAST( + values, seq_fast_item, verts_per_prim, + &PyLong_Type, false, error_prefix) == 0; + + if (ok) { + for (uint j = 0; j < verts_per_prim; j++) { + GPU_indexbuf_add_generic_vert(&builder, values[j]); + } + } + Py_DECREF(seq_fast_item); + } + } + + if (PyErr_Occurred()) { + ok = false; + } + +finally: + + Py_DECREF(seq_fast); + } + + if (ok == false) { + MEM_freeN(builder.data); + return NULL; + } + + return BPyGPUIndexBuf_CreatePyObject(GPU_indexbuf_build(&builder)); +} + +static void bpygpu_IndexBuf_dealloc(BPyGPUIndexBuf *self) +{ + GPU_indexbuf_discard(self->elem); + Py_TYPE(self)->tp_free(self); +} + +PyDoc_STRVAR(py_gpu_element_doc, +".. class:: GPUIndexBuf(type, seq)\n" +"\n" +" Contains an index buffer.\n" +"\n" +" :param type: One of these primitive types: {\n" +" `POINTS`,\n" +" `LINES`,\n" +" `TRIS`,\n" +" `LINE_STRIP_ADJ` }\n" +" :type type: `str`\n" +" :param seq: Indices this index buffer will contain.\n" +" Whether a 1D or 2D sequence is required depends on the type.\n" +" Optionally the sequence can support the buffer protocol.\n" +" :type seq: 1D or 2D sequence\n" +); +PyTypeObject BPyGPUIndexBuf_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUIndexBuf", + .tp_basicsize = sizeof(BPyGPUIndexBuf), + .tp_dealloc = (destructor)bpygpu_IndexBuf_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = py_gpu_element_doc, + .tp_new = bpygpu_IndexBuf_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUIndexBuf_CreatePyObject(GPUIndexBuf *elem) +{ + BPyGPUIndexBuf *self; + + self = PyObject_New(BPyGPUIndexBuf, &BPyGPUIndexBuf_Type); + self->elem = elem; + + return (PyObject *)self; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_element.h b/source/blender/python/gpu/gpu_py_element.h new file mode 100644 index 00000000000..e201a767582 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_element.h @@ -0,0 +1,39 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_element.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_ELEMENT_H__ +#define __GPU_PY_ELEMENT_H__ + +extern PyTypeObject BPyGPUIndexBuf_Type; + +#define BPyGPUIndexBuf_Check(v) (Py_TYPE(v) == &BPyGPUIndexBuf_Type) + +typedef struct BPyGPUIndexBuf { + PyObject_VAR_HEAD + struct GPUIndexBuf *elem; +} BPyGPUIndexBuf; + +PyObject *BPyGPUIndexBuf_CreatePyObject(struct GPUIndexBuf *elem); + +#endif /* __GPU_PY_ELEMENT_H__ */ diff --git a/source/blender/python/gpu/gpu_py_matrix.c b/source/blender/python/gpu/gpu_py_matrix.c new file mode 100644 index 00000000000..6c77f2ee02b --- /dev/null +++ b/source/blender/python/gpu/gpu_py_matrix.c @@ -0,0 +1,575 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_matrix.c + * \ingroup bpygpu + * + * This file defines the gpu.matrix stack API. + * + * \warning While these functions attempt to ensure correct stack usage. + * Mixing Python and C functions may still crash on invalid use. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + + +#include "BLI_utildefines.h" + +#include "../mathutils/mathutils.h" + +#include "../generic/py_capi_utils.h" + +#define USE_GPU_PY_MATRIX_API +#include "GPU_matrix.h" +#undef USE_GPU_PY_MATRIX_API + +#include "gpu_py_matrix.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Helper Functions + * \{ */ + +static bool bpygpu_stack_is_push_model_view_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_model_view() >= GPU_PY_MATRIX_STACK_LEN) { + PyErr_SetString(PyExc_RuntimeError, + "Maximum model-view stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached"); + return false; + } + return true; +} + +static bool bpygpu_stack_is_push_projection_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_projection() >= GPU_PY_MATRIX_STACK_LEN) { + PyErr_SetString(PyExc_RuntimeError, + "Maximum projection stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached"); + return false; + } + return true; +} + +static bool bpygpu_stack_is_pop_model_view_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_model_view() == 0) { + PyErr_SetString(PyExc_RuntimeError, + "Minimum model-view stack depth reached"); + return false; + } + return true; +} + +static bool bpygpu_stack_is_pop_projection_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_projection() == 0) { + PyErr_SetString(PyExc_RuntimeError, + "Minimum projection stack depth reached"); + return false; + } + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Manage Stack + * \{ */ + +PyDoc_STRVAR(bpygpu_matrix_push_doc, +".. function:: push()\n" +"\n" +" Add to the model-view matrix stack.\n" +); +static PyObject *bpygpu_matrix_push(PyObject *UNUSED(self)) +{ + if (!bpygpu_stack_is_push_model_view_ok_or_error()) { + return NULL; + } + GPU_matrix_push(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_pop_doc, +".. function:: pop()\n" +"\n" +" Remove the last model-view matrix from the stack.\n" +); +static PyObject *bpygpu_matrix_pop(PyObject *UNUSED(self)) +{ + if (!bpygpu_stack_is_pop_model_view_ok_or_error()) { + return NULL; + } + GPU_matrix_pop(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_push_projection_doc, +".. function:: push_projection()\n" +"\n" +" Add to the projection matrix stack.\n" +); +static PyObject *bpygpu_matrix_push_projection(PyObject *UNUSED(self)) +{ + if (!bpygpu_stack_is_push_projection_ok_or_error()) { + return NULL; + } + GPU_matrix_push_projection(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_pop_projection_doc, +".. function:: pop_projection()\n" +"\n" +" Remove the last projection matrix from the stack.\n" +); +static PyObject *bpygpu_matrix_pop_projection(PyObject *UNUSED(self)) +{ + if (!bpygpu_stack_is_pop_projection_ok_or_error()) { + return NULL; + } + GPU_matrix_pop_projection(); + Py_RETURN_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stack (Context Manager) + * + * Safer alternative to ensure balanced push/pop calls. + * + * \{ */ + +typedef struct { + PyObject_HEAD /* required python macro */ + int type; + int level; +} BPyGPU_MatrixStackContext; + +enum { + PYGPU_MATRIX_TYPE_MODEL_VIEW = 1, + PYGPU_MATRIX_TYPE_PROJECTION = 2, +}; + +static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self); +static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args); + +static PyMethodDef bpygpu_matrix_stack_context_methods[] = { + {"__enter__", (PyCFunction)bpygpu_matrix_stack_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)bpygpu_matrix_stack_context_exit, METH_VARARGS}, + {NULL} +}; + +static PyTypeObject BPyGPU_matrix_stack_context_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUMatrixStackContext", + .tp_basicsize = sizeof(BPyGPU_MatrixStackContext), + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = bpygpu_matrix_stack_context_methods, +}; + +static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self) +{ + /* sanity - should never happen */ + if (self->level != -1) { + PyErr_SetString(PyExc_RuntimeError, "Already in use"); + return NULL; + } + + if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) { + if (!bpygpu_stack_is_push_model_view_ok_or_error()) { + return NULL; + } + GPU_matrix_push(); + self->level = GPU_matrix_stack_level_get_model_view(); + } + else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) { + if (!bpygpu_stack_is_push_projection_ok_or_error()) { + return NULL; + } + GPU_matrix_push_projection(); + self->level = GPU_matrix_stack_level_get_projection(); + } + else { + BLI_assert(0); + } + Py_RETURN_NONE; +} + +static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *UNUSED(args)) +{ + /* sanity - should never happen */ + if (self->level == -1) { + fprintf(stderr, "Not yet in use\n"); + goto finally; + } + + if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) { + const int level = GPU_matrix_stack_level_get_model_view(); + if (level != self->level) { + fprintf(stderr, "Level push/pop mismatch, expected %d, got %d\n", self->level, level); + } + if (level != 0) { + GPU_matrix_pop(); + } + } + else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) { + const int level = GPU_matrix_stack_level_get_projection(); + if (level != self->level) { + fprintf(stderr, "Level push/pop mismatch, expected %d, got %d", self->level, level); + } + if (level != 0) { + GPU_matrix_pop_projection(); + } + } + else { + BLI_assert(0); + } +finally: + Py_RETURN_NONE; +} + +static PyObject *bpygpu_matrix_push_pop_impl(int type) +{ + BPyGPU_MatrixStackContext *ret = PyObject_New(BPyGPU_MatrixStackContext, &BPyGPU_matrix_stack_context_Type); + ret->type = type; + ret->level = -1; + return (PyObject *)ret; +} + +PyDoc_STRVAR(bpygpu_matrix_push_pop_doc, +".. function:: push_pop()\n" +"\n" +" Context manager to ensure balanced push/pop calls, even in the case of an error.\n" +); +static PyObject *bpygpu_matrix_push_pop(PyObject *UNUSED(self)) +{ + return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_MODEL_VIEW); +} + +PyDoc_STRVAR(bpygpu_matrix_push_pop_projection_doc, +".. function:: push_pop_projection()\n" +"\n" +" Context manager to ensure balanced push/pop calls, even in the case of an error.\n" +); +static PyObject *bpygpu_matrix_push_pop_projection(PyObject *UNUSED(self)) +{ + return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_PROJECTION); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Manipulate State + * \{ */ + +PyDoc_STRVAR(bpygpu_matrix_multiply_matrix_doc, +".. function:: multiply_matrix(matrix)\n" +"\n" +" Multiply the current stack matrix.\n" +"\n" +" :param matrix: A 4x4 matrix.\n" +" :type matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value) +{ + MatrixObject *pymat; + if (!Matrix_Parse4x4(value, &pymat)) { + return NULL; + } + GPU_matrix_mul(pymat->matrix); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_scale_doc, +".. function:: scale(scale)\n" +"\n" +" Scale the current stack matrix.\n" +"\n" +" :param scale: Scale the current stack matrix.\n" +" :type scale: sequence of 2 or 3 floats\n" +); +static PyObject *bpygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value) +{ + float scale[3]; + int len; + if ((len = mathutils_array_parse(scale, 2, 3, value, "gpu.matrix.scale(): invalid vector arg")) == -1) { + return NULL; + } + if (len == 2) { + GPU_matrix_scale_2fv(scale); + } + else { + GPU_matrix_scale_3fv(scale); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_scale_uniform_doc, +".. function:: scale_uniform(scale)\n" +"\n" +" :param scale: Scale the current stack matrix.\n" +" :type scale: float\n" +); +static PyObject *bpygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value) +{ + float scalar; + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + "expected a number, not %.200s", + Py_TYPE(value)->tp_name); + return NULL; + } + GPU_matrix_scale_1f(scalar); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_translate_doc, +".. function:: translate(offset)\n" +"\n" +" Scale the current stack matrix.\n" +"\n" +" :param offset: Translate the current stack matrix.\n" +" :type offset: sequence of 2 or 3 floats\n" +); +static PyObject *bpygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value) +{ + float offset[3]; + int len; + if ((len = mathutils_array_parse(offset, 2, 3, value, "gpu.matrix.translate(): invalid vector arg")) == -1) { + return NULL; + } + if (len == 2) { + GPU_matrix_translate_2fv(offset); + } + else { + GPU_matrix_translate_3fv(offset); + } + Py_RETURN_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Write State + * \{ */ + +PyDoc_STRVAR(bpygpu_matrix_reset_doc, +".. function:: reset()\n" +"\n" +" Empty stack and set to identity.\n" +); +static PyObject *bpygpu_matrix_reset(PyObject *UNUSED(self)) +{ + GPU_matrix_reset(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_load_identity_doc, +".. function:: load_identity()\n" +"\n" +" Empty stack and set to identity.\n" +); +static PyObject *bpygpu_matrix_load_identity(PyObject *UNUSED(self)) +{ + GPU_matrix_identity_set(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_load_matrix_doc, +".. function:: load_matrix(matrix)\n" +"\n" +" Load a matrix into the stack.\n" +"\n" +" :param matrix: A 4x4 matrix.\n" +" :type matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value) +{ + MatrixObject *pymat; + if (!Matrix_Parse4x4(value, &pymat)) { + return NULL; + } + GPU_matrix_set(pymat->matrix); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_matrix_load_projection_matrix_doc, +".. function:: load_projection_matrix(matrix)\n" +"\n" +" Load a projection matrix into the stack.\n" +"\n" +" :param matrix: A 4x4 matrix.\n" +" :type matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_matrix_load_projection_matrix(PyObject *UNUSED(self), PyObject *value) +{ + MatrixObject *pymat; + if (!Matrix_Parse4x4(value, &pymat)) { + return NULL; + } + GPU_matrix_projection_set(pymat->matrix); + Py_RETURN_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read State + * \{ */ + +PyDoc_STRVAR(bpygpu_matrix_get_projection_matrix_doc, +".. function:: get_projection_matrix()\n" +"\n" +" Return a copy of the projection matrix.\n" +"\n" +" :return: A 4x4 projection matrix.\n" +" :rtype: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_matrix_get_projection_matrix(PyObject *UNUSED(self)) +{ + float matrix[4][4]; + GPU_matrix_projection_get(matrix); + return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL); +} + + +PyDoc_STRVAR(bpygpu_matrix_get_model_view_matrix_doc, +".. function:: get_model_view_matrix()\n" +"\n" +" Return a copy of the model-view matrix.\n" +"\n" +" :return: A 4x4 view matrix.\n" +" :rtype: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_matrix_get_model_view_matrix(PyObject *UNUSED(self)) +{ + float matrix[4][4]; + GPU_matrix_model_view_get(matrix); + return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL); +} + +PyDoc_STRVAR(bpygpu_matrix_get_normal_matrix_doc, +".. function:: get_normal_matrix()\n" +"\n" +" Return a copy of the normal matrix.\n" +"\n" +" :return: A 3x3 normal matrix.\n" +" :rtype: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_matrix_get_normal_matrix(PyObject *UNUSED(self)) +{ + float matrix[3][3]; + GPU_matrix_normal_get(matrix); + return Matrix_CreatePyObject(&matrix[0][0], 3, 3, NULL); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Module + * \{ */ + +static struct PyMethodDef bpygpu_matrix_methods[] = { + /* Manage Stack */ + {"push", (PyCFunction)bpygpu_matrix_push, + METH_NOARGS, bpygpu_matrix_push_doc}, + {"pop", (PyCFunction)bpygpu_matrix_pop, + METH_NOARGS, bpygpu_matrix_pop_doc}, + + {"push_projection", (PyCFunction)bpygpu_matrix_push_projection, + METH_NOARGS, bpygpu_matrix_push_projection_doc}, + {"pop_projection", (PyCFunction)bpygpu_matrix_pop_projection, + METH_NOARGS, bpygpu_matrix_pop_projection_doc}, + + /* Stack (Context Manager) */ + {"push_pop", (PyCFunction)bpygpu_matrix_push_pop, + METH_NOARGS, bpygpu_matrix_push_pop_doc}, + {"push_pop_projection", (PyCFunction)bpygpu_matrix_push_pop_projection, + METH_NOARGS, bpygpu_matrix_push_pop_projection_doc}, + + /* Manipulate State */ + {"multiply_matrix", (PyCFunction)bpygpu_matrix_multiply_matrix, + METH_O, bpygpu_matrix_multiply_matrix_doc}, + {"scale", (PyCFunction)bpygpu_matrix_scale, + METH_O, bpygpu_matrix_scale_doc}, + {"scale_uniform", (PyCFunction)bpygpu_matrix_scale_uniform, + METH_O, bpygpu_matrix_scale_uniform_doc}, + {"translate", (PyCFunction)bpygpu_matrix_translate, + METH_O, bpygpu_matrix_translate_doc}, + + /* TODO */ +#if 0 + {"rotate", (PyCFunction)bpygpu_matrix_rotate, + METH_O, bpygpu_matrix_rotate_doc}, + {"rotate_axis", (PyCFunction)bpygpu_matrix_rotate_axis, + METH_O, bpygpu_matrix_rotate_axis_doc}, + {"look_at", (PyCFunction)bpygpu_matrix_look_at, + METH_O, bpygpu_matrix_look_at_doc}, +#endif + + /* Write State */ + {"reset", (PyCFunction)bpygpu_matrix_reset, + METH_NOARGS, bpygpu_matrix_reset_doc}, + {"load_identity", (PyCFunction)bpygpu_matrix_load_identity, + METH_NOARGS, bpygpu_matrix_load_identity_doc}, + {"load_matrix", (PyCFunction)bpygpu_matrix_load_matrix, + METH_O, bpygpu_matrix_load_matrix_doc}, + {"load_projection_matrix", (PyCFunction)bpygpu_matrix_load_projection_matrix, + METH_O, bpygpu_matrix_load_projection_matrix_doc}, + + /* Read State */ + {"get_projection_matrix", (PyCFunction)bpygpu_matrix_get_projection_matrix, + METH_NOARGS, bpygpu_matrix_get_projection_matrix_doc}, + {"get_model_view_matrix", (PyCFunction)bpygpu_matrix_get_model_view_matrix, + METH_NOARGS, bpygpu_matrix_get_model_view_matrix_doc}, + {"get_normal_matrix", (PyCFunction)bpygpu_matrix_get_normal_matrix, + METH_NOARGS, bpygpu_matrix_get_normal_matrix_doc}, + + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(bpygpu_matrix_doc, +"This module provides access to the matrix stack." +); +static PyModuleDef BPyGPU_matrix_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu.matrix", + .m_doc = bpygpu_matrix_doc, + .m_methods = bpygpu_matrix_methods, +}; + +PyObject *BPyInit_gpu_matrix(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&BPyGPU_matrix_module_def); + + if (PyType_Ready(&BPyGPU_matrix_stack_context_Type) < 0) { + return NULL; + } + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_matrix.h b/source/blender/python/gpu/gpu_py_matrix.h new file mode 100644 index 00000000000..7bd6318611d --- /dev/null +++ b/source/blender/python/gpu/gpu_py_matrix.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_matrix.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_MATRIX_H__ +#define __GPU_PY_MATRIX_H__ + +PyObject *BPyInit_gpu_matrix(void); + +#endif /* __GPU_PY_MATRIX_H__ */ diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c new file mode 100644 index 00000000000..5dc6e36ca56 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -0,0 +1,374 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2015, Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_offscreen.c + * \ingroup bpygpu + * + * This file defines the offscreen functionalities of the 'gpu' module + * used for off-screen OpenGL rendering. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_scene.h" + +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" + +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + +#include "../editors/include/ED_view3d.h" + +#include "../mathutils/mathutils.h" + +#include "../generic/py_capi_utils.h" + +#include "gpu_py_api.h" +#include "gpu_py_offscreen.h" /* own include */ + + + /* -------------------------------------------------------------------- */ + + /** \name GPUOffScreen Common Utilities + * \{ */ + +static int bpygpu_offscreen_valid_check(BPyGPUOffScreen *bpygpu_ofs) +{ + if (UNLIKELY(bpygpu_ofs->ofs == NULL)) { + PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid"); + return -1; + } + return 0; +} + +#define BPY_GPU_OFFSCREEN_CHECK_OBJ(bpygpu) { \ + if (UNLIKELY(bpygpu_offscreen_valid_check(bpygpu) == -1)) { \ + return NULL; \ + } \ +} ((void)0) + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name GPUOffscreen Type + * \{ */ + + +static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds) +{ + BPYGPU_IS_INIT_OR_ERROR_OBJ; + + GPUOffScreen *ofs; + int width, height, samples = 0; + char err_out[256]; + + static const char *_keywords[] = {"width", "height", "samples", NULL}; + static _PyArg_Parser _parser = {"ii|i:GPUOffScreen.__new__", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + &width, &height, &samples)) + { + return NULL; + } + + ofs = GPU_offscreen_create(width, height, samples, true, false, err_out); + + if (ofs == NULL) { + PyErr_Format(PyExc_RuntimeError, + "gpu.offscreen.new(...) failed with '%s'", + err_out[0] ? err_out : "unknown error"); + return NULL; + } + + return BPyGPUOffScreen_CreatePyObject(ofs); +} + +PyDoc_STRVAR(bpygpu_offscreen_width_doc, "Width of the texture.\n\n:type: `int`"); +static PyObject *bpygpu_offscreen_width_get(BPyGPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + return PyLong_FromLong(GPU_offscreen_width(self->ofs)); +} + +PyDoc_STRVAR(bpygpu_offscreen_height_doc, "Height of the texture.\n\n:type: `int`"); +static PyObject *bpygpu_offscreen_height_get(BPyGPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + return PyLong_FromLong(GPU_offscreen_height(self->ofs)); +} + +PyDoc_STRVAR(bpygpu_offscreen_color_texture_doc, "OpenGL bindcode for the color texture.\n\n:type: `int`"); +static PyObject *bpygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + GPUTexture *texture = GPU_offscreen_color_texture(self->ofs); + return PyLong_FromLong(GPU_texture_opengl_bindcode(texture)); +} + +PyDoc_STRVAR(bpygpu_offscreen_bind_doc, +".. method:: bind(save=True)\n" +"\n" +" Bind the offscreen object.\n" +" To make sure that the offscreen gets unbind whether an exception occurs or not, pack it into a `with` statement.\n" +"\n" +" :arg save: Save the current OpenGL state, so that it can be restored when unbinding.\n" +" :type save: `bool`\n" +); +static PyObject *bpygpu_offscreen_bind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + bool save = true; + + static const char *_keywords[] = {"save", NULL}; + static _PyArg_Parser _parser = {"|O&:bind", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + PyC_ParseBool, &save)) + { + return NULL; + } + + GPU_offscreen_bind(self->ofs, save); + + self->is_saved = save; + Py_INCREF(self); + + return (PyObject *)self; +} + +PyDoc_STRVAR(bpygpu_offscreen_unbind_doc, +".. method:: unbind(restore=True)\n" +"\n" +" Unbind the offscreen object.\n" +"\n" +" :arg restore: Restore the OpenGL state, can only be used when the state has been saved before.\n" +" :type restore: `bool`\n" +); +static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + bool restore = true; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + static const char *_keywords[] = {"restore", NULL}; + static _PyArg_Parser _parser = {"|O&:unbind", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + PyC_ParseBool, &restore)) + { + return NULL; + } + + GPU_offscreen_unbind(self->ofs, restore); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_offscreen_draw_view3d_doc, +".. method:: draw_view3d(scene, view3d, region, view_matrix, projection_matrix)\n" +"\n" +" Draw the 3d viewport in the offscreen object.\n" +"\n" +" :arg scene: Scene to draw.\n" +" :type scene: :class:`bpy.types.Scene`\n" +" :arg view_layer: View layer to draw.\n" +" :type view_layer: :class:`bpy.types.ViewLayer`\n" +" :arg view3d: 3D View to get the drawing settings from.\n" +" :type view3d: :class:`bpy.types.SpaceView3D`\n" +" :arg region: Region of the 3D View (required as temporary draw target).\n" +" :type region: :class:`bpy.types.Region`\n" +" :arg view_matrix: View Matrix (e.g. ``camera.matrix_world.inverted()``).\n" +" :type view_matrix: :class:`mathutils.Matrix`\n" +" :arg projection_matrix: Projection Matrix (e.g. ``camera.calc_matrix_camera(...)``).\n" +" :type projection_matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + MatrixObject *py_mat_view, *py_mat_projection; + PyObject *py_scene, *py_view_layer, *py_region, *py_view3d; + + struct Depsgraph *depsgraph; + struct Scene *scene; + struct ViewLayer *view_layer; + View3D *v3d; + ARegion *ar; + struct RV3DMatrixStore *rv3d_mats; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + static const char *_keywords[] = { + "scene", "view_layer", "view3d", "region", + "view_matrix", "projection_matrix", NULL}; + + static _PyArg_Parser _parser = {"OOOOO&O&:draw_view3d", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + &py_scene, &py_view_layer, &py_view3d, &py_region, + Matrix_Parse4x4, &py_mat_view, + Matrix_Parse4x4, &py_mat_projection) || + (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) || + !(view_layer = PyC_RNA_AsPointer(py_view_layer, "ViewLayer")) || + !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) || + !(ar = PyC_RNA_AsPointer(py_region, "Region")))) + { + return NULL; + } + + BLI_assert(BKE_id_is_in_global_main(&scene->id)); + + depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + + rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata); + + GPU_offscreen_bind(self->ofs, true); + + ED_view3d_draw_offscreen(depsgraph, + scene, + v3d->shading.type, + v3d, + ar, + GPU_offscreen_width(self->ofs), + GPU_offscreen_height(self->ofs), + (float(*)[4])py_mat_view->matrix, + (float(*)[4])py_mat_projection->matrix, + false, + true, + "", + NULL, + self->ofs, + NULL); + + GPU_offscreen_unbind(self->ofs, true); + + ED_view3d_mats_rv3d_restore(ar->regiondata, rv3d_mats); + MEM_freeN(rv3d_mats); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_offscreen_free_doc, +".. method:: free()\n" +"\n" +" Free the offscreen object.\n" +" The framebuffer, texture and render objects will no longer be accessible.\n" +); +static PyObject *bpygpu_offscreen_free(BPyGPUOffScreen *self) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + GPU_offscreen_free(self->ofs); + self->ofs = NULL; + Py_RETURN_NONE; +} + +static PyObject *bpygpu_offscreen_bind_context_enter(BPyGPUOffScreen *UNUSED(self)) +{ + Py_RETURN_NONE; +} + +static PyObject *bpygpu_offscreen_bind_context_exit(BPyGPUOffScreen *self, PyObject *UNUSED(args)) +{ + GPU_offscreen_unbind(self->ofs, self->is_saved); + Py_RETURN_NONE; +} + +static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self) +{ + if (self->ofs) + GPU_offscreen_free(self->ofs); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyGetSetDef bpygpu_offscreen_getseters[] = { + {(char *)"color_texture", (getter)bpygpu_offscreen_color_texture_get, (setter)NULL, bpygpu_offscreen_color_texture_doc, NULL}, + {(char *)"width", (getter)bpygpu_offscreen_width_get, (setter)NULL, bpygpu_offscreen_width_doc, NULL}, + {(char *)"height", (getter)bpygpu_offscreen_height_get, (setter)NULL, bpygpu_offscreen_height_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +static struct PyMethodDef bpygpu_offscreen_methods[] = { + {"bind", (PyCFunction)bpygpu_offscreen_bind, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_bind_doc}, + {"unbind", (PyCFunction)bpygpu_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_unbind_doc}, + {"draw_view3d", (PyCFunction)bpygpu_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_draw_view3d_doc}, + {"free", (PyCFunction)bpygpu_offscreen_free, METH_NOARGS, bpygpu_offscreen_free_doc}, + {"__enter__", (PyCFunction)bpygpu_offscreen_bind_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)bpygpu_offscreen_bind_context_exit, METH_VARARGS}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(bpygpu_offscreen_doc, +".. class:: GPUOffScreen(width, height, samples=0)\n" +"\n" +" This object gives access to off screen buffers.\n" +"\n" +" :arg width: Horizontal dimension of the buffer.\n" +" :type width: `int`\n" +" :arg height: Vertical dimension of the buffer.\n" +" :type height: `int`\n" +" :arg samples: OpenGL samples to use for MSAA or zero to disable.\n" +" :type samples: `int`\n" +); +PyTypeObject BPyGPUOffScreen_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUOffScreen", + .tp_basicsize = sizeof(BPyGPUOffScreen), + .tp_dealloc = (destructor)BPyGPUOffScreen__tp_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = bpygpu_offscreen_doc, + .tp_methods = bpygpu_offscreen_methods, + .tp_getset = bpygpu_offscreen_getseters, + .tp_new = bpygpu_offscreen_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs) +{ + BPyGPUOffScreen *self; + + self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type); + self->ofs = ofs; + + return (PyObject *)self; +} + +/** \} */ + +#undef BPY_GPU_OFFSCREEN_CHECK_OBJ diff --git a/source/blender/python/gpu/gpu_py_offscreen.h b/source/blender/python/gpu/gpu_py_offscreen.h new file mode 100644 index 00000000000..c4a2d02a694 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_offscreen.h @@ -0,0 +1,42 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_offscreen.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_OFFSCREEN_H__ +#define __GPU_PY_OFFSCREEN_H__ + +#include "BLI_compiler_attrs.h" + +extern PyTypeObject BPyGPUOffScreen_Type; + +#define BPyGPUOffScreen_Check(v) (Py_TYPE(v) == &BPyGPUOffScreen_Type) + +typedef struct BPyGPUOffScreen { + PyObject_HEAD + struct GPUOffScreen *ofs; + bool is_saved; +} BPyGPUOffScreen; + +PyObject *BPyGPUOffScreen_CreatePyObject(struct GPUOffScreen *ofs) ATTR_NONNULL(1); + +#endif /* __GPU_PY_OFFSCREEN_H__ */ diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c new file mode 100644 index 00000000000..56b8b904464 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_select.c @@ -0,0 +1,95 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_select.c + * \ingroup bpygpu + * + * This file defines the gpu.select API. + * + * \note Currently only used for gizmo selection, + * will need to add begin/end and a way to access the hits. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "BLI_utildefines.h" + +#include "../generic/py_capi_utils.h" + +#include "GPU_select.h" + +#include "gpu_py_select.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Methods + * \{ */ + +PyDoc_STRVAR(bpygpu_select_load_id_doc, +"load_id(id)\n" +"\n" +" Set the selection ID.\n" +"\n" +" :param id: Number (32-bit unsigned int).\n" +" :type select: int\n" +); +static PyObject *bpygpu_select_load_id(PyObject *UNUSED(self), PyObject *value) +{ + uint id; + if ((id = PyC_Long_AsU32(value)) == (uint)-1) { + return NULL; + } + GPU_select_load_id(id); + Py_RETURN_NONE; +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Module + * \{ */ + +static struct PyMethodDef bpygpu_select_methods[] = { + /* Manage Stack */ + {"load_id", (PyCFunction)bpygpu_select_load_id, METH_O, bpygpu_select_load_id_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(bpygpu_select_doc, +"This module provides access to selection." +); +static PyModuleDef BPyGPU_select_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu.select", + .m_doc = bpygpu_select_doc, + .m_methods = bpygpu_select_methods, +}; + +PyObject *BPyInit_gpu_select(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&BPyGPU_select_module_def); + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_select.h b/source/blender/python/gpu/gpu_py_select.h new file mode 100644 index 00000000000..11daf2ade64 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_select.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_select.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_SELECT_H__ +#define __GPU_PY_SELECT_H__ + +PyObject *BPyInit_gpu_select(void); + +#endif /* __GPU_PY_SELECT_H__ */ diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c new file mode 100644 index 00000000000..31e1ccf6f8c --- /dev/null +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -0,0 +1,839 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_shader.c + * \ingroup bpygpu + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "BLI_utildefines.h" + +#include "GPU_shader.h" +#include "GPU_shader_interface.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" +#include "../mathutils/mathutils.h" + +#include "gpu_py_api.h" +#include "gpu_py_shader.h" /* own include */ +#include "gpu_py_vertex_format.h" + + + /* -------------------------------------------------------------------- */ + + /** \name Enum Conversion. + * \{ */ + +static int bpygpu_ParseBultinShaderEnum(PyObject *o, void *p) +{ + Py_ssize_t mode_id_len; + const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len); + if (mode_id == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } +#define MATCH_ID(id) \ + if (mode_id_len == (Py_ssize_t)strlen(STRINGIFY(id))) { \ + if (STREQ(mode_id, STRINGIFY(id))) { \ + mode = GPU_SHADER_##id; \ + goto success; \ + } \ + } ((void)0) + + GPUBuiltinShader mode; + MATCH_ID(2D_UNIFORM_COLOR); + MATCH_ID(2D_FLAT_COLOR); + MATCH_ID(2D_SMOOTH_COLOR); + MATCH_ID(2D_IMAGE); + MATCH_ID(3D_UNIFORM_COLOR); + MATCH_ID(3D_FLAT_COLOR); + MATCH_ID(3D_SMOOTH_COLOR); + +#undef MATCH_ID + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + mode_id); + return 0; + +success: + (*(GPUBuiltinShader *)p) = mode; + return 1; +} + +static int bpygpu_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix) +{ + int uniform = GPU_shader_get_uniform_ensure(shader, name); + + if (uniform == -1) { + PyErr_Format(PyExc_ValueError, "%s: uniform %.32s %.32s not found", error_prefix, name); + } + + return uniform; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Shader Type + * \{ */ + +static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + BPYGPU_IS_INIT_OR_ERROR_OBJ; + + struct { + const char *vertexcode; + const char *fragcode; + const char *geocode; + const char *libcode; + const char *defines; + } params = {0}; + + static const char *_keywords[] = { + "vertexcode", "fragcode", "geocode", + "libcode", "defines", NULL}; + + static _PyArg_Parser _parser = {"ss|$sss:GPUShader.__new__", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + ¶ms.vertexcode, ¶ms.fragcode, ¶ms.geocode, + ¶ms.libcode, ¶ms.defines)) + { + return NULL; + } + + GPUShader *shader = GPU_shader_create( + params.vertexcode, + params.fragcode, + params.geocode, + params.libcode, + params.defines, + NULL); + + if (shader == NULL) { + PyErr_SetString(PyExc_Exception, + "Shader Compile Error, see console for more details"); + return NULL; + } + + return BPyGPUShader_CreatePyObject(shader, false); +} + +PyDoc_STRVAR(bpygpu_shader_bind_doc, +".. method:: bind()\n" +"\n" +" Bind the shader object. Required to be able to change uniforms of this shader.\n" +); +static PyObject *bpygpu_shader_bind(BPyGPUShader *self) +{ + GPU_shader_bind(self->shader); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_shader_uniform_from_name_doc, +".. method:: uniform_from_name(name)\n" +"\n" +" Get uniform location by name.\n" +"\n" +" :param name: Name of the uniform variable whose location is to be queried.\n" +" :type name: `str`\n" +" :return: Location of the uniform variable.\n" +" :rtype: `int`\n" +); +static PyObject *bpygpu_shader_uniform_from_name( + BPyGPUShader *self, PyObject *arg) +{ + const char *name = PyUnicode_AsUTF8(arg); + if (name == NULL) { + return NULL; + } + + int uniform = bpygpu_uniform_location_get( + self->shader, name, "GPUShader.get_uniform"); + + if (uniform == -1) { + return NULL; + } + + return PyLong_FromLong(uniform); +} + +PyDoc_STRVAR(bpygpu_shader_uniform_block_from_name_doc, +".. method:: uniform_block_from_name(name)\n" +"\n" +" Get uniform block location by name.\n" +"\n" +" :param name: Name of the uniform block variable whose location is to be queried.\n" +" :type name: `str`\n" +" :return: The location of the uniform block variable.\n" +" :rtype: `int`\n" +); +static PyObject *bpygpu_shader_uniform_block_from_name( + BPyGPUShader *self, PyObject *arg) +{ + const char *name = PyUnicode_AsUTF8(arg); + if (name == NULL) { + return NULL; + } + + int uniform = GPU_shader_get_uniform_block(self->shader, name); + + if (uniform == -1) { + PyErr_Format(PyExc_ValueError, + "GPUShader.get_uniform_block: uniform %.32s not found", name); + return NULL; + } + + return PyLong_FromLong(uniform); +} + +static bool bpygpu_shader_uniform_vector_imp( + PyObject *args, int elem_size, + int *r_location, int *r_length, int *r_count, Py_buffer *r_pybuffer) +{ + PyObject *buffer; + + *r_count = 1; + if (!PyArg_ParseTuple( + args, "iOi|i:GPUShader.uniform_vector_*", + r_location, &buffer, r_length, r_count)) + { + return false; + } + + if (PyObject_GetBuffer(buffer, r_pybuffer, PyBUF_SIMPLE) == -1) { + /* PyObject_GetBuffer raise a PyExc_BufferError */ + return false; + } + + if (r_pybuffer->len != (*r_length * *r_count * elem_size)) { + PyErr_SetString( + PyExc_BufferError, + "GPUShader.uniform_vector_*: buffer size does not match."); + return false; + } + + return true; +} + +PyDoc_STRVAR(bpygpu_shader_uniform_vector_float_doc, +".. method:: uniform_vector_float(location, buffer, length, count)\n" +"\n" +" Set the buffer to fill the uniform.\n" +"\n" +" :param location: Location of the uniform variable to be modified.\n" +" :type location: int\n" +" :param buffer: The data that should be set. Can support the buffer protocol.\n" +" :type buffer: sequence of floats\n" +" :param length: Size of the uniform data type:\n" +"\n" +" - 1: float\n" +" - 2: vec2 or float[2]\n" +" - 3: vec3 or float[3]\n" +" - 4: vec4 or float[4]\n" +" - 9: mat3\n" +" - 16: mat4\n" +"\n" +" :type length: int\n" +" :param count: Specifies the number of elements, vector or matrices that are to be modified.\n" +" :type count: int\n" +); +static PyObject *bpygpu_shader_uniform_vector_float( + BPyGPUShader *self, PyObject *args) +{ + int location, length, count; + + Py_buffer pybuffer; + + if (!bpygpu_shader_uniform_vector_imp( + args, sizeof(float), + &location, &length, &count, &pybuffer)) + { + return NULL; + } + + GPU_shader_uniform_vector( + self->shader, location, length, + count, pybuffer.buf); + + PyBuffer_Release(&pybuffer); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_shader_uniform_vector_int_doc, +".. method:: uniform_vector_int(location, buffer, length, count)\n" +"\n" +" See GPUShader.uniform_vector_float(...) description.\n" +); +static PyObject *bpygpu_shader_uniform_vector_int( + BPyGPUShader *self, PyObject *args) +{ + int location, length, count; + + Py_buffer pybuffer; + + if (!bpygpu_shader_uniform_vector_imp( + args, sizeof(int), + &location, &length, &count, &pybuffer)) + { + return NULL; + } + + GPU_shader_uniform_vector_int( + self->shader, location, length, + count, pybuffer.buf); + + PyBuffer_Release(&pybuffer); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_shader_uniform_bool_doc, +".. method:: uniform_bool(name, seq)\n" +"\n" +" Specify the value of a uniform variable for the current program object.\n" +"\n" +" :param name: Name of the uniform variable whose value is to be changed.\n" +" :type name: str\n" +" :param seq: Value that will be used to update the specified uniform variable.\n" +" :type seq: sequence of bools\n" +); +static PyObject *bpygpu_shader_uniform_bool( + BPyGPUShader *self, PyObject *args) +{ + const char *error_prefix = "GPUShader.uniform_bool"; + + struct { + const char *id; + PyObject *seq; + } params; + + if (!PyArg_ParseTuple( + args, "sO:GPUShader.uniform_bool", + ¶ms.id, ¶ms.seq)) + { + return NULL; + } + + int values[4]; + int length; + int ret; + { + PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix); + if (seq_fast == NULL) { + PyErr_Format(PyExc_TypeError, + "%s: expected a sequence, got %s", + error_prefix, Py_TYPE(params.seq)->tp_name); + ret = -1; + } + else { + length = PySequence_Fast_GET_SIZE(seq_fast); + if (length == 0 || length > 4) { + PyErr_Format(PyExc_TypeError, + "%s: invalid sequence length. expected 1..4, got %d", + error_prefix, length); + ret = -1; + } + else { + ret = PyC_AsArray_FAST( + values, seq_fast, length, &PyLong_Type, + false, error_prefix); + } + Py_DECREF(seq_fast); + } + } + if (ret == -1) { + return NULL; + } + + const int location = bpygpu_uniform_location_get( + self->shader, params.id, error_prefix); + + if (location == -1) { + return NULL; + } + + GPU_shader_uniform_vector_int(self->shader, location, length, 1, values); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_shader_uniform_float_doc, +".. method:: uniform_float(name, value)\n" +"\n" +" Specify the value of a uniform variable for the current program object.\n" +"\n" +" :param name: Name of the uniform variable whose value is to be changed.\n" +" :type name: str\n" +" :param value: Value that will be used to update the specified uniform variable.\n" +" :type value: single number or sequence of numbers\n" +); +static PyObject *bpygpu_shader_uniform_float( + BPyGPUShader *self, PyObject *args) +{ + const char *error_prefix = "GPUShader.uniform_float"; + + struct { + const char *id; + PyObject *seq; + } params; + + if (!PyArg_ParseTuple( + args, "sO:GPUShader.uniform_float", + ¶ms.id, ¶ms.seq)) + { + return NULL; + } + + float values[16]; + int length; + + if (PyFloat_Check(params.seq)) { + values[0] = (float)PyFloat_AsDouble(params.seq); + length = 1; + } + else if (PyLong_Check(params.seq)) { + values[0] = (float)PyLong_AsDouble(params.seq); + length = 1; + } + else if (MatrixObject_Check(params.seq)) { + MatrixObject *mat = (MatrixObject *)params.seq; + if (BaseMath_ReadCallback(mat) == -1) { + return NULL; + } + if ((mat->num_row != mat->num_col) || !ELEM(mat->num_row, 3, 4)) { + PyErr_SetString(PyExc_ValueError, + "Expected 3x3 or 4x4 matrix"); + return NULL; + } + length = mat->num_row * mat->num_col; + memcpy(values, mat->matrix, sizeof(float) * length); + } + else { + length = mathutils_array_parse(values, 2, 16, params.seq, ""); + if (length == -1) { + return NULL; + } + } + + if (!ELEM(length, 1, 2, 3, 4, 9, 16)) { + PyErr_SetString(PyExc_TypeError, + "Expected a single float or a sequence of floats of length 1..4, 9 or 16."); + return NULL; + } + + const int location = bpygpu_uniform_location_get( + self->shader, params.id, error_prefix); + + if (location == -1) { + return NULL; + } + + GPU_shader_uniform_vector(self->shader, location, length, 1, values); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_shader_uniform_int_doc, +".. method:: uniform_int(name, seq)\n" +"\n" +" Specify the value of a uniform variable for the current program object.\n" +"\n" +" :param name: name of the uniform variable whose value is to be changed.\n" +" :type name: str\n" +" :param seq: Value that will be used to update the specified uniform variable.\n" +" :type seq: sequence of numbers\n" +); +static PyObject *bpygpu_shader_uniform_int( + BPyGPUShader *self, PyObject *args) +{ + const char *error_prefix = "GPUShader.uniform_int"; + + struct { + const char *id; + PyObject *seq; + } params; + + if (!PyArg_ParseTuple( + args, "sO:GPUShader.uniform_int", + ¶ms.id, ¶ms.seq)) + { + return NULL; + } + + int values[4]; + int length; + int ret; + + if (PyLong_Check(params.seq)) { + values[0] = PyC_Long_AsI32(params.seq); + length = 1; + ret = 0; + } + else { + PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix); + if (seq_fast == NULL) { + PyErr_Format(PyExc_TypeError, + "%s: expected a sequence, got %s", + error_prefix, Py_TYPE(params.seq)->tp_name); + ret = -1; + } + else { + length = PySequence_Fast_GET_SIZE(seq_fast); + if (length == 0 || length > 4) { + PyErr_Format(PyExc_TypeError, + "%s: invalid sequence length. expected 1..4, got %d", + error_prefix, length); + ret = -1; + } + else { + ret = PyC_AsArray_FAST( + values, seq_fast, length, &PyLong_Type, + false, error_prefix); + } + Py_DECREF(seq_fast); + } + } + if (ret == -1) { + return NULL; + } + + const int location = bpygpu_uniform_location_get( + self->shader, params.id, error_prefix); + + if (location == -1) { + return NULL; + } + + GPU_shader_uniform_vector_int(self->shader, location, length, 1, values); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_shader_attr_from_name_doc, +".. method:: attr_from_name(name)\n" +"\n" +" Get attribute location by name.\n" +"\n" +" :param name: The name of the attribute variable whose location is to be queried.\n" +" :type name: str\n" +" :return: The location of an attribute variable.\n" +" :rtype: int\n" +); +static PyObject *bpygpu_shader_attr_from_name( + BPyGPUShader *self, PyObject *arg) +{ + const char *name = PyUnicode_AsUTF8(arg); + if (name == NULL) { + return NULL; + } + + int attr = GPU_shader_get_attribute(self->shader, name); + + if (attr == -1) { + PyErr_Format(PyExc_ValueError, + "GPUShader.attr_from_name: attribute %.32s not found", name); + return NULL; + } + + return PyLong_FromLong(attr); +} + +PyDoc_STRVAR(bpygpu_shader_calc_format_doc, +".. method:: calc_format()\n" +"\n" +" Build a new format based on the attributes of the shader.\n" +"\n" +" :return: vertex attribute format for the shader\n" +" :rtype: GPUVertFormat\n" +); +static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg)) +{ + BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL); + GPU_vertformat_from_interface(&ret->fmt, GPU_shader_get_interface(self->shader)); + return (PyObject *)ret; +} + +static struct PyMethodDef bpygpu_shader_methods[] = { + {"bind", (PyCFunction)bpygpu_shader_bind, + METH_NOARGS, bpygpu_shader_bind_doc}, + {"uniform_from_name", + (PyCFunction)bpygpu_shader_uniform_from_name, + METH_O, bpygpu_shader_uniform_from_name_doc}, + {"uniform_block_from_name", + (PyCFunction)bpygpu_shader_uniform_block_from_name, + METH_O, bpygpu_shader_uniform_block_from_name_doc}, + {"uniform_vector_float", + (PyCFunction)bpygpu_shader_uniform_vector_float, + METH_VARARGS, bpygpu_shader_uniform_vector_float_doc}, + {"uniform_vector_int", + (PyCFunction)bpygpu_shader_uniform_vector_int, + METH_VARARGS, bpygpu_shader_uniform_vector_int_doc}, + {"uniform_bool", + (PyCFunction)bpygpu_shader_uniform_bool, + METH_VARARGS, bpygpu_shader_uniform_bool_doc}, + {"uniform_float", + (PyCFunction)bpygpu_shader_uniform_float, + METH_VARARGS, bpygpu_shader_uniform_float_doc}, + {"uniform_int", + (PyCFunction)bpygpu_shader_uniform_int, + METH_VARARGS, bpygpu_shader_uniform_int_doc}, + {"attr_from_name", + (PyCFunction)bpygpu_shader_attr_from_name, + METH_O, bpygpu_shader_attr_from_name_doc}, + {"format_calc", + (PyCFunction)bpygpu_shader_calc_format, + METH_NOARGS, bpygpu_shader_calc_format_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(bpygpu_shader_program_doc, +"The name of the program object for use by the OpenGL API (read-only).\n\n:type: int" +); +static PyObject *bpygpu_shader_program_get(BPyGPUShader *self, void *UNUSED(closure)) +{ + return PyLong_FromLong(GPU_shader_get_program(self->shader)); +} + +static PyGetSetDef bpygpu_shader_getseters[] = { + {(char *)"program", + (getter)bpygpu_shader_program_get, (setter)NULL, + bpygpu_shader_program_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + + +static void bpygpu_shader_dealloc(BPyGPUShader *self) +{ + if (self->is_builtin == false) { + GPU_shader_free(self->shader); + } + Py_TYPE(self)->tp_free((PyObject *)self); +} + + +PyDoc_STRVAR(bpygpu_shader_doc, +".. class:: GPUShader(vertexcode, fragcode, geocode=None, libcode=None, defines=None)\n" +"\n" +" GPUShader combines multiple GLSL shaders into a program used for drawing.\n" +" It must contain a vertex and fragment shaders, with an optional geometry shader.\n" +"\n" +" The GLSL #version directive is automatically included at the top of shaders, and set to 330.\n" +" Some preprocessor directives are automatically added according to the Operating System or availability:\n" +" ``GPU_ATI``, ``GPU_NVIDIA`` and ``GPU_INTEL``.\n" +"\n" +" The following extensions are enabled by default if supported by the GPU:\n" +" ``GL_ARB_texture_gather`` and ``GL_ARB_texture_query_lod``.\n" +"\n" +" To debug shaders, use the --debug-gpu-shaders command line option" +" to see full GLSL shader compilation and linking errors.\n" +"\n" +" :param vertexcode: Vertex shader code.\n" +" :type vertexcode: str\n" +" :param fragcode: Fragment shader code.\n" +" :type value: str\n" +" :param geocode: Geometry shader code.\n" +" :type value: str\n" +" :param libcode: Code with functions and presets to be shared between shaders.\n" +" :type value: str\n" +" :param defines: Preprocessor directives.\n" +" :type value: str\n" +); +PyTypeObject BPyGPUShader_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUShader", + .tp_basicsize = sizeof(BPyGPUShader), + .tp_dealloc = (destructor)bpygpu_shader_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = bpygpu_shader_doc, + .tp_methods = bpygpu_shader_methods, + .tp_getset = bpygpu_shader_getseters, + .tp_new = bpygpu_shader_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name gpu.shader Module API + * \{ */ + +PyDoc_STRVAR(bpygpu_shader_unbind_doc, +".. function:: unbind()\n" +"\n" +" Unbind the bound shader object.\n" +); +static PyObject *bpygpu_shader_unbind(BPyGPUShader *UNUSED(self)) +{ + GPU_shader_unbind(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_shader_from_builtin_doc, +".. function:: from_builtin(shader_name)\n" +"\n" +" Shaders that are embedded in the blender internal code.\n" +" They all read the uniform 'mat4 ModelViewProjectionMatrix', which can be edited by the 'gpu.matrix' module.\n" +" For more details, you can check the shader code with the function 'gpu.shader.code_from_builtin';\n" +"\n" +" :param shader_name: One of these builtin shader names: {\n" +" '2D_UNIFORM_COLOR',\n" +" '2D_FLAT_COLOR',\n" +" '2D_SMOOTH_COLOR',\n" +" '2D_IMAGE',\n" +" '3D_UNIFORM_COLOR',\n" +" '3D_FLAT_COLOR',\n" +" '3D_SMOOTH_COLOR'}\n" +" :type shader_name: str\n" +" :return: Shader object corresponding to the given name.\n" +" :rtype: :class:`bpy.types.GPUShader`\n" +); +static PyObject *bpygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg) +{ + BPYGPU_IS_INIT_OR_ERROR_OBJ; + + GPUBuiltinShader shader_id; + + if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) { + return NULL; + } + + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + + return BPyGPUShader_CreatePyObject(shader, true); +} + +PyDoc_STRVAR(bpygpu_shader_code_from_builtin_doc, +".. function:: code_from_builtin(shader_name)\n" +"\n" +" Exposes the internal shader code for query.\n" +"\n" +" :param shader_name: One of these builtin shader names: {\n" +" '2D_UNIFORM_COLOR',\n" +" '2D_FLAT_COLOR',\n" +" '2D_SMOOTH_COLOR',\n" +" '2D_IMAGE',\n" +" '3D_UNIFORM_COLOR',\n" +" '3D_FLAT_COLOR',\n" +" '3D_SMOOTH_COLOR'}\n" +" :type shader_name: str\n" +" :return: Vertex, fragment and geometry shader codes.\n" +" :rtype: dict\n" +); +static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg) +{ + GPUBuiltinShader shader_id; + + const char *vert; + const char *frag; + const char *geom; + const char *defines; + + PyObject *item, *r_dict; + + if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) { + return NULL; + } + + GPU_shader_get_builtin_shader_code( + shader_id, &vert, &frag, &geom, &defines); + + r_dict = PyDict_New(); + + PyDict_SetItemString(r_dict, "vertex_shader", item = PyUnicode_FromString(vert)); + Py_DECREF(item); + + PyDict_SetItemString(r_dict, "fragment_shader", item = PyUnicode_FromString(frag)); + Py_DECREF(item); + + if (geom) { + PyDict_SetItemString(r_dict, "geometry_shader", item = PyUnicode_FromString(geom)); + Py_DECREF(item); + } + if (defines) { + PyDict_SetItemString(r_dict, "defines", item = PyUnicode_FromString(defines)); + Py_DECREF(item); + } + return r_dict; +} + +static struct PyMethodDef bpygpu_shader_module_methods[] = { + {"unbind", + (PyCFunction)bpygpu_shader_unbind, + METH_NOARGS, bpygpu_shader_unbind_doc}, + {"from_builtin", + (PyCFunction)bpygpu_shader_from_builtin, + METH_O, bpygpu_shader_from_builtin_doc}, + {"code_from_builtin", + (PyCFunction)bpygpu_shader_code_from_builtin, + METH_O, bpygpu_shader_code_from_builtin_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(bpygpu_shader_module_doc, +"This module provides access to GPUShader internal functions." +); +static PyModuleDef BPyGPU_shader_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu.shader", + .m_doc = bpygpu_shader_module_doc, + .m_methods = bpygpu_shader_module_methods, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUShader_CreatePyObject(GPUShader *shader, bool is_builtin) +{ + BPyGPUShader *self; + + self = PyObject_New(BPyGPUShader, &BPyGPUShader_Type); + self->shader = shader; + self->is_builtin = is_builtin; + + return (PyObject *)self; +} + +PyObject *BPyInit_gpu_shader(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&BPyGPU_shader_module_def); + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_shader.h b/source/blender/python/gpu/gpu_py_shader.h new file mode 100644 index 00000000000..c038cf63e40 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_shader.h @@ -0,0 +1,41 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_shader.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_SHADER_H__ +#define __GPU_PY_SHADER_H__ + +extern PyTypeObject BPyGPUShader_Type; + +#define BPyGPUShader_Check(v) (Py_TYPE(v) == &BPyGPUShader_Type) + +typedef struct BPyGPUShader { + PyObject_VAR_HEAD + struct GPUShader *shader; + bool is_builtin; +} BPyGPUShader; + +PyObject *BPyGPUShader_CreatePyObject(struct GPUShader *shader, bool is_builtin); +PyObject *BPyInit_gpu_shader(void); + +#endif /* __GPU_PY_SHADER_H__ */ diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c new file mode 100644 index 00000000000..d9ef0736f8e --- /dev/null +++ b/source/blender/python/gpu/gpu_py_types.c @@ -0,0 +1,80 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_types.c + * \ingroup bpygpu + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "gpu_py_types.h" /* own include */ + +/* -------------------------------------------------------------------- */ + + +/** \name GPU Types Module + * \{ */ + +static struct PyModuleDef BPyGPU_types_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu.types", +}; + +PyObject *BPyInit_gpu_types(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&BPyGPU_types_module_def); + + if (PyType_Ready(&BPyGPUVertFormat_Type) < 0) + return NULL; + if (PyType_Ready(&BPyGPUVertBuf_Type) < 0) + return NULL; + if (PyType_Ready(&BPyGPUIndexBuf_Type) < 0) + return NULL; + if (PyType_Ready(&BPyGPUBatch_Type) < 0) + return NULL; + if (PyType_Ready(&BPyGPUOffScreen_Type) < 0) + return NULL; + if (PyType_Ready(&BPyGPUShader_Type) < 0) + return NULL; + +#define MODULE_TYPE_ADD(s, t) \ + PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t) + + MODULE_TYPE_ADD(submodule, BPyGPUVertFormat_Type); + MODULE_TYPE_ADD(submodule, BPyGPUVertBuf_Type); + MODULE_TYPE_ADD(submodule, BPyGPUIndexBuf_Type); + MODULE_TYPE_ADD(submodule, BPyGPUBatch_Type); + MODULE_TYPE_ADD(submodule, BPyGPUOffScreen_Type); + MODULE_TYPE_ADD(submodule, BPyGPUShader_Type); + +#undef MODULE_TYPE_ADD + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_types.h b/source/blender/python/gpu/gpu_py_types.h new file mode 100644 index 00000000000..dc91c579aaf --- /dev/null +++ b/source/blender/python/gpu/gpu_py_types.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_types.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_TYPES_H__ +#define __GPU_PY_TYPES_H__ + +#include "gpu_py_vertex_format.h" +#include "gpu_py_vertex_buffer.h" +#include "gpu_py_element.h" +#include "gpu_py_batch.h" +#include "gpu_py_offscreen.h" +#include "gpu_py_shader.h" + +PyObject *BPyInit_gpu_types(void); + +#endif /* __GPU_PY_TYPES_H__ */ diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c new file mode 100644 index 00000000000..c13e3f2195e --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c @@ -0,0 +1,352 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_vertex_buffer.c + * \ingroup bpygpu + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "GPU_vertex_buffer.h" + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "gpu_py_vertex_format.h" +#include "gpu_py_vertex_buffer.h" /* own include */ + +/* -------------------------------------------------------------------- */ + +/** \name Utility Functions + * \{ */ + +#define PY_AS_NATIVE_SWITCH(attr) \ + switch (attr->comp_type) { \ + case GPU_COMP_I8: { PY_AS_NATIVE(int8_t, PyC_Long_AsI8); break; } \ + case GPU_COMP_U8: { PY_AS_NATIVE(uint8_t, PyC_Long_AsU8); break; } \ + case GPU_COMP_I16: { PY_AS_NATIVE(int16_t, PyC_Long_AsI16); break; } \ + case GPU_COMP_U16: { PY_AS_NATIVE(uint16_t, PyC_Long_AsU16); break; } \ + case GPU_COMP_I32: { PY_AS_NATIVE(int32_t, PyC_Long_AsI32); break; } \ + case GPU_COMP_U32: { PY_AS_NATIVE(uint32_t, PyC_Long_AsU32); break; } \ + case GPU_COMP_F32: { PY_AS_NATIVE(float, PyFloat_AsDouble); break; } \ + default: \ + BLI_assert(0); \ + } ((void)0) + +/* No error checking, callers must run PyErr_Occurred */ +static void fill_format_elem(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr) +{ +#define PY_AS_NATIVE(ty_dst, py_as_native) \ +{ \ + ty_dst *data_dst = data_dst_void; \ + *data_dst = py_as_native(py_src); \ +} ((void)0) + + PY_AS_NATIVE_SWITCH(attr); + +#undef PY_AS_NATIVE +} + +/* No error checking, callers must run PyErr_Occurred */ +static void fill_format_sequence(void *data_dst_void, PyObject *py_seq_fast, const GPUVertAttr *attr) +{ + const uint len = attr->comp_len; + PyObject **value_fast_items = PySequence_Fast_ITEMS(py_seq_fast); + +/** + * Args are constants, so range checks will be optimized out if they're nop's. + */ +#define PY_AS_NATIVE(ty_dst, py_as_native) \ + ty_dst *data_dst = data_dst_void; \ + for (uint i = 0; i < len; i++) { \ + data_dst[i] = py_as_native(value_fast_items[i]); \ + } ((void)0) + + PY_AS_NATIVE_SWITCH(attr); + +#undef PY_AS_NATIVE +} + +#undef PY_AS_NATIVE_SWITCH +#undef WARN_TYPE_LIMIT_PUSH +#undef WARN_TYPE_LIMIT_POP + +static bool bpygpu_vertbuf_fill_impl( + GPUVertBuf *vbo, + uint data_id, PyObject *seq, const char *error_prefix) +{ + const char *exc_str_size_mismatch = "Expected a %s of size %d, got %u"; + + bool ok = true; + const GPUVertAttr *attr = &vbo->format.attribs[data_id]; + + if (PyObject_CheckBuffer(seq)) { + Py_buffer pybuffer; + + if (PyObject_GetBuffer(seq, &pybuffer, PyBUF_STRIDES | PyBUF_ND) == -1) { + /* PyObject_GetBuffer raise a PyExc_BufferError */ + return false; + } + + uint comp_len = pybuffer.ndim == 1 ? 1 : (uint)pybuffer.shape[1]; + + if (pybuffer.shape[0] != vbo->vertex_len) { + PyErr_Format(PyExc_ValueError, exc_str_size_mismatch, + "sequence", vbo->vertex_len, pybuffer.shape[0]); + ok = false; + } + else if (comp_len != attr->comp_len) { + PyErr_Format(PyExc_ValueError, exc_str_size_mismatch, + "component", attr->comp_len, comp_len); + ok = false; + } + else { + GPU_vertbuf_attr_fill_stride(vbo, data_id, pybuffer.strides[0], pybuffer.buf); + } + + PyBuffer_Release(&pybuffer); + } + else { + GPUVertBufRaw data_step; + GPU_vertbuf_attr_get_raw_data(vbo, data_id, &data_step); + + PyObject *seq_fast = PySequence_Fast(seq, "Vertex buffer fill"); + if (seq_fast == NULL) { + return false; + } + + const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast); + + if (seq_len != vbo->vertex_len) { + PyErr_Format(PyExc_ValueError, exc_str_size_mismatch, + "sequence", vbo->vertex_len, seq_len); + } + + PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast); + + if (attr->comp_len == 1) { + for (uint i = 0; i < seq_len; i++) { + uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step); + PyObject *item = seq_items[i]; + fill_format_elem(data, item, attr); + } + } + else { + for (uint i = 0; i < seq_len; i++) { + uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step); + PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix); + + if (seq_fast_item == NULL) { + ok = false; + goto finally; + } + if (PySequence_Fast_GET_SIZE(seq_fast_item) != attr->comp_len) { + PyErr_Format(PyExc_ValueError, exc_str_size_mismatch, + "sequence", attr->comp_len, PySequence_Fast_GET_SIZE(seq_fast_item)); + ok = false; + Py_DECREF(seq_fast_item); + goto finally; + } + + /* May trigger error, check below */ + fill_format_sequence(data, seq_fast_item, attr); + Py_DECREF(seq_fast_item); + } + } + + if (PyErr_Occurred()) { + ok = false; + } + +finally: + + Py_DECREF(seq_fast); + } + return ok; +} + +static int bpygpu_attr_fill(GPUVertBuf *buf, int id, PyObject *py_seq_data, const char *error_prefix) +{ + if (id < 0 || id >= buf->format.attr_len) { + PyErr_Format(PyExc_ValueError, + "Format id %d out of range", + id); + return 0; + } + + if (buf->data == NULL) { + PyErr_SetString(PyExc_ValueError, + "Can't fill, static buffer already in use"); + return 0; + } + + if (!bpygpu_vertbuf_fill_impl(buf, (uint)id, py_seq_data, error_prefix)) { + return 0; + } + + return 1; +} + + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertBuf Type + * \{ */ + +static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + struct { + PyObject *py_fmt; + uint len; + } params; + + static const char *_keywords[] = {"format", "len", NULL}; + static _PyArg_Parser _parser = {"O!I:GPUVertBuf.__new__", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + &BPyGPUVertFormat_Type, ¶ms.py_fmt, + ¶ms.len)) + { + return NULL; + } + + const GPUVertFormat *fmt = &((BPyGPUVertFormat *)params.py_fmt)->fmt; + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(fmt); + + GPU_vertbuf_data_alloc(vbo, params.len); + + return BPyGPUVertBuf_CreatePyObject(vbo); +} + +PyDoc_STRVAR(bpygpu_VertBuf_attr_fill_doc, +".. method:: attr_fill(id, data)\n" +"\n" +" Insert data into the buffer for a single attribute.\n" +"\n" +" :param id: Either the name or the id of the attribute.\n" +" :type id: int or str\n" +" :param data: Sequence of data that should be stored in the buffer\n" +" :type data: sequence of values or tuples\n" +); +static PyObject *bpygpu_VertBuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds) +{ + PyObject *data; + PyObject *identifier; + + static const char *_keywords[] = {"id", "data", NULL}; + static _PyArg_Parser _parser = {"OO:attr_fill", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + &identifier, &data)) + { + return NULL; + } + + int id; + + if (PyLong_Check(identifier)) { + id = PyLong_AsLong(identifier); + } + else if (PyUnicode_Check(identifier)) { + const char *name = PyUnicode_AsUTF8(identifier); + id = GPU_vertformat_attr_id_get(&self->buf->format, name); + if (id == -1) { + PyErr_SetString(PyExc_ValueError, + "Unknown attribute name"); + return NULL; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "expected int or str type as identifier"); + return NULL; + } + + + if (!bpygpu_attr_fill(self->buf, id, data, "GPUVertBuf.attr_fill")) { + return NULL; + } + + Py_RETURN_NONE; +} + + +static struct PyMethodDef bpygpu_VertBuf_methods[] = { + {"attr_fill", (PyCFunction) bpygpu_VertBuf_attr_fill, + METH_VARARGS | METH_KEYWORDS, bpygpu_VertBuf_attr_fill_doc}, + {NULL, NULL, 0, NULL} +}; + +static void bpygpu_VertBuf_dealloc(BPyGPUVertBuf *self) +{ + GPU_vertbuf_discard(self->buf); + Py_TYPE(self)->tp_free(self); +} + +PyDoc_STRVAR(py_gpu_vertex_buffer_doc, +".. class:: GPUVertBuf(len, format)\n" +"\n" +" Contains a VBO.\n" +"\n" +" :param len: Amount of vertices that will fit into this buffer.\n" +" :type type: `int`\n" +" :param format: Vertex format.\n" +" :type buf: :class:`gpu.types.GPUVertFormat`\n" +); +PyTypeObject BPyGPUVertBuf_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUVertBuf", + .tp_basicsize = sizeof(BPyGPUVertBuf), + .tp_dealloc = (destructor)bpygpu_VertBuf_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = py_gpu_vertex_buffer_doc, + .tp_methods = bpygpu_VertBuf_methods, + .tp_new = bpygpu_VertBuf_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUVertBuf_CreatePyObject(GPUVertBuf *buf) +{ + BPyGPUVertBuf *self; + + self = PyObject_New(BPyGPUVertBuf, &BPyGPUVertBuf_Type); + self->buf = buf; + + return (PyObject *)self; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.h b/source/blender/python/gpu/gpu_py_vertex_buffer.h new file mode 100644 index 00000000000..6751956298c --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.h @@ -0,0 +1,42 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_vertex_buffer.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_VERTEX_BUFFER_H__ +#define __GPU_PY_VERTEX_BUFFER_H__ + +#include "BLI_compiler_attrs.h" + +extern PyTypeObject BPyGPUVertBuf_Type; + +#define BPyGPUVertBuf_Check(v) (Py_TYPE(v) == &BPyGPUVertBuf_Type) + +typedef struct BPyGPUVertBuf { + PyObject_VAR_HEAD + /* The buf is owned, we may support thin wrapped batches later. */ + struct GPUVertBuf *buf; +} BPyGPUVertBuf; + +PyObject *BPyGPUVertBuf_CreatePyObject(struct GPUVertBuf *vbo) ATTR_NONNULL(1); + +#endif /* __GPU_PY_VERTEX_BUFFER_H__ */ diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c new file mode 100644 index 00000000000..27f3791ec15 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_format.c @@ -0,0 +1,263 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_vertex_format.c + * \ingroup bpygpu + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "gpu_py_vertex_format.h" /* own include */ + +#ifdef __BIG_ENDIAN__ + /* big endian */ +# define MAKE_ID2(c, d) ((c) << 8 | (d)) +# define MAKE_ID3(a, b, c) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 ) +# define MAKE_ID4(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) ) +#else + /* little endian */ +# define MAKE_ID2(c, d) ((d) << 8 | (c)) +# define MAKE_ID3(a, b, c) ( (int)(c) << 16 | (b) << 8 | (a) ) +# define MAKE_ID4(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) ) +#endif + +/* -------------------------------------------------------------------- */ + +/** \name Enum Conversion + * + * Use with PyArg_ParseTuple's "O&" formatting. + * \{ */ + +static int bpygpu_parse_component_type(const char *str, int length) +{ + if (length == 2) { + switch (*((ushort *)str)) { + case MAKE_ID2('I', '8'): return GPU_COMP_I8; + case MAKE_ID2('U', '8'): return GPU_COMP_U8; + default: break; + } + } + else if (length == 3) { + switch (*((uint *)str)) { + case MAKE_ID3('I', '1', '6'): return GPU_COMP_I16; + case MAKE_ID3('U', '1', '6'): return GPU_COMP_U16; + case MAKE_ID3('I', '3', '2'): return GPU_COMP_I32; + case MAKE_ID3('U', '3', '2'): return GPU_COMP_U32; + case MAKE_ID3('F', '3', '2'): return GPU_COMP_F32; + case MAKE_ID3('I', '1', '0'): return GPU_COMP_I10; + default: break; + } + } + return -1; +} + +static int bpygpu_parse_fetch_mode(const char *str, int length) +{ +#define MATCH_ID(id) \ + if (length == strlen(STRINGIFY(id))) { \ + if (STREQ(str, STRINGIFY(id))) { \ + return GPU_FETCH_##id; \ + } \ + } ((void)0) + + MATCH_ID(FLOAT); + MATCH_ID(INT); + MATCH_ID(INT_TO_FLOAT_UNIT); + MATCH_ID(INT_TO_FLOAT); +#undef MATCH_ID + + return -1; +} + +static int bpygpu_ParseVertCompType(PyObject *o, void *p) +{ + Py_ssize_t length; + const char *str = _PyUnicode_AsStringAndSize(o, &length); + + if (str == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } + + int comp_type = bpygpu_parse_component_type(str, length); + if (comp_type == -1) { + PyErr_Format(PyExc_ValueError, + "unkown component type: '%s", + str); + return 0; + } + + *((GPUVertCompType *)p) = comp_type; + return 1; +} + +static int bpygpu_ParseVertFetchMode(PyObject *o, void *p) +{ + Py_ssize_t length; + const char *str = _PyUnicode_AsStringAndSize(o, &length); + + if (str == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } + + int fetch_mode = bpygpu_parse_fetch_mode(str, length); + if (fetch_mode == -1) { + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + str); + return 0; + } + + (*(GPUVertFetchMode *)p) = fetch_mode; + return 1; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertFormat Type + * \{ */ + +static PyObject *bpygpu_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) { + PyErr_SetString(PyExc_ValueError, "This function takes no arguments"); + return NULL; + } + return BPyGPUVertFormat_CreatePyObject(NULL); +} + +PyDoc_STRVAR(bpygpu_VertFormat_attr_add_doc, +".. method:: attr_add(id, comp_type, len, fetch_mode)\n" +"\n" +" Add a new attribute to the format.\n" +"\n" +" :param id: Name the attribute. Often `position`, `normal`, ...\n" +" :type id: str\n" +" :param comp_type: The data type that will be used store the value in memory.\n" +" Possible values are `I8`, `U8`, `I16`, `U16`, `I32`, `U32`, `F32` and `I10`.\n" +" :type comp_type: `str`\n" +" :param len: How many individual values the attribute consists of (e.g. 2 for uv coordinates).\n" +" :type len: int\n" +" :param fetch_mode: How values from memory will be converted when used in the shader.\n" +" This is mainly useful for memory optimizations when you want to store values with reduced precision.\n" +" E.g. you can store a float in only 1 byte but it will be converted to a normal 4 byte float when used.\n" +" Possible values are `FLOAT`, `INT`, `INT_TO_FLOAT_UNIT` and `INT_TO_FLOAT`.\n" +" :type fetch_mode: `str`\n" +); +static PyObject *bpygpu_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds) +{ + struct { + const char *id; + GPUVertCompType comp_type; + uint len; + GPUVertFetchMode fetch_mode; + } params; + + if (self->fmt.attr_len == GPU_VERT_ATTR_MAX_LEN) { + PyErr_SetString(PyExc_ValueError, "Maxumum attr reached " STRINGIFY(GPU_VERT_ATTR_MAX_LEN)); + return NULL; + } + + static const char *_keywords[] = {"id", "comp_type", "len", "fetch_mode", NULL}; + static _PyArg_Parser _parser = {"$sO&IO&:attr_add", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + ¶ms.id, + bpygpu_ParseVertCompType, ¶ms.comp_type, + ¶ms.len, + bpygpu_ParseVertFetchMode, ¶ms.fetch_mode)) + { + return NULL; + } + + uint attr_id = GPU_vertformat_attr_add(&self->fmt, params.id, params.comp_type, params.len, params.fetch_mode); + return PyLong_FromLong(attr_id); +} + +static struct PyMethodDef bpygpu_VertFormat_methods[] = { + {"attr_add", (PyCFunction)bpygpu_VertFormat_attr_add, + METH_VARARGS | METH_KEYWORDS, bpygpu_VertFormat_attr_add_doc}, + {NULL, NULL, 0, NULL} +}; + + +static void bpygpu_VertFormat_dealloc(BPyGPUVertFormat *self) +{ + Py_TYPE(self)->tp_free(self); +} + +PyDoc_STRVAR(bpygpu_VertFormat_doc, +".. class:: GPUVertFormat()\n" +"\n" +" This object contains information about the structure of a vertex buffer.\n" +); +PyTypeObject BPyGPUVertFormat_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUVertFormat", + .tp_basicsize = sizeof(BPyGPUVertFormat), + .tp_dealloc = (destructor)bpygpu_VertFormat_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = bpygpu_VertFormat_doc, + .tp_methods = bpygpu_VertFormat_methods, + .tp_new = bpygpu_VertFormat_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUVertFormat_CreatePyObject(GPUVertFormat *fmt) +{ + BPyGPUVertFormat *self; + + self = PyObject_New(BPyGPUVertFormat, &BPyGPUVertFormat_Type); + if (fmt) { + self->fmt = *fmt; + } + else { + memset(&self->fmt, 0, sizeof(self->fmt)); + } + + return (PyObject *)self; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_vertex_format.h b/source/blender/python/gpu/gpu_py_vertex_format.h new file mode 100644 index 00000000000..5b0bf1addc2 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_format.h @@ -0,0 +1,41 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_vertex_format.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_VERTEX_FORMAT_H__ +#define __GPU_PY_VERTEX_FORMAT_H__ + +#include "GPU_vertex_format.h" + +extern PyTypeObject BPyGPUVertFormat_Type; + +#define BPyGPUVertFormat_Check(v) (Py_TYPE(v) == &BPyGPUVertFormat_Type) + +typedef struct BPyGPUVertFormat { + PyObject_VAR_HEAD + struct GPUVertFormat fmt; +} BPyGPUVertFormat; + +PyObject *BPyGPUVertFormat_CreatePyObject(struct GPUVertFormat *fmt); + +#endif /* __GPU_PY_VERTEX_FORMAT_H__ */ diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 357cb175769..bd7306cddf2 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -52,11 +52,13 @@ set(SRC bpy_app_build_options.c bpy_app_ffmpeg.c bpy_app_handlers.c + bpy_app_icons.c bpy_app_ocio.c bpy_app_oiio.c bpy_app_opensubdiv.c bpy_app_openvdb.c bpy_app_sdl.c + bpy_app_timers.c bpy_app_translations.c bpy_capi_utils.c bpy_driver.c @@ -65,6 +67,8 @@ set(SRC bpy_intern_string.c bpy_library_load.c bpy_library_write.c + bpy_gizmo_wrap.c + bpy_msgbus.c bpy_operator.c bpy_operator_wrap.c bpy_path.c @@ -75,11 +79,10 @@ set(SRC bpy_rna_callback.c bpy_rna_driver.c bpy_rna_id_collection.c + bpy_rna_gizmo.c bpy_traceback.c bpy_utils_previews.c bpy_utils_units.c - gpu.c - gpu_offscreen.c stubs.c bpy.h @@ -88,16 +91,20 @@ set(SRC bpy_app_build_options.h bpy_app_ffmpeg.h bpy_app_handlers.h + bpy_app_icons.h bpy_app_ocio.h bpy_app_oiio.h bpy_app_opensubdiv.h bpy_app_openvdb.h bpy_app_sdl.h + bpy_app_timers.h bpy_app_translations.h bpy_capi_utils.h bpy_driver.h bpy_intern_string.h bpy_library.h + bpy_gizmo_wrap.h + bpy_msgbus.h bpy_operator.h bpy_operator_wrap.h bpy_path.h @@ -107,10 +114,10 @@ set(SRC bpy_rna_callback.h bpy_rna_driver.h bpy_rna_id_collection.h + bpy_rna_gizmo.h bpy_traceback.h bpy_utils_previews.h bpy_utils_units.h - gpu.h ../BPY_extern.h ../BPY_extern_clog.h ) @@ -176,10 +183,6 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() -if(WITH_GAMEENGINE) - add_definitions(-DWITH_GAMEENGINE) -endif() - if(WITH_IMAGE_CINEON) add_definitions(-DWITH_CINEON) endif() @@ -188,10 +191,6 @@ if(WITH_IMAGE_DDS) add_definitions(-DWITH_DDS) endif() -if(WITH_IMAGE_FRAMESERVER) - add_definitions(-DWITH_FRAMESERVER) -endif() - if(WITH_IMAGE_HDR) add_definitions(-DWITH_HDR) endif() @@ -302,10 +301,6 @@ if(WITH_OPENSUBDIV) ) endif() -if(WITH_PLAYER) - add_definitions(-DWITH_PLAYER) -endif() - add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_python "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 82f710e4acf..07ad8274f11 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -46,6 +46,7 @@ #include "bpy_rna.h" #include "bpy_app.h" #include "bpy_rna_id_collection.h" +#include "bpy_rna_gizmo.h" #include "bpy_props.h" #include "bpy_library.h" #include "bpy_operator.h" @@ -57,6 +58,7 @@ /* external util modules */ #include "../generic/idprop_py_api.h" +#include "bpy_msgbus.h" #ifdef WITH_FREESTYLE # include "BPy_Freestyle.h" @@ -338,6 +340,8 @@ void BPy_init_modules(void) BPY_rna_id_collection_module(mod); + BPY_rna_gizmo_module(mod); + bpy_import_test("bpy_types"); PyModule_AddObject(mod, "data", BPY_rna_module()); /* imports bpy_types by running this */ bpy_import_test("bpy_types"); @@ -347,6 +351,7 @@ void BPy_init_modules(void) PyModule_AddObject(mod, "app", BPY_app_struct()); PyModule_AddObject(mod, "_utils_units", BPY_utils_units()); PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module()); + PyModule_AddObject(mod, "msgbus", BPY_msgbus_module()); /* bpy context */ RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr); @@ -371,6 +376,9 @@ void BPy_init_modules(void) PyModule_AddObject(mod, meth_bpy_register_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_register_class, NULL)); PyModule_AddObject(mod, meth_bpy_unregister_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unregister_class, NULL)); + PyModule_AddObject(mod, meth_bpy_owner_id_get.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_get, NULL)); + PyModule_AddObject(mod, meth_bpy_owner_id_set.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_set, NULL)); + /* add our own modules dir, this is a python package */ bpy_package_py = bpy_import_test("bpy"); } diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 928e14c09bf..fe8eb768b3a 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -47,11 +47,16 @@ #include "bpy_app_handlers.h" #include "bpy_driver.h" +/* modules */ +#include "bpy_app_icons.h" +#include "bpy_app_timers.h" + #include "BLI_utildefines.h" #include "BKE_appdir.h" #include "BKE_blender_version.h" #include "BKE_global.h" +#include "BKE_library_override.h" #include "DNA_ID.h" @@ -117,6 +122,10 @@ static PyStructSequence_Field app_info_fields[] = { {(char *)"build_options", (char *)"A set containing most important enabled optional build features"}, {(char *)"handlers", (char *)"Application handler callbacks"}, {(char *)"translations", (char *)"Application and addons internationalization API"}, + + /* Modules (not struct sequence). */ + {(char *)"icons", (char *)"Manage custom icons"}, + {(char *)"timers", (char *)"Manage timers"}, {NULL}, }; @@ -129,6 +138,8 @@ PyDoc_STRVAR(bpy_app_doc, " :maxdepth: 1\n" "\n" " bpy.app.handlers.rst\n" +" bpy.app.icons.rst\n" +" bpy.app.timers.rst\n" " bpy.app.translations.rst\n" ); @@ -210,6 +221,10 @@ static PyObject *make_app_info(void) SetObjItem(BPY_app_handlers_struct()); SetObjItem(BPY_app_translations_struct()); + /* modules */ + SetObjItem(BPY_app_icons_module()); + SetObjItem(BPY_app_timers_module()); + #undef SetIntItem #undef SetStrItem #undef SetBytesItem @@ -282,7 +297,7 @@ static PyObject *bpy_app_binary_path_python_get(PyObject *self, void *UNUSED(clo } PyDoc_STRVAR(bpy_app_debug_value_doc, -"Int, number which can be set to non-zero values for testing purposes" +"Short, number which can be set to non-zero values for testing purposes" ); static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(closure)) { @@ -291,10 +306,12 @@ static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(cl static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure)) { - int param = PyC_Long_AsI32(value); + short param = PyC_Long_AsI16(value); if (param == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "bpy.app.debug_value can only be set to a whole number"); + PyC_Err_SetString_Prefix( + PyExc_TypeError, + "bpy.app.debug_value can only be set to a whole number"); return -1; } @@ -348,6 +365,29 @@ static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void } +PyDoc_STRVAR(bpy_app_use_static_override_doc, +"Boolean, whether static override is exposed in UI or not." +); +static PyObject *bpy_app_use_static_override_get(PyObject *UNUSED(self), void *UNUSED(closure)) +{ + return PyBool_FromLong((long)BKE_override_static_is_enabled()); +} + +static int bpy_app_use_static_override_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure)) +{ + const int param = PyC_Long_AsBool(value); + + if (param == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "bpy.app.use_static_override must be a boolean"); + return -1; + } + + BKE_override_static_enable((const bool)param); + + return 0; +} + + static PyGetSetDef bpy_app_getsets[] = { {(char *)"debug", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG}, {(char *)"debug_ffmpeg", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_FFMPEG}, @@ -366,6 +406,8 @@ static PyGetSetDef bpy_app_getsets[] = { {(char *)"debug_gpumem", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_GPU_MEM}, {(char *)"debug_io", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_IO}, + {(char *)"use_static_override", bpy_app_use_static_override_get, bpy_app_use_static_override_set, (char *)bpy_app_use_static_override_doc, NULL}, + {(char *)"binary_path_python", bpy_app_binary_path_python_get, NULL, (char *)bpy_app_binary_path_python_doc, NULL}, {(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)bpy_app_debug_value_doc, NULL}, diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index d5c325e4317..70c52b8860c 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -42,10 +42,8 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"cycles", NULL}, {(char *)"cycles_osl", NULL}, {(char *)"freestyle", NULL}, - {(char *)"gameengine", NULL}, {(char *)"image_cineon", NULL}, {(char *)"image_dds", NULL}, - {(char *)"image_frameserver", NULL}, {(char *)"image_hdr", NULL}, {(char *)"image_openexr", NULL}, {(char *)"image_openjpeg", NULL}, @@ -64,7 +62,6 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"mod_smoke", NULL}, {(char *)"collada", NULL}, {(char *)"opencolorio", NULL}, - {(char *)"player", NULL}, {(char *)"openmp", NULL}, {(char *)"openvdb", NULL}, {(char *)"alembic", NULL}, @@ -140,12 +137,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_GAMEENGINE - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef WITH_CINEON SetObjIncref(Py_True); #else @@ -158,12 +149,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_FRAMESERVER - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef WITH_HDR SetObjIncref(Py_True); #else @@ -272,12 +257,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_PLAYER - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef _OPENMP SetObjIncref(Py_True); #else diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 8453808d6ec..d89b3bd01f5 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -46,35 +46,30 @@ void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg); static PyTypeObject BlenderAppCbType; static PyStructSequence_Field app_cb_info_fields[] = { - {(char *)"frame_change_pre", (char *)"on frame change for playback and rendering (before)"}, - {(char *)"frame_change_post", (char *)"on frame change for playback and rendering (after)"}, - {(char *)"render_pre", (char *)"on render (before)"}, - {(char *)"render_post", (char *)"on render (after)"}, - {(char *)"render_write", (char *)"on writing a render frame (directly after the frame is written)"}, - {(char *)"render_stats", (char *)"on printing render statistics"}, - {(char *)"render_init", (char *)"on initialization of a render job"}, - {(char *)"render_complete", (char *)"on completion of render job"}, - {(char *)"render_cancel", (char *)"on canceling a render job"}, - {(char *)"load_pre", (char *)"on loading a new blend file (before)"}, - {(char *)"load_post", (char *)"on loading a new blend file (after)"}, - {(char *)"save_pre", (char *)"on saving a blend file (before)"}, - {(char *)"save_post", (char *)"on saving a blend file (after)"}, - {(char *)"undo_pre", (char *)"on loading an undo step (before)"}, - {(char *)"undo_post", (char *)"on loading an undo step (after)"}, - {(char *)"redo_pre", (char *)"on loading a redo step (before)"}, - {(char *)"redo_post", (char *)"on loading a redo step (after)"}, - {(char *)"scene_update_pre", (char *)"on every scene data update. Does not imply that anything changed in the " - "scene, just that the dependency graph is about to be reevaluated, and the " - "scene is about to be updated by Blender's animation system."}, - {(char *)"scene_update_post", (char *)"on every scene data update. Does not imply that anything changed in the " - "scene, just that the dependency graph was reevaluated, and the scene was " - "possibly updated by Blender's animation system."}, - {(char *)"game_pre", (char *)"on starting the game engine"}, - {(char *)"game_post", (char *)"on ending the game engine"}, - {(char *)"version_update", (char *)"on ending the versioning code"}, + {(char *)"frame_change_pre", (char *)"on frame change for playback and rendering (before)"}, + {(char *)"frame_change_post", (char *)"on frame change for playback and rendering (after)"}, + {(char *)"render_pre", (char *)"on render (before)"}, + {(char *)"render_post", (char *)"on render (after)"}, + {(char *)"render_write", (char *)"on writing a render frame (directly after the frame is written)"}, + {(char *)"render_stats", (char *)"on printing render statistics"}, + {(char *)"render_init", (char *)"on initialization of a render job"}, + {(char *)"render_complete", (char *)"on completion of render job"}, + {(char *)"render_cancel", (char *)"on canceling a render job"}, + {(char *)"load_pre", (char *)"on loading a new blend file (before)"}, + {(char *)"load_post", (char *)"on loading a new blend file (after)"}, + {(char *)"save_pre", (char *)"on saving a blend file (before)"}, + {(char *)"save_post", (char *)"on saving a blend file (after)"}, + {(char *)"undo_pre", (char *)"on loading an undo step (before)"}, + {(char *)"undo_post", (char *)"on loading an undo step (after)"}, + {(char *)"redo_pre", (char *)"on loading a redo step (before)"}, + {(char *)"redo_post", (char *)"on loading a redo step (after)"}, + {(char *)"depsgraph_update_pre", (char *)"on depsgraph update (pre)"}, + {(char *)"depsgraph_update_post", (char *)"on depsgraph update (post)"}, + {(char *)"version_update", (char *)"on ending the versioning code"}, + {(char *)"load_factory_startup_post", (char *)"on loading factory startup (after)"}, /* sets the permanent tag */ -# define APP_CB_OTHER_FIELDS 1 +#define APP_CB_OTHER_FIELDS 1 {(char *)"persistent", (char *)"Function decorator for callback functions not to be removed when loading new files"}, {NULL} diff --git a/source/blender/python/intern/bpy_app_icons.c b/source/blender/python/intern/bpy_app_icons.c new file mode 100644 index 00000000000..12315a6e112 --- /dev/null +++ b/source/blender/python/intern/bpy_app_icons.c @@ -0,0 +1,187 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_icons.c + * \ingroup pythonintern + * + * Runtime defined icons. + */ + +#include <Python.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_icons.h" + +#include "../generic/py_capi_utils.h" + +#include "bpy_app_icons.h" + +/* We may want to load direct from file. */ +PyDoc_STRVAR(bpy_app_icons_new_triangles_doc, +".. function:: new_triangles(range, coords, colors)" +"\n" +" Create a new icon from triangle geometry.\n" +"\n" +" :arg range: Pair of ints.\n" +" :type range: tuple.\n" +" :arg coords: Sequence of bytes (6 floats for one triangle) for (X, Y) coordinates.\n" +" :type coords: byte sequence.\n" +" :arg colors: Sequence of ints (12 for one triangles) for RGBA.\n" +" :type colors: byte sequence.\n" +" :return: Unique icon value (pass to interface ``icon_value`` argument).\n" +" :rtype: int\n" +); +static PyObject *bpy_app_icons_new_triangles(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + /* bytes */ + uchar coords_range[2]; + PyObject *py_coords, *py_colors; + + static const char *_keywords[] = {"range", "coords", "colors", NULL}; + static _PyArg_Parser _parser = {"(BB)SS:new_triangles", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &coords_range[0], &coords_range[1], &py_coords, &py_colors)) + { + return NULL; + } + + const int coords_len = PyBytes_GET_SIZE(py_coords); + const int tris_len = coords_len / 6; + if (tris_len * 6 != coords_len) { + PyErr_SetString(PyExc_ValueError, "coords must be multiple of 6"); + return NULL; + } + if (PyBytes_GET_SIZE(py_colors) != 2 * coords_len) { + PyErr_SetString(PyExc_ValueError, "colors must be twice size of coords"); + return NULL; + } + + int coords_size = sizeof(uchar[2]) * tris_len * 3; + int colors_size = sizeof(uchar[4]) * tris_len * 3; + uchar (*coords)[2] = MEM_mallocN(coords_size, __func__); + uchar (*colors)[4] = MEM_mallocN(colors_size, __func__); + + memcpy(coords, PyBytes_AS_STRING(py_coords), coords_size); + memcpy(colors, PyBytes_AS_STRING(py_colors), colors_size); + + struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__); + geom->coords_len = tris_len; + geom->coords_range[0] = coords_range[0]; + geom->coords_range[1] = coords_range[1]; + geom->coords = coords; + geom->colors = colors; + geom->icon_id = 0; + int icon_id = BKE_icon_geom_ensure(geom); + return PyLong_FromLong(icon_id); +} + +PyDoc_STRVAR(bpy_app_icons_new_triangles_from_file_doc, +".. function:: new_triangles_from_file(filename)" +"\n" +" Create a new icon from triangle geometry.\n" +"\n" +" :arg filename: File path.\n" +" :type filename: string.\n" +" :return: Unique icon value (pass to interface ``icon_value`` argument).\n" +" :rtype: int\n" +); +static PyObject *bpy_app_icons_new_triangles_from_file(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + /* bytes */ + char *filename; + + static const char *_keywords[] = {"filename", NULL}; + static _PyArg_Parser _parser = {"s:new_triangles_from_file", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &filename)) + { + return NULL; + } + + struct Icon_Geom *geom = BKE_icon_geom_from_file(filename); + if (geom == NULL) { + PyErr_SetString(PyExc_ValueError, "Unable to load from file"); + return NULL; + } + int icon_id = BKE_icon_geom_ensure(geom); + return PyLong_FromLong(icon_id); +} + +PyDoc_STRVAR(bpy_app_icons_release_doc, +".. function:: release(icon_id)" +"\n" +" Release the icon.\n" +); +static PyObject *bpy_app_icons_release(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + int icon_id; + static const char *_keywords[] = {"icon_id", NULL}; + static _PyArg_Parser _parser = {"i:release", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &icon_id)) + { + return NULL; + } + + if (!BKE_icon_delete_unmanaged(icon_id)) { + PyErr_SetString(PyExc_ValueError, "invalid icon_id"); + return NULL; + } + Py_RETURN_NONE; +} + +static struct PyMethodDef M_AppIcons_methods[] = { + {"new_triangles", (PyCFunction)bpy_app_icons_new_triangles, + METH_VARARGS | METH_KEYWORDS, bpy_app_icons_new_triangles_doc}, + {"new_triangles_from_file", (PyCFunction)bpy_app_icons_new_triangles_from_file, + METH_VARARGS | METH_KEYWORDS, bpy_app_icons_new_triangles_from_file_doc}, + {"release", (PyCFunction)bpy_app_icons_release, + METH_VARARGS | METH_KEYWORDS, bpy_app_icons_release_doc}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef M_AppIcons_module_def = { + PyModuleDef_HEAD_INIT, + "bpy.app.icons", /* m_name */ + NULL, /* m_doc */ + 0, /* m_size */ + M_AppIcons_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyObject *BPY_app_icons_module(void) +{ + PyObject *sys_modules = PyImport_GetModuleDict(); + + PyObject *mod = PyModule_Create(&M_AppIcons_module_def); + + PyDict_SetItem(sys_modules, PyModule_GetNameObject(mod), mod); + + return mod; +} diff --git a/source/blender/python/intern/bpy_app_icons.h b/source/blender/python/intern/bpy_app_icons.h new file mode 100644 index 00000000000..309c7ed222f --- /dev/null +++ b/source/blender/python/intern/bpy_app_icons.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_icons.h + * \ingroup pythonintern + */ + +#ifndef __BPY_APP_ICONS_H__ +#define __BPY_APP_ICONS_H__ + +PyObject *BPY_app_icons_module(void); + +#endif /* __BPY_APP_ICONS_H__ */ diff --git a/source/blender/python/intern/bpy_app_timers.c b/source/blender/python/intern/bpy_app_timers.c new file mode 100644 index 00000000000..cd0e57200ec --- /dev/null +++ b/source/blender/python/intern/bpy_app_timers.c @@ -0,0 +1,199 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_timers.c + * \ingroup pythonintern + */ + +#include <Python.h> +#include "BLI_utildefines.h" +#include "BLI_timer.h" +#include "PIL_time.h" + +#include "BPY_extern.h" +#include "bpy_app_timers.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + + +static double handle_returned_value(PyObject *function, PyObject *ret) +{ + if (ret == NULL) { + PyErr_PrintEx(0); + PyErr_Clear(); + return -1; + } + + if (ret == Py_None) { + return -1; + } + + double value = PyFloat_AsDouble(ret); + if (value == -1.0f && PyErr_Occurred()) { + PyErr_Clear(); + printf("Error: 'bpy.app.timers' callback "); + PyObject_Print(function, stdout, Py_PRINT_RAW); + printf(" did not return None or float.\n"); + return -1; + } + + if (value < 0.0) { + value = 0.0; + } + + return value; +} + +static double py_timer_execute(uintptr_t UNUSED(uuid), void *user_data) +{ + PyObject *function = user_data; + + PyGILState_STATE gilstate; + gilstate = PyGILState_Ensure(); + + PyObject *py_ret = PyObject_CallObject(function, NULL); + double ret = handle_returned_value(function, py_ret); + + PyGILState_Release(gilstate); + + return ret; +} + +static void py_timer_free(uintptr_t UNUSED(uuid), void *user_data) +{ + PyObject *function = user_data; + + PyGILState_STATE gilstate; + gilstate = PyGILState_Ensure(); + + Py_DECREF(function); + + PyGILState_Release(gilstate); +} + + +PyDoc_STRVAR(bpy_app_timers_register_doc, +".. function:: register(function, first_interval=0, persistent=False)\n" +"\n" +" Add a new function that will be called after the specified amount of seconds.\n" +" The function gets no arguments and is expected to return either None or a float.\n" +" If ``None`` is returned, the timer will be unregistered.\n" +" A returned number specifies the delay until the function is called again.\n" +" ``functools.partial`` can be used to assign some parameters.\n" +"\n" +" :arg function: The function that should called.\n" +" :type function: Callable[[], Union[float, None]]\n" +" :arg first_interval: Seconds until the callback should be called the first time.\n" +" :type first_interval: float\n" +" :arg persistent: Don't remove timer when a new file is loaded.\n" +" :type persistent: bool\n" +); +static PyObject *bpy_app_timers_register(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + PyObject *function; + double first_interval = 0; + int persistent = false; + + static const char *_keywords[] = {"function", "first_interval", "persistent", NULL}; + static _PyArg_Parser _parser = {"O|$dp:register", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &function, &first_interval, &persistent)) + { + return NULL; + } + + if (!PyCallable_Check(function)) { + PyErr_SetString(PyExc_TypeError, "function is not callable"); + return NULL; + } + + Py_INCREF(function); + BLI_timer_register( + (intptr_t)function, + py_timer_execute, function, py_timer_free, + first_interval, persistent); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpy_app_timers_unregister_doc, +".. function:: unregister(function)\n" +"\n" +" Unregister timer.\n" +"\n" +" :arg function: Function to unregister.\n" +" :type function: function\n" +); +static PyObject *bpy_app_timers_unregister(PyObject *UNUSED(self), PyObject *function) +{ + if (!BLI_timer_unregister((intptr_t)function)) { + PyErr_SetString(PyExc_ValueError, "Error: function is not registered"); + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpy_app_timers_is_registered_doc, +".. function:: is_registered(function)\n" +"\n" +" Check if this function is registered as a timer.\n" +"\n" +" :arg function: Function to check.\n" +" :type function: int\n" +" :return: True when this function is registered, otherwise False.\n" +" :rtype: bool\n" +); +static PyObject *bpy_app_timers_is_registered(PyObject *UNUSED(self), PyObject *function) +{ + bool ret = BLI_timer_is_registered((intptr_t)function); + return PyBool_FromLong(ret); +} + + +static struct PyMethodDef M_AppTimers_methods[] = { + {"register", (PyCFunction)bpy_app_timers_register, + METH_VARARGS | METH_KEYWORDS, bpy_app_timers_register_doc}, + {"unregister", (PyCFunction)bpy_app_timers_unregister, + METH_O, bpy_app_timers_unregister_doc}, + {"is_registered", (PyCFunction)bpy_app_timers_is_registered, + METH_O, bpy_app_timers_is_registered_doc}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef M_AppTimers_module_def = { + PyModuleDef_HEAD_INIT, + "bpy.app.timers", /* m_name */ + NULL, /* m_doc */ + 0, /* m_size */ + M_AppTimers_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyObject *BPY_app_timers_module(void) +{ + PyObject *sys_modules = PyImport_GetModuleDict(); + PyObject *mod = PyModule_Create(&M_AppTimers_module_def); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(mod), mod); + return mod; +} diff --git a/source/blender/python/intern/bpy_app_timers.h b/source/blender/python/intern/bpy_app_timers.h new file mode 100644 index 00000000000..ddf0e258e67 --- /dev/null +++ b/source/blender/python/intern/bpy_app_timers.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_timers.h + * \ingroup pythonintern + */ + +#ifndef __BPY_APP_TIMERS_H__ +#define __BPY_APP_TIMERS_H__ + +PyObject *BPY_app_timers_module(void); + +#endif /* __BPY_APP_TIMERS_H__ */ diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index e7608e93f58..f098a28d679 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -48,6 +48,8 @@ #include "bpy_driver.h" +#include "BPY_extern.h" + extern void BPY_update_rna_module(void); #define USE_RNA_AS_PYOBJECT @@ -381,8 +383,12 @@ static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *d * (new)note: checking if python is running is not threadsafe [#28114] * now release the GIL on python operator execution instead, using * PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender. + * + * For copy-on-write we always cache expressions and write errors in the + * original driver, otherwise these would get freed while editing. Due to + * the GIL this is thread-safe. */ -float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime) +float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime) { PyObject *driver_vars = NULL; PyObject *retval = NULL; @@ -398,7 +404,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c int i; /* get the py expression to be evaluated */ - expr = driver->expression; + expr = driver_orig->expression; if (expr[0] == '\0') return 0.0f; @@ -438,50 +444,50 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c /* update global namespace */ bpy_pydriver_namespace_update_frame(evaltime); - if (driver->flag & DRIVER_FLAG_USE_SELF) { + if (driver_orig->flag & DRIVER_FLAG_USE_SELF) { bpy_pydriver_namespace_update_self(anim_rna); } else { bpy_pydriver_namespace_clear_self(); } - if (driver->expr_comp == NULL) - driver->flag |= DRIVER_FLAG_RECOMPILE; + if (driver_orig->expr_comp == NULL) + driver_orig->flag |= DRIVER_FLAG_RECOMPILE; /* compile the expression first if it hasn't been compiled or needs to be rebuilt */ - if (driver->flag & DRIVER_FLAG_RECOMPILE) { - Py_XDECREF(driver->expr_comp); - driver->expr_comp = PyTuple_New(2); + if (driver_orig->flag & DRIVER_FLAG_RECOMPILE) { + Py_XDECREF(driver_orig->expr_comp); + driver_orig->expr_comp = PyTuple_New(2); expr_code = Py_CompileString(expr, "<bpy driver>", Py_eval_input); - PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 0, expr_code); + PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, expr_code); - driver->flag &= ~DRIVER_FLAG_RECOMPILE; - driver->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */ + driver_orig->flag &= ~DRIVER_FLAG_RECOMPILE; + driver_orig->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */ #ifdef USE_BYTECODE_WHITELIST is_recompile = true; #endif } else { - expr_code = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 0); + expr_code = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 0); } - if (driver->flag & DRIVER_FLAG_RENAMEVAR) { + if (driver_orig->flag & DRIVER_FLAG_RENAMEVAR) { /* may not be set */ - expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1); + expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1); Py_XDECREF(expr_vars); - expr_vars = PyTuple_New(BLI_listbase_count(&driver->variables)); - PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 1, expr_vars); + expr_vars = PyTuple_New(BLI_listbase_count(&driver_orig->variables)); + PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 1, expr_vars); - for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) { + for (dvar = driver_orig->variables.first, i = 0; dvar; dvar = dvar->next) { PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_FromString(dvar->name)); } - driver->flag &= ~DRIVER_FLAG_RENAMEVAR; + driver_orig->flag &= ~DRIVER_FLAG_RENAMEVAR; } else { - expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1); + expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1); } /* add target values to a dict that will be used as '__locals__' dict */ @@ -543,7 +549,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c } #ifdef USE_BYTECODE_WHITELIST - if (is_recompile) { + if (is_recompile && expr_code) { if (!(G.f & G_SCRIPT_AUTOEXEC)) { if (!bpy_driver_secure_bytecode_validate( expr_code, (PyObject *[]){ @@ -555,7 +561,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c { Py_DECREF(expr_code); expr_code = NULL; - PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 0, NULL); + PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, NULL); } } } @@ -595,7 +601,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c return (float)result; } else { - fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", dvar->name, result); + fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", driver->expression, result); return 0.0f; } } diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h index 017a6fe89c5..971cbdf901f 100644 --- a/source/blender/python/intern/bpy_driver.h +++ b/source/blender/python/intern/bpy_driver.h @@ -27,14 +27,7 @@ #ifndef __BPY_DRIVER_H__ #define __BPY_DRIVER_H__ -struct ChannelDriver; -struct PathResolvedRNA; - int bpy_pydriver_create_dict(void); extern PyObject *bpy_pydriver_Dict; -/* externals */ -float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); -void BPY_driver_reset(void); - #endif /* __BPY_DRIVER_H__ */ diff --git a/source/blender/python/intern/bpy_gizmo_wrap.c b/source/blender/python/intern/bpy_gizmo_wrap.c new file mode 100644 index 00000000000..411822ee4da --- /dev/null +++ b/source/blender/python/intern/bpy_gizmo_wrap.c @@ -0,0 +1,228 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_gizmo_wrap.c + * \ingroup pythonintern + * + * This file is so Python can define widget-group's that C can call into. + * The generic callback functions for Python widget-group are defines in + * 'rna_wm.c', some calling into functions here to do python specific + * functionality. + * + * \note This follows 'bpy_operator_wrap.c' very closely. + * Keep in sync unless there is good reason not to! + */ + +#include <Python.h> + +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "bpy_rna.h" +#include "bpy_intern_string.h" +#include "bpy_gizmo_wrap.h" /* own include */ + +/* we may want to add, but not now */ + +/* -------------------------------------------------------------------- */ + +/** \name Gizmo + * \{ */ + + +static bool bpy_gizmotype_target_property_def( + wmGizmoType *gzt, PyObject *item) +{ + /* Note: names based on 'rna_rna.c' */ + PyObject *empty_tuple = PyTuple_New(0); + + struct { + char *id; + char *type_id; int type; + int array_length; + } params = { + .id = NULL, /* not optional */ + .type = PROP_FLOAT, + .type_id = NULL, + .array_length = 1, + }; + + static const char * const _keywords[] = {"id", "type", "array_length", NULL}; + static _PyArg_Parser _parser = {"|$ssi:register_class", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + empty_tuple, item, + &_parser, + ¶ms.id, + ¶ms.type_id, + ¶ms.array_length)) + { + goto fail; + } + + if (params.id == NULL) { + PyErr_SetString(PyExc_ValueError, "'id' argument not given"); + goto fail; + } + + if ((params.type_id != NULL) && + pyrna_enum_value_from_id( + rna_enum_property_type_items, params.type_id, ¶ms.type, "'type' enum value") == -1) + { + goto fail; + } + else { + params.type = rna_enum_property_type_items[params.type].value; + } + + if ((params.array_length < 1 || params.array_length > RNA_MAX_ARRAY_LENGTH)) { + PyErr_SetString(PyExc_ValueError, "'array_length' out of range"); + goto fail; + } + + WM_gizmotype_target_property_def(gzt, params.id, params.type, params.array_length); + Py_DECREF(empty_tuple); + return true; + +fail: + Py_DECREF(empty_tuple); + return false; +} + +static void gizmo_properties_init(wmGizmoType *gzt) +{ + PyTypeObject *py_class = gzt->ext.data; + RNA_struct_blender_type_set(gzt->ext.srna, gzt); + + /* only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier + * later */ + RNA_def_struct_identifier_no_struct_map(gzt->srna, gzt->idname); + + if (pyrna_deferred_register_class(gzt->srna, py_class) != 0) { + PyErr_Print(); /* failed to register operator props */ + PyErr_Clear(); + } + + /* Extract target property definitions from 'bl_target_properties' */ + { + /* picky developers will notice that 'bl_targets' won't work with inheritance + * get direct from the dict to avoid raising a load of attribute errors (yes this isnt ideal) - campbell */ + PyObject *py_class_dict = py_class->tp_dict; + PyObject *bl_target_properties = PyDict_GetItem(py_class_dict, bpy_intern_str_bl_target_properties); + + /* Some widgets may only exist to activate operators. */ + if (bl_target_properties != NULL) { + PyObject *bl_target_properties_fast; + if (!(bl_target_properties_fast = PySequence_Fast( + bl_target_properties, "bl_target_properties sequence"))) + { + /* PySequence_Fast sets the error */ + PyErr_Print(); + PyErr_Clear(); + return; + } + + const uint items_len = PySequence_Fast_GET_SIZE(bl_target_properties_fast); + PyObject **items = PySequence_Fast_ITEMS(bl_target_properties_fast); + + for (uint i = 0; i < items_len; i++) { + if (!bpy_gizmotype_target_property_def(gzt, items[i])) { + PyErr_Print(); + PyErr_Clear(); + break; + } + } + + Py_DECREF(bl_target_properties_fast); + } + } +} + +void BPY_RNA_gizmo_wrapper(wmGizmoType *gzt, void *userdata) +{ + /* take care not to overwrite anything set in + * WM_gizmomaptype_group_link_ptr before opfunc() is called */ + StructRNA *srna = gzt->srna; + *gzt = *((wmGizmoType *)userdata); + gzt->srna = srna; /* restore */ + + /* don't do translations here yet */ +#if 0 + /* Use i18n context from ext.srna if possible (py gizmogroups). */ + if (gt->ext.srna) { + RNA_def_struct_translation_context(gt->srna, RNA_struct_translation_context(gt->ext.srna)); + } +#endif + + gzt->struct_size = sizeof(wmGizmo); + + gizmo_properties_init(gzt); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Gizmo Group + * \{ */ + +static void gizmogroup_properties_init(wmGizmoGroupType *gzgt) +{ + PyTypeObject *py_class = gzgt->ext.data; + RNA_struct_blender_type_set(gzgt->ext.srna, gzgt); + + /* only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier + * later */ + RNA_def_struct_identifier_no_struct_map(gzgt->srna, gzgt->idname); + + if (pyrna_deferred_register_class(gzgt->srna, py_class) != 0) { + PyErr_Print(); /* failed to register operator props */ + PyErr_Clear(); + } +} + +void BPY_RNA_gizmogroup_wrapper(wmGizmoGroupType *gzgt, void *userdata) +{ + /* take care not to overwrite anything set in + * WM_gizmomaptype_group_link_ptr before opfunc() is called */ + StructRNA *srna = gzgt->srna; + *gzgt = *((wmGizmoGroupType *)userdata); + gzgt->srna = srna; /* restore */ + + /* don't do translations here yet */ +#if 0 + /* Use i18n context from ext.srna if possible (py gizmogroups). */ + if (gzgt->ext.srna) { + RNA_def_struct_translation_context(gzgt->srna, RNA_struct_translation_context(gzgt->ext.srna)); + } +#endif + + gizmogroup_properties_init(gzgt); +} + +/** \} */ diff --git a/source/blender/python/intern/bpy_gizmo_wrap.h b/source/blender/python/intern/bpy_gizmo_wrap.h new file mode 100644 index 00000000000..96f15312a4e --- /dev/null +++ b/source/blender/python/intern/bpy_gizmo_wrap.h @@ -0,0 +1,35 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_gizmo_wrap.h + * \ingroup pythonintern + */ + +#ifndef __BPY_GIZMO_WRAP_H__ +#define __BPY_GIZMO_WRAP_H__ + +struct wmGizmoType; +struct wmGizmoGroupType; + +/* exposed to rna/wm api */ +void BPY_RNA_gizmo_wrapper(struct wmGizmoType *gzt, void *userdata); +void BPY_RNA_gizmogroup_wrapper(struct wmGizmoGroupType *gzgt, void *userdata); + +#endif /* __BPY_GIZMO_WRAP_H__ */ diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 1ae3106aa76..e17e7562f2a 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -46,7 +46,6 @@ #include "RNA_types.h" #include "bpy.h" -#include "gpu.h" #include "bpy_rna.h" #include "bpy_path.h" #include "bpy_capi_utils.h" @@ -59,9 +58,9 @@ #include "BKE_appdir.h" #include "BKE_context.h" -#include "BKE_text.h" -#include "BKE_main.h" #include "BKE_global.h" /* only for script checking */ +#include "BKE_main.h" +#include "BKE_text.h" #include "CCL_api.h" @@ -75,6 +74,7 @@ #include "../generic/blf_py_api.h" #include "../generic/idprop_py_api.h" #include "../generic/imbuf_py_api.h" +#include "../gpu/gpu_py_api.h" #include "../bmesh/bmesh_py_api.h" #include "../mathutils/mathutils.h" @@ -233,7 +233,7 @@ static struct _inittab bpy_internal_modules[] = { #ifdef WITH_CYCLES {"_cycles", CCL_initPython}, #endif - {"gpu", GPU_initPython}, + {"gpu", BPyInit_gpu}, {"idprop", BPyInit_idprop}, {NULL, NULL} }; @@ -537,7 +537,8 @@ static bool python_script_exec( if (py_dict) { #ifdef PYMODULE_CLEAR_WORKAROUND - PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItemString(PyImport_GetModuleDict(), "__main__"); + PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItem( + PyImport_GetModuleDict(), bpy_intern_str___main__); PyObject *dict_back = mmod->md_dict; /* freeing the module will clear the namespace, * gives problems running classes defined in this namespace being used later. */ diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c index ac0100fa75d..41276963fc9 100644 --- a/source/blender/python/intern/bpy_intern_string.c +++ b/source/blender/python/intern/bpy_intern_string.c @@ -34,21 +34,24 @@ #include "BLI_utildefines.h" -static PyObject *bpy_intern_str_arr[13]; +static PyObject *bpy_intern_str_arr[16]; -PyObject *bpy_intern_str_register; -PyObject *bpy_intern_str_unregister; -PyObject *bpy_intern_str_bl_rna; +PyObject *bpy_intern_str___annotations__; +PyObject *bpy_intern_str___doc__; +PyObject *bpy_intern_str___main__; +PyObject *bpy_intern_str___module__; +PyObject *bpy_intern_str___name__; +PyObject *bpy_intern_str___slots__; +PyObject *bpy_intern_str_attr; PyObject *bpy_intern_str_bl_property; +PyObject *bpy_intern_str_bl_rna; +PyObject *bpy_intern_str_bl_target_properties; PyObject *bpy_intern_str_bpy_types; -PyObject *bpy_intern_str_order; -PyObject *bpy_intern_str_attr; -PyObject *bpy_intern_str_self; PyObject *bpy_intern_str_frame; -PyObject *bpy_intern_str___slots__; -PyObject *bpy_intern_str___name__; -PyObject *bpy_intern_str___doc__; -PyObject *bpy_intern_str___module__; +PyObject *bpy_intern_str_properties; +PyObject *bpy_intern_str_register; +PyObject *bpy_intern_str_self; +PyObject *bpy_intern_str_unregister; void bpy_intern_string_init(void) { @@ -57,19 +60,22 @@ void bpy_intern_string_init(void) #define BPY_INTERN_STR(var, str) \ { var = bpy_intern_str_arr[i++] = PyUnicode_FromString(str); } (void)0 - BPY_INTERN_STR(bpy_intern_str_register, "register"); - BPY_INTERN_STR(bpy_intern_str_unregister, "unregister"); - BPY_INTERN_STR(bpy_intern_str_bl_rna, "bl_rna"); + BPY_INTERN_STR(bpy_intern_str___annotations__, "__annotations__"); + BPY_INTERN_STR(bpy_intern_str___doc__, "__doc__"); + BPY_INTERN_STR(bpy_intern_str___main__, "__main__"); + BPY_INTERN_STR(bpy_intern_str___module__, "__module__"); + BPY_INTERN_STR(bpy_intern_str___name__, "__name__"); + BPY_INTERN_STR(bpy_intern_str___slots__, "__slots__"); + BPY_INTERN_STR(bpy_intern_str_attr, "attr"); BPY_INTERN_STR(bpy_intern_str_bl_property, "bl_property"); + BPY_INTERN_STR(bpy_intern_str_bl_rna, "bl_rna"); + BPY_INTERN_STR(bpy_intern_str_bl_target_properties, "bl_target_properties"); BPY_INTERN_STR(bpy_intern_str_bpy_types, "bpy.types"); - BPY_INTERN_STR(bpy_intern_str_order, "order"); - BPY_INTERN_STR(bpy_intern_str_attr, "attr"); - BPY_INTERN_STR(bpy_intern_str_self, "self"); BPY_INTERN_STR(bpy_intern_str_frame, "frame"); - BPY_INTERN_STR(bpy_intern_str___slots__, "__slots__"); - BPY_INTERN_STR(bpy_intern_str___name__, "__name__"); - BPY_INTERN_STR(bpy_intern_str___doc__, "__doc__"); - BPY_INTERN_STR(bpy_intern_str___module__, "__module__"); + BPY_INTERN_STR(bpy_intern_str_properties, "properties"); + BPY_INTERN_STR(bpy_intern_str_register, "register"); + BPY_INTERN_STR(bpy_intern_str_self, "self"); + BPY_INTERN_STR(bpy_intern_str_unregister, "unregister"); #undef BPY_INTERN_STR diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h index 394e84d89bd..41cd58f9c3d 100644 --- a/source/blender/python/intern/bpy_intern_string.h +++ b/source/blender/python/intern/bpy_intern_string.h @@ -30,18 +30,21 @@ void bpy_intern_string_init(void); void bpy_intern_string_exit(void); -extern PyObject *bpy_intern_str_register; -extern PyObject *bpy_intern_str_unregister; -extern PyObject *bpy_intern_str_bl_rna; +extern PyObject *bpy_intern_str___annotations__; +extern PyObject *bpy_intern_str___doc__; +extern PyObject *bpy_intern_str___main__; +extern PyObject *bpy_intern_str___module__; +extern PyObject *bpy_intern_str___name__; +extern PyObject *bpy_intern_str___slots__; +extern PyObject *bpy_intern_str_attr; extern PyObject *bpy_intern_str_bl_property; +extern PyObject *bpy_intern_str_bl_rna; +extern PyObject *bpy_intern_str_bl_target_properties; extern PyObject *bpy_intern_str_bpy_types; -extern PyObject *bpy_intern_str_order; -extern PyObject *bpy_intern_str_attr; -extern PyObject *bpy_intern_str_self; extern PyObject *bpy_intern_str_frame; -extern PyObject *bpy_intern_str___slots__; -extern PyObject *bpy_intern_str___name__; -extern PyObject *bpy_intern_str___doc__; -extern PyObject *bpy_intern_str___module__; +extern PyObject *bpy_intern_str_properties; +extern PyObject *bpy_intern_str_register; +extern PyObject *bpy_intern_str_self; +extern PyObject *bpy_intern_str_unregister; #endif /* __BPY_INTERN_STRING_H__ */ diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index e66b4e834dc..5c64a65fb58 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -38,16 +38,16 @@ #include "BLI_linklist.h" #include "BLI_path_util.h" -#include "BLO_readfile.h" - -#include "BKE_main.h" -#include "BKE_library.h" +#include "BKE_context.h" #include "BKE_idcode.h" +#include "BKE_library.h" +#include "BKE_main.h" #include "BKE_report.h" -#include "BKE_context.h" #include "DNA_space_types.h" /* FILE_LINK, FILE_RELPATH */ +#include "BLO_readfile.h" + #include "bpy_capi_utils.h" #include "bpy_library.h" @@ -332,6 +332,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) Main *bmain = CTX_data_main(BPy_GetContext()); Main *mainl = NULL; int err = 0; + const bool do_append = ((self->flag & FILE_LINK) == 0); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); @@ -341,7 +342,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) { int idcode_step = 0, idcode; while ((idcode = BKE_idcode_iter_step(&idcode_step))) { - if (BKE_idcode_is_linkable(idcode)) { + if (BKE_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) { const char *name_plural = BKE_idcode_to_name_plural(idcode); PyObject *ls = PyDict_GetItemString(self->dict, name_plural); // printf("lib: %s\n", name_plural); @@ -402,7 +403,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) } else { Library *lib = mainl->curlib; /* newly added lib, assign before append end */ - BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL); + BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL, NULL, NULL); BLO_blendhandle_close(self->blo_handle); self->blo_handle = NULL; @@ -414,7 +415,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BKE_main_lib_objects_recalc_all(bmain); /* append, rather than linking */ - if ((self->flag & FILE_LINK) == 0) { + if (do_append) { BKE_library_make_local(bmain, lib, old_to_new_ids, true, false); } } @@ -427,7 +428,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) { int idcode_step = 0, idcode; while ((idcode = BKE_idcode_iter_step(&idcode_step))) { - if (BKE_idcode_is_linkable(idcode)) { + if (BKE_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) { const char *name_plural = BKE_idcode_to_name_plural(idcode); PyObject *ls = PyDict_GetItemString(self->dict, name_plural); if (ls && PyList_Check(ls)) { diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index 76b7ccf72fa..69dcfdb9455 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -34,7 +34,6 @@ #include "BLI_string.h" #include "BLI_path_util.h" -#include "BKE_library.h" #include "BKE_blendfile.h" #include "BKE_global.h" #include "BKE_main.h" @@ -135,7 +134,7 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject if (!pyrna_id_FromPyObject(key, &id_store->id)) { PyErr_Format(PyExc_TypeError, - "Expected and ID type, not %.200s", + "Expected an ID type, not %.200s", Py_TYPE(key)->tp_name); ret = NULL; goto finally; diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c new file mode 100644 index 00000000000..101cc8b41a3 --- /dev/null +++ b/source/blender/python/intern/bpy_msgbus.c @@ -0,0 +1,399 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_msgbus.c + * \ingroup pythonintern + * This file defines '_bpy_msgbus' module, exposed as 'bpy.msgbus'. + */ + +#include <Python.h> + +#include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" +#include "../mathutils/mathutils.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "WM_message.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "bpy_capi_utils.h" +#include "bpy_rna.h" +#include "bpy_intern_string.h" +#include "bpy_gizmo_wrap.h" /* own include */ + + +#include "bpy_msgbus.h" /* own include */ + + +/* -------------------------------------------------------------------- */ +/** \name Internal Utils + * \{ */ + +#define BPY_MSGBUS_RNA_MSGKEY_DOC \ +" :arg key: Represents the type of data being subscribed to\n" \ +"\n" \ +" Arguments include\n" \ +" - :class:`bpy.types.Property` instance.\n" \ +" - :class:`bpy.types.Struct` type.\n" \ +" - (:class:`bpy.types.Struct`, str) type and property name.\n" \ +" :type key: Muliple\n" + +/** + * There are multiple ways we can get RNA from Python, + * it's also possible to register a type instead of an instance. + * + * This function handles converting Python to RNA subscription information. + * + * \param py_sub: See #BPY_MSGBUS_RNA_MSGKEY_DOC for description. + * \param msg_key_params: Message key with all members zeroed out. + * \return -1 on failure, 0 on success. + */ +static int py_msgbus_rna_key_from_py( + PyObject *py_sub, + wmMsgParams_RNA *msg_key_params, + const char *error_prefix) +{ + + /* Allow common case, object rotation, location - etc. */ + if (BaseMathObject_CheckExact(py_sub)) { + BaseMathObject *py_sub_math = (BaseMathObject *)py_sub; + if (py_sub_math->cb_user == NULL) { + PyErr_Format( + PyExc_TypeError, + "%s: math argument has no owner", + error_prefix); + return -1; + } + py_sub = py_sub_math->cb_user; + /* Common case will use BPy_PropertyRNA_Check below. */ + } + + if (BPy_PropertyRNA_Check(py_sub)) { + BPy_PropertyRNA *data_prop = (BPy_PropertyRNA *)py_sub; + PYRNA_PROP_CHECK_INT(data_prop); + msg_key_params->ptr = data_prop->ptr; + msg_key_params->prop = data_prop->prop; + } + else if (BPy_StructRNA_Check(py_sub)) { + /* note, this isn't typically used since we don't edit structs directly. */ + BPy_StructRNA *data_srna = (BPy_StructRNA *)py_sub; + PYRNA_STRUCT_CHECK_INT(data_srna); + msg_key_params->ptr = data_srna->ptr; + } + /* TODO - property / type, not instance. */ + else if (PyType_Check(py_sub)) { + StructRNA *data_type = pyrna_struct_as_srna(py_sub, false, error_prefix); + if (data_type == NULL) { + return -1; + } + msg_key_params->ptr.type = data_type; + } + else if (PyTuple_CheckExact(py_sub)) { + if (PyTuple_GET_SIZE(py_sub) == 2) { + PyObject *data_type_py = PyTuple_GET_ITEM(py_sub, 0); + PyObject *data_prop_py = PyTuple_GET_ITEM(py_sub, 1); + StructRNA *data_type = pyrna_struct_as_srna(data_type_py, false, error_prefix); + if (data_type == NULL) { + return -1; + } + if (!PyUnicode_CheckExact(data_prop_py)) { + PyErr_Format( + PyExc_TypeError, + "%s: expected property to be a string", + error_prefix); + return -1; + } + PointerRNA data_type_ptr = { .type = data_type, }; + const char *data_prop_str = _PyUnicode_AsString(data_prop_py); + PropertyRNA *data_prop = RNA_struct_find_property(&data_type_ptr, data_prop_str); + + if (data_prop == NULL) { + PyErr_Format( + PyExc_TypeError, + "%s: struct %.200s does not contain property %.200s", + error_prefix, + RNA_struct_identifier(data_type), + data_prop_str); + return -1; + } + + msg_key_params->ptr.type = data_type; + msg_key_params->prop = data_prop; + } + else { + PyErr_Format( + PyExc_ValueError, + "%s: Expected a pair (type, property_id)", + error_prefix); + return -1; + } + } + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Callbacks + * \{ */ + +#define BPY_MSGBUS_USER_DATA_LEN 2 + +/* Follow wmMsgNotifyFn spec */ +static void bpy_msgbus_notify( + bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + PyGILState_STATE gilstate; + bpy_context_set(C, &gilstate); + + PyObject *user_data = msg_val->user_data; + BLI_assert(PyTuple_GET_SIZE(user_data) == BPY_MSGBUS_USER_DATA_LEN); + + PyObject *callback_args = PyTuple_GET_ITEM(user_data, 0); + PyObject *callback_notify = PyTuple_GET_ITEM(user_data, 1); + + const bool is_write_ok = pyrna_write_check(); + if (!is_write_ok) { + pyrna_write_set(true); + } + + PyObject *ret = PyObject_CallObject(callback_notify, callback_args); + + if (ret == NULL) { + PyC_Err_PrintWithFunc(callback_notify); + } + else { + if (ret != Py_None) { + PyErr_SetString(PyExc_ValueError, "the return value must be None"); + PyC_Err_PrintWithFunc(callback_notify); + } + Py_DECREF(ret); + } + + bpy_context_clear(C, &gilstate); + + if (!is_write_ok) { + pyrna_write_set(false); + } +} + +/* Follow wmMsgSubscribeValueFreeDataFn spec */ +static void bpy_msgbus_subscribe_value_free_data( + struct wmMsgSubscribeKey *UNUSED(msg_key), struct wmMsgSubscribeValue *msg_val) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + Py_DECREF(msg_val->owner); + Py_DECREF(msg_val->user_data); + PyGILState_Release(gilstate); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Message Bus API + * \{ */ + +PyDoc_STRVAR(bpy_msgbus_subscribe_rna_doc, +".. function:: subscribe_rna(data, owner, args, notify)\n" +"\n" +BPY_MSGBUS_RNA_MSGKEY_DOC +" :arg owner: Handle for this subscription (compared by identity).\n" +" :type owner: Any type.\n" +"\n" +" Returns a new vector int property definition.\n" +); +static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *error_prefix = "subscribe_rna"; + PyObject *py_sub = NULL; + PyObject *py_owner = NULL; + PyObject *callback_args = NULL; + PyObject *callback_notify = NULL; + + enum { + IS_PERSISTENT = (1 << 0), + }; + PyObject *py_options = NULL; + EnumPropertyItem py_options_enum[] = { + {IS_PERSISTENT, "PERSISTENT", 0, ""}, + {0, NULL, 0, NULL, NULL} + }; + int options = 0; + + static const char *_keywords[] = { + "key", + "owner", + "args", + "notify", + "options", + NULL, + }; + static _PyArg_Parser _parser = {"$OOO!OO!:subscribe_rna", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &py_sub, &py_owner, + &PyTuple_Type, &callback_args, + &callback_notify, + &PySet_Type, &py_options)) + { + return NULL; + } + + if (py_options && + (pyrna_set_to_enum_bitfield(py_options_enum, py_options, &options, error_prefix)) == -1) + { + return NULL; + } + + /* Note: we may want to have a way to pass this in. */ + bContext *C = (bContext *)BPy_GetContext(); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + wmMsgParams_RNA msg_key_params = {{{0}}}; + + wmMsgSubscribeValue msg_val_params = {0}; + + if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) { + return NULL; + } + + if (!PyFunction_Check(callback_notify)) { + PyErr_Format( + PyExc_TypeError, + "notify expects a function, found %.200s", + Py_TYPE(callback_notify)->tp_name); + return NULL; + } + + if (options != 0) { + if (options & IS_PERSISTENT) { + msg_val_params.is_persistent = true; + } + } + + /* owner can be anything. */ + { + msg_val_params.owner = py_owner; + Py_INCREF(py_owner); + } + + { + PyObject *user_data = PyTuple_New(2); + PyTuple_SET_ITEMS( + user_data, + Py_INCREF_RET(callback_args), + Py_INCREF_RET(callback_notify)); + msg_val_params.user_data = user_data; + } + + msg_val_params.notify = bpy_msgbus_notify; + msg_val_params.free_data = bpy_msgbus_subscribe_value_free_data; + + WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_val_params, __func__); + + WM_msg_dump(mbus, __func__); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpy_msgbus_publish_rna_doc, +".. function:: publish_rna(data, owner, args, notify)\n" +"\n" +BPY_MSGBUS_RNA_MSGKEY_DOC +"\n" +" Notify subscribers of changes to this property\n" +" (this typically doesn't need to be called explicitly since changes will automatically publish updates).\n" +" In some cases it may be useful to publish changes explicitly using more general keys.\n" +); +static PyObject *bpy_msgbus_publish_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *error_prefix = "publish_rna"; + PyObject *py_sub = NULL; + + static const char *_keywords[] = { + "key", + NULL, + }; + static _PyArg_Parser _parser = {"$O:publish_rna", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &py_sub)) + { + return NULL; + } + + /* Note: we may want to have a way to pass this in. */ + bContext *C = (bContext *)BPy_GetContext(); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + wmMsgParams_RNA msg_key_params = {{{0}}}; + + if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) { + return NULL; + } + + WM_msg_publish_rna_params(mbus, &msg_key_params); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpy_msgbus_clear_by_owner_doc, +".. function:: clear_by_owner(owner)\n" +"\n" +" Clear all subscribers using this owner.\n" +); +static PyObject *bpy_msgbus_clear_by_owner(PyObject *UNUSED(self), PyObject *py_owner) +{ + bContext *C = (bContext *)BPy_GetContext(); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + WM_msgbus_clear_by_owner(mbus, py_owner); + Py_RETURN_NONE; +} + +static struct PyMethodDef BPy_msgbus_methods[] = { + {"subscribe_rna", (PyCFunction)bpy_msgbus_subscribe_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_subscribe_rna_doc}, + {"publish_rna", (PyCFunction)bpy_msgbus_publish_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_publish_rna_doc}, + {"clear_by_owner", (PyCFunction)bpy_msgbus_clear_by_owner, METH_O, bpy_msgbus_clear_by_owner_doc}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef _bpy_msgbus_def = { + PyModuleDef_HEAD_INIT, + .m_name = "msgbus", + .m_methods = BPy_msgbus_methods, +}; + + +PyObject *BPY_msgbus_module(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&_bpy_msgbus_def); + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/intern/bpy_msgbus.h b/source/blender/python/intern/bpy_msgbus.h new file mode 100644 index 00000000000..97b20e9b926 --- /dev/null +++ b/source/blender/python/intern/bpy_msgbus.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_msgbus.h + * \ingroup pythonintern + */ + +#ifndef __BPY_MSGBUS_H__ +#define __BPY_MSGBUS_H__ + +PyObject *BPY_msgbus_module(void); + +#endif /* __BPY_MSGBUS_H__ */ diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 0db2fc189c1..b7242680dca 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -1905,7 +1905,7 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge #define BPY_PROPDEF_UNIT_DOC \ " :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION', 'MASS', 'CAMERA'].\n" \ -" :type unit: string\n" \ +" :type unit: string\n" \ #define BPY_PROPDEF_NUM_MIN_DOC \ " :arg min: Hard minimum, trying to assign a value below will silently assign this minimum instead.\n" \ @@ -3083,9 +3083,10 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) { - PyErr_Format(PyExc_TypeError, - "CollectionProperty(...) expected an RNA type derived from %.200s", - RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup)); + PyErr_Format( + PyExc_TypeError, + "CollectionProperty(...) expected an RNA type derived from %.200s", + RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup)); return NULL; } @@ -3203,11 +3204,6 @@ PyObject *BPY_rna_props(void) submodule = PyModule_Create(&props_module); PyDict_SetItemString(PyImport_GetModuleDict(), props_module.m_name, submodule); - /* INCREF since its its assumed that all these functions return the - * module with a new ref like PyDict_New, since they are passed to - * PyModule_AddObject which steals a ref */ - Py_INCREF(submodule); - /* api needs the PyObjects internally */ submodule_dict = PyModule_GetDict(submodule); diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h index 614c1b4b708..fa2594f94d2 100644 --- a/source/blender/python/intern/bpy_props.h +++ b/source/blender/python/intern/bpy_props.h @@ -34,6 +34,6 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw); StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix); -#define PYRNA_STACK_ARRAY 32 +#define PYRNA_STACK_ARRAY RNA_STACK_ARRAY #endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index b36a6e06651..f25f007033f 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -315,7 +315,7 @@ static bool rna_id_write_error(PointerRNA *ptr, PyObject *key) ID *id = ptr->id.data; if (id) { const short idcode = GS(id->name); - if (!ELEM(idcode, ID_WM, ID_SCR)) { /* may need more added here */ + if (!ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { /* may need more added here */ const char *idtype = BKE_idcode_to_name(idcode); const char *pyname; if (key && PyUnicode_Check(key)) pyname = _PyUnicode_AsString(key); @@ -1401,53 +1401,39 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) ret = PyUnicode_FromString(identifier); } else { + /* Static, no need to free. */ const EnumPropertyItem *enum_item; - bool free; + bool free_dummy; + RNA_property_enum_items_ex(NULL, ptr, prop, true, &enum_item, NULL, &free_dummy); + BLI_assert(!free_dummy); - /* don't throw error here, can't trust blender 100% to give the - * right values, python code should not generate error for that */ - RNA_property_enum_items(BPy_GetContext(), ptr, prop, &enum_item, NULL, &free); - if (enum_item && enum_item->identifier) { - ret = PyUnicode_FromString(enum_item->identifier); - } - else { - if (free) { - MEM_freeN((void *)enum_item); - } - RNA_property_enum_items(NULL, ptr, prop, &enum_item, NULL, &free); - - /* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */ - if (enum_item != DummyRNA_NULL_items) { - const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL); + /* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */ + if (enum_item != DummyRNA_NULL_items) { + const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL); - /* prefer not fail silently in case of api errors, maybe disable it later */ - CLOG_WARN(BPY_LOG_RNA, - "current value '%d' " - "matches no enum in '%s', '%s', '%s'", - val, RNA_struct_identifier(ptr->type), - ptr_name, RNA_property_identifier(prop)); + /* prefer not fail silently in case of api errors, maybe disable it later */ + CLOG_WARN(BPY_LOG_RNA, + "current value '%d' " + "matches no enum in '%s', '%s', '%s'", + val, RNA_struct_identifier(ptr->type), + ptr_name, RNA_property_identifier(prop)); #if 0 /* gives python decoding errors while generating docs :( */ - char error_str[256]; - BLI_snprintf(error_str, sizeof(error_str), - "RNA Warning: Current value \"%d\" " - "matches no enum in '%s', '%s', '%s'", - val, RNA_struct_identifier(ptr->type), - ptr_name, RNA_property_identifier(prop)); - - PyErr_Warn(PyExc_RuntimeWarning, error_str); + char error_str[256]; + BLI_snprintf(error_str, sizeof(error_str), + "RNA Warning: Current value \"%d\" " + "matches no enum in '%s', '%s', '%s'", + val, RNA_struct_identifier(ptr->type), + ptr_name, RNA_property_identifier(prop)); + + PyErr_Warn(PyExc_RuntimeWarning, error_str); #endif - if (ptr_name) - MEM_freeN((void *)ptr_name); - } - - ret = PyUnicode_FromString(""); + if (ptr_name) + MEM_freeN((void *)ptr_name); } - if (free) { - MEM_freeN((void *)enum_item); - } + ret = PyUnicode_FromString(""); #if 0 PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); @@ -1729,7 +1715,25 @@ static int pyrna_py_to_prop( const int subtype = RNA_property_subtype(prop); const char *param; - if (subtype == PROP_BYTESTRING) { + if (value == Py_None) { + if ((RNA_property_flag(prop) & PROP_NEVER_NULL) == 0) { + if (data) { + *((char **)data) = (char *)NULL; + } + else { + RNA_property_string_set(ptr, prop, NULL); + } + } + else { + PyC_Err_Format_Prefix( + PyExc_TypeError, + "%.200s %.200s.%.200s doesn't support None from string types", + error_prefix, RNA_struct_identifier(ptr->type), + RNA_property_identifier(prop)); + return -1; + } + } + else if (subtype == PROP_BYTESTRING) { /* Byte String */ @@ -1849,19 +1853,28 @@ static int pyrna_py_to_prop( * class mixing if this causes problems in the future it should be removed. */ if ((ptr_type == &RNA_AnyType) && - (BPy_StructRNA_Check(value)) && - (RNA_struct_is_a(((BPy_StructRNA *)value)->ptr.type, &RNA_Operator))) + (BPy_StructRNA_Check(value))) { - value = PyObject_GetAttrString(value, "properties"); - value_new = value; + const StructRNA *base_type = + RNA_struct_base_child_of(((const BPy_StructRNA *)value)->ptr.type, NULL); + if (ELEM(base_type, &RNA_Operator, &RNA_Gizmo)) { + value = PyObject_GetAttr(value, bpy_intern_str_properties); + value_new = value; + } } - - /* if property is an OperatorProperties pointer and value is a map, + /* if property is an OperatorProperties/GizmoProperties pointer and value is a map, * forward back to pyrna_pydict_to_props */ - if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) { - PointerRNA opptr = RNA_property_pointer_get(ptr, prop); - return pyrna_pydict_to_props(&opptr, value, false, error_prefix); + if (PyDict_Check(value)) { + const StructRNA *base_type = RNA_struct_base_child_of(ptr_type, NULL); + if (base_type == &RNA_OperatorProperties) { + PointerRNA opptr = RNA_property_pointer_get(ptr, prop); + return pyrna_pydict_to_props(&opptr, value, false, error_prefix); + } + else if (base_type == &RNA_GizmoProperties) { + PointerRNA opptr = RNA_property_pointer_get(ptr, prop); + return pyrna_pydict_to_props(&opptr, value, false, error_prefix); + } } /* another exception, allow to pass a collection as an RNA property */ @@ -3500,6 +3513,68 @@ static PyObject *pyrna_struct_is_property_readonly(BPy_StructRNA *self, PyObject return PyBool_FromLong(!RNA_property_editable(&self->ptr, prop)); } + +PyDoc_STRVAR(pyrna_struct_is_property_overridable_static_doc, +".. method:: is_property_overridable_static(property)\n" +"\n" +" Check if a property is statically overridable.\n" +"\n" +" :return: True when the property is statically overridable.\n" +" :rtype: boolean\n" +); +static PyObject *pyrna_struct_is_property_overridable_static(BPy_StructRNA *self, PyObject *args) +{ + PropertyRNA *prop; + const char *name; + + PYRNA_STRUCT_CHECK_OBJ(self); + + if (!PyArg_ParseTuple(args, "s:is_property_overridable_static", &name)) { + return NULL; + } + + if ((prop = RNA_struct_find_property(&self->ptr, name)) == NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s.is_property_overridable_static(\"%.200s\") not found", + RNA_struct_identifier(self->ptr.type), name); + return NULL; + } + + return PyBool_FromLong((long)RNA_property_overridable_get(&self->ptr, prop)); +} + +PyDoc_STRVAR(pyrna_struct_property_overridable_static_set_doc, +".. method:: property_overridable_static_set(property)\n" +"\n" +" Define a property as statically overridable or not (only for custom properties!).\n" +"\n" +" :return: True when the overridable status of the property was successfully set.\n" +" :rtype: boolean\n" +); +static PyObject *pyrna_struct_property_overridable_static_set(BPy_StructRNA *self, PyObject *args) +{ + PropertyRNA *prop; + const char *name; + int is_overridable; + + PYRNA_STRUCT_CHECK_OBJ(self); + + if (!PyArg_ParseTuple(args, "sp:property_overridable_static_set", &name, &is_overridable)) { + return NULL; + } + + if ((prop = RNA_struct_find_property(&self->ptr, name)) == NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s.property_overridable_static_set(\"%.200s\") not found", + RNA_struct_identifier(self->ptr.type), name); + return NULL; + } + + return PyBool_FromLong((long)RNA_property_overridable_static_set(&self->ptr, prop, (bool)is_overridable)); +} + + + PyDoc_STRVAR(pyrna_struct_path_resolve_doc, ".. method:: path_resolve(path, coerce=True)\n" "\n" @@ -5172,6 +5247,8 @@ static struct PyMethodDef pyrna_struct_methods[] = { {"property_unset", (PyCFunction)pyrna_struct_property_unset, METH_VARARGS, pyrna_struct_property_unset_doc}, {"is_property_hidden", (PyCFunction)pyrna_struct_is_property_hidden, METH_VARARGS, pyrna_struct_is_property_hidden_doc}, {"is_property_readonly", (PyCFunction)pyrna_struct_is_property_readonly, METH_VARARGS, pyrna_struct_is_property_readonly_doc}, + {"is_property_overridable_static", (PyCFunction)pyrna_struct_is_property_overridable_static, METH_VARARGS, pyrna_struct_is_property_overridable_static_doc}, + {"property_overridable_static_set", (PyCFunction)pyrna_struct_property_overridable_static_set, METH_VARARGS, pyrna_struct_property_overridable_static_set_doc}, {"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_VARARGS, pyrna_struct_path_resolve_doc}, {"path_from_id", (PyCFunction)pyrna_struct_path_from_id, METH_VARARGS, pyrna_struct_path_from_id_doc}, {"type_recast", (PyCFunction)pyrna_struct_type_recast, METH_NOARGS, pyrna_struct_type_recast_doc}, @@ -5581,6 +5658,17 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject item = NULL; if (i < pyargs_len) { + /* New in 2.8x, optional arguments must be keywords. */ + if (UNLIKELY((flag_parameter & PARM_REQUIRED) == 0)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s(): required parameter \"%.200s\" to be a keyword argument!", + RNA_struct_identifier(self_ptr->type), + RNA_function_identifier(self_func), + RNA_property_identifier(parm)); + err = -1; + break; + } + item = PyTuple_GET_ITEM(args, i); kw_arg = false; } @@ -7353,29 +7441,40 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item static int pyrna_deferred_register_props(StructRNA *srna, PyObject *class_dict) { + PyObject *annotations_dict; PyObject *item, *key; - PyObject *order; Py_ssize_t pos = 0; int ret = 0; /* in both cases PyDict_CheckExact(class_dict) will be true even * though Operators have a metaclass dict namespace */ + if ((annotations_dict = PyDict_GetItem(class_dict, bpy_intern_str___annotations__)) && + PyDict_CheckExact(annotations_dict)) + { + while (PyDict_Next(annotations_dict, &pos, &key, &item)) { + ret = deferred_register_prop(srna, key, item); - if ((order = PyDict_GetItem(class_dict, bpy_intern_str_order)) && PyList_CheckExact(order)) { - for (pos = 0; pos < PyList_GET_SIZE(order); pos++) { - key = PyList_GET_ITEM(order, pos); - /* however unlikely its possible - * fails in py 3.3 beta with __qualname__ */ - if ((item = PyDict_GetItem(class_dict, key))) { - ret = deferred_register_prop(srna, key, item); - if (ret != 0) { - break; - } + if (ret != 0) { + break; } } } - else { + + { + /* This block can be removed once 2.8x is released and annotations are in use. */ + bool has_warning = false; while (PyDict_Next(class_dict, &pos, &key, &item)) { + if (pyrna_is_deferred_prop(item)) { + if (!has_warning) { + printf("Warning: class %.200s " + "contains a properties which should be an annotation!\n", + RNA_struct_identifier(srna)); + PyC_LineSpit(); + has_warning = true; + } + printf(" make annotation: %.200s.%.200s\n", + RNA_struct_identifier(srna), _PyUnicode_AsString(key)); + } ret = deferred_register_prop(srna, key, item); if (ret != 0) @@ -7658,7 +7757,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param PyGILState_STATE gilstate; #ifdef USE_PEDANTIC_WRITE - const bool is_readonly_init = !RNA_struct_is_a(ptr->type, &RNA_Operator); + const bool is_readonly_init = !(RNA_struct_is_a(ptr->type, &RNA_Operator) || + RNA_struct_is_a(ptr->type, &RNA_Gizmo)); // const char *func_id = RNA_function_identifier(func); /* UNUSED */ /* testing, for correctness, not operator and not draw function */ const bool is_readonly = !(RNA_function_flag(func) & FUNC_ALLOW_WRITE); @@ -8316,6 +8416,43 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla Py_RETURN_NONE; } +/* Access to 'owner_id' internal global. */ + +static PyObject *pyrna_bl_owner_id_get(PyObject *UNUSED(self)) +{ + const char *name = RNA_struct_state_owner_get(); + if (name) { + return PyUnicode_FromString(name); + } + Py_RETURN_NONE; +} + +static PyObject *pyrna_bl_owner_id_set(PyObject *UNUSED(self), PyObject *value) +{ + const char *name; + if (value == Py_None) { + name = NULL; + } + else if (PyUnicode_Check(value)) { + name = _PyUnicode_AsString(value); + } + else { + PyErr_Format(PyExc_ValueError, + "owner_set(...): " + "expected None or a string, not '%.200s'", Py_TYPE(value)->tp_name); + return NULL; + } + RNA_struct_state_owner_set(name); + Py_RETURN_NONE; +} + +PyMethodDef meth_bpy_owner_id_get = { + "_bl_owner_id_get", (PyCFunction)pyrna_bl_owner_id_get, METH_NOARGS, NULL, +}; +PyMethodDef meth_bpy_owner_id_set = { + "_bl_owner_id_set", (PyCFunction)pyrna_bl_owner_id_set, METH_O, NULL, +}; + /* currently this is fairly limited, we would need to make some way to split up * pyrna_callback_classmethod_... if we want more than one callback per type */ typedef struct BPyRNA_CallBack { @@ -8323,9 +8460,46 @@ typedef struct BPyRNA_CallBack { StructRNA *bpy_srna; } PyRNA_CallBack; +PyDoc_STRVAR(pyrna_draw_handler_add_doc, +".. method:: draw_handler_add(callback, args, region_type, draw_type)\n" +"\n" +" Add a new draw handler to this space type.\n" +" It will be called every time the specified region in the space type will be drawn.\n" +" Note: All arguments are positional only for now.\n" +"\n" +" :param callback:\n" +" A function that will be called when the region is drawn.\n" +" It gets the specified arguments as input.\n" +" :type callback: function\n" +" :param args: Arguments that will be passed to the callback.\n" +" :type args: tuple\n" +" :param region_type: The region type the callback draws in; usually `'WINDOW'`. (:class:`bpy.types.Region.type`)\n" +" :type region_type: str\n" +" :param draw_type: Usually `POST_PIXEL` for 2D drawing and `POST_VIEW` for 3D drawing. In some cases `PRE_VIEW` can be used.\n" +" :type draw_type: str\n" +" :return: Handler that can be removed later on.\n" +" :rtype: object" +); + +PyDoc_STRVAR(pyrna_draw_handler_remove_doc, +".. method:: draw_handler_remove(handler, region_type)\n" +"\n" +" Remove a draw handler that was added previously.\n" +"\n" +" :param handler: The draw handler that should be removed.\n" +" :type handler: object\n" +" :param region_type: Region type the callback was added to.\n" +" :type region_type: str\n" +); + static struct BPyRNA_CallBack pyrna_cb_methods[] = { - {{"draw_handler_add", (PyCFunction)pyrna_callback_classmethod_add, METH_VARARGS | METH_STATIC, ""}, &RNA_Space}, - {{"draw_handler_remove", (PyCFunction)pyrna_callback_classmethod_remove, METH_VARARGS | METH_STATIC, ""}, &RNA_Space}, + {{"draw_handler_add", (PyCFunction)pyrna_callback_classmethod_add, + METH_VARARGS | METH_STATIC, pyrna_draw_handler_add_doc}, &RNA_Space}, + {{"draw_handler_remove", (PyCFunction)pyrna_callback_classmethod_remove, + METH_VARARGS | METH_STATIC, pyrna_draw_handler_remove_doc}, &RNA_Space}, + + {{"draw_cursor_add", (PyCFunction)pyrna_callback_classmethod_add, METH_VARARGS | METH_STATIC, ""}, &RNA_WindowManager}, + {{"draw_cursor_remove", (PyCFunction)pyrna_callback_classmethod_remove, METH_VARARGS | METH_STATIC, ""}, &RNA_WindowManager}, {{NULL, NULL, 0, NULL}, NULL} }; diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index f666294666e..32a63acde40 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -225,4 +225,8 @@ int pyrna_prop_validity_check(BPy_PropertyRNA *self); extern PyMethodDef meth_bpy_register_class; extern PyMethodDef meth_bpy_unregister_class; +/* bpy.utils._bl_owner_(get/set) */ +extern PyMethodDef meth_bpy_owner_id_set; +extern PyMethodDef meth_bpy_owner_id_get; + #endif diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 73809e96560..2727b81e1cf 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "DNA_scene_types.h" #include "DNA_anim_types.h" @@ -61,9 +62,9 @@ #include "../generic/python_utildefines.h" /* for keyframes and drivers */ -static int pyrna_struct_anim_args_parse( +static int pyrna_struct_anim_args_parse_ex( PointerRNA *ptr, const char *error_prefix, const char *path, - const char **path_full, int *index) + const char **r_path_full, int *r_index, bool *r_path_no_validate) { const bool is_idbase = RNA_struct_is_ID(ptr->type); PropertyRNA *prop; @@ -78,11 +79,11 @@ static int pyrna_struct_anim_args_parse( /* full paths can only be given from ID base */ if (is_idbase) { - int r_index = -1; - if (RNA_path_resolve_property_full(ptr, path, &r_ptr, &prop, &r_index) == false) { + int path_index = -1; + if (RNA_path_resolve_property_full(ptr, path, &r_ptr, &prop, &path_index) == false) { prop = NULL; } - else if (r_index != -1) { + else if (path_index != -1) { PyErr_Format(PyExc_ValueError, "%.200s path includes index, must be a separate argument", error_prefix, path); @@ -101,86 +102,167 @@ static int pyrna_struct_anim_args_parse( } if (prop == NULL) { + if (r_path_no_validate) { + *r_path_no_validate = true; + return -1; + } PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not found", error_prefix, path); return -1; } - if (!RNA_property_animateable(&r_ptr, prop)) { - PyErr_Format(PyExc_TypeError, - "%.200s property \"%s\" not animatable", - error_prefix, path); - return -1; + if (r_path_no_validate) { + /* Don't touch the index. */ } + else { + if (!RNA_property_animateable(&r_ptr, prop)) { + PyErr_Format(PyExc_TypeError, + "%.200s property \"%s\" not animatable", + error_prefix, path); + return -1; + } - if (RNA_property_array_check(prop) == 0) { - if ((*index) == -1) { - *index = 0; + if (RNA_property_array_check(prop) == 0) { + if ((*r_index) == -1) { + *r_index = 0; + } + else { + PyErr_Format(PyExc_TypeError, + "%.200s index %d was given while property \"%s\" is not an array", + error_prefix, *r_index, path); + return -1; + } } else { - PyErr_Format(PyExc_TypeError, - "%.200s index %d was given while property \"%s\" is not an array", - error_prefix, *index, path); - return -1; + int array_len = RNA_property_array_length(&r_ptr, prop); + if ((*r_index) < -1 || (*r_index) >= array_len) { + PyErr_Format(PyExc_TypeError, + "%.200s index out of range \"%s\", given %d, array length is %d", + error_prefix, path, *r_index, array_len); + return -1; + } } } + + if (is_idbase) { + *r_path_full = BLI_strdup(path); + } else { - int array_len = RNA_property_array_length(&r_ptr, prop); - if ((*index) < -1 || (*index) >= array_len) { + *r_path_full = RNA_path_from_ID_to_property(&r_ptr, prop); + + if (*r_path_full == NULL) { PyErr_Format(PyExc_TypeError, - "%.200s index out of range \"%s\", given %d, array length is %d", - error_prefix, path, *index, array_len); + "%.200s could not make path to \"%s\"", + error_prefix, path); return -1; } } + return 0; +} + +static int pyrna_struct_anim_args_parse( + PointerRNA *ptr, const char *error_prefix, const char *path, + const char **r_path_full, int *r_index) +{ + return pyrna_struct_anim_args_parse_ex(ptr, error_prefix, path, r_path_full, r_index, NULL); +} + +/** + * Unlike #pyrna_struct_anim_args_parse \a r_path_full may be copied from \a path. + */ +static int pyrna_struct_anim_args_parse_no_resolve( + PointerRNA *ptr, const char *error_prefix, const char *path, + const char **r_path_full) +{ + const bool is_idbase = RNA_struct_is_ID(ptr->type); if (is_idbase) { - *path_full = BLI_strdup(path); + *r_path_full = path; + return 0; } else { - *path_full = RNA_path_from_ID_to_property(&r_ptr, prop); - - if (*path_full == NULL) { + char *path_prefix = RNA_path_from_ID_to_struct(ptr); + if (path_prefix == NULL) { PyErr_Format(PyExc_TypeError, - "%.200s could not make path to \"%s\"", - error_prefix, path); + "%.200s could not make path for type %s", + error_prefix, RNA_struct_identifier(ptr->type)); return -1; } + + if (*path == '[') { + *r_path_full = BLI_string_joinN(path_prefix, path); + } + else { + *r_path_full = BLI_string_join_by_sep_charN('.', path_prefix, path); + } + MEM_freeN(path_prefix); } + return 0; +} +static int pyrna_struct_anim_args_parse_no_resolve_fallback( + PointerRNA *ptr, const char *error_prefix, const char *path, + const char **r_path_full, int *r_index) +{ + bool path_unresolved = false; + if (pyrna_struct_anim_args_parse_ex( + ptr, error_prefix, path, + r_path_full, r_index, &path_unresolved) == -1) + { + if (path_unresolved == true) { + if (pyrna_struct_anim_args_parse_no_resolve( + ptr, error_prefix, path, r_path_full) == -1) + { + return -1; + } + } + else { + return -1; + } + } return 0; } /* internal use for insert and delete */ static int pyrna_struct_keyframe_parse( PointerRNA *ptr, PyObject *args, PyObject *kw, const char *parse_str, const char *error_prefix, - const char **path_full, int *index, float *cfra, const char **group_name, int *options) /* return values */ + /* return values */ + const char **r_path_full, int *r_index, float *r_cfra, const char **r_group_name, int *r_options) { static const char *kwlist[] = {"data_path", "index", "frame", "group", "options", NULL}; PyObject *pyoptions = NULL; const char *path; /* note, parse_str MUST start with 's|ifsO!' */ - if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name, - &PySet_Type, &pyoptions)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, parse_str, (char **)kwlist, &path, r_index, r_cfra, r_group_name, + &PySet_Type, &pyoptions)) { return -1; } - if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, path_full, index) == -1) + if (pyrna_struct_anim_args_parse( + ptr, error_prefix, path, + r_path_full, r_index) == -1) + { return -1; + } - if (*cfra == FLT_MAX) - *cfra = CTX_data_scene(BPy_GetContext())->r.cfra; + if (*r_cfra == FLT_MAX) { + *r_cfra = CTX_data_scene(BPy_GetContext())->r.cfra; + } /* flag may be null (no option currently for remove keyframes e.g.). */ - if (options) { - if (pyoptions && (pyrna_set_to_enum_bitfield(rna_enum_keying_flag_items, pyoptions, options, error_prefix) == -1)) { + if (r_options) { + if (pyoptions && + (pyrna_set_to_enum_bitfield( + rna_enum_keying_flag_items, pyoptions, r_options, error_prefix) == -1)) + { return -1; } - *options |= INSERTKEY_NO_USERPREF; + *r_options |= INSERTKEY_NO_USERPREF; } return 0; /* success */ @@ -222,9 +304,10 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb PYRNA_STRUCT_CHECK_OBJ(self); - if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, - "s|ifsO!:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", - &path_full, &index, &cfra, &group_name, &options) == -1) + if (pyrna_struct_keyframe_parse( + &self->ptr, args, kw, + "s|ifsO!:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", + &path_full, &index, &cfra, &group_name, &options) == -1) { return NULL; } @@ -233,6 +316,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb * strips themselves. These are stored separately or else the properties will * not have any effect. */ + struct Depsgraph *depsgraph = CTX_data_depsgraph(BPy_GetContext()); ReportList reports; short result = 0; @@ -254,7 +338,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, options); + result = insert_keyframe_direct(depsgraph, &reports, ptr, prop, fcu, cfra, keytype, NULL, options); } else { BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full); @@ -268,13 +352,14 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb } else { ID *id = self->ptr.id.data; + struct Depsgraph *depsgraph = CTX_data_depsgraph(BPy_GetContext()); ReportList reports; short result; BKE_reports_init(&reports, RPT_STORE); - BLI_assert(BKE_id_is_in_gobal_main(id)); - result = insert_keyframe(G_MAIN, &reports, id, NULL, group_name, path_full, index, cfra, keytype, options); + BLI_assert(BKE_id_is_in_global_main(id)); + result = insert_keyframe(G_MAIN, depsgraph, &reports, id, NULL, group_name, path_full, index, cfra, keytype, NULL, options); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) @@ -384,7 +469,7 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb BKE_reports_init(&reports, RPT_STORE); - result = delete_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0); + result = delete_keyframe(G.main, &reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0); MEM_freeN((void *)path_full); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) @@ -417,7 +502,10 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index)) return NULL; - if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) == -1) { + if (pyrna_struct_anim_args_parse( + &self->ptr, "bpy_struct.driver_add():", path, + &path_full, &index) == -1) + { return NULL; } else { @@ -488,10 +576,14 @@ PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args) PYRNA_STRUCT_CHECK_OBJ(self); - if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) + if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) { return NULL; + } - if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) == -1) { + if (pyrna_struct_anim_args_parse_no_resolve_fallback( + &self->ptr, "bpy_struct.driver_remove():", path, + &path_full, &index) == -1) + { return NULL; } else { @@ -502,7 +594,9 @@ PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args) result = ANIM_remove_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0); - MEM_freeN((void *)path_full); + if (path != path_full) { + MEM_freeN((void *)path_full); + } if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) return NULL; diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index fbdcc03ddd0..ed29aa795e6 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -33,6 +33,7 @@ #include "RNA_types.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "bpy_rna.h" #include "bpy_rna_callback.h" @@ -47,8 +48,12 @@ #include "BKE_context.h" #include "BKE_screen.h" +#include "WM_api.h" + #include "ED_space_api.h" +#include "../generic/python_utildefines.h" + /* use this to stop other capsules from being mis-used */ #define RNA_CAPSULE_ID "RNA_HANDLE" #define RNA_CAPSULE_ID_INVALID "RNA_HANDLE_REMOVED" @@ -82,6 +87,53 @@ static void cb_region_draw(const bContext *C, ARegion *UNUSED(ar), void *customd bpy_context_clear((bContext *)C, &gilstate); } +/* We could make generic utility */ +static PyObject *PyC_Tuple_CopySized(PyObject *src, int len_dst) +{ + PyObject *dst = PyTuple_New(len_dst); + int len_src = PyTuple_GET_SIZE(src); + BLI_assert(len_src <= len_dst); + for (int i = 0; i < len_src; i++) { + PyObject *item = PyTuple_GET_ITEM(src, i); + PyTuple_SET_ITEM(dst, i, item); + Py_INCREF(item); + } + return dst; +} + +static void cb_wm_cursor_draw(bContext *C, int x, int y, void *customdata) +{ + PyObject *cb_func, *cb_args, *result; + PyGILState_STATE gilstate; + + bpy_context_set((bContext *)C, &gilstate); + + cb_func = PyTuple_GET_ITEM((PyObject *)customdata, 1); + cb_args = PyTuple_GET_ITEM((PyObject *)customdata, 2); + + const int cb_args_len = PyTuple_GET_SIZE(cb_args); + + PyObject *cb_args_xy = PyTuple_New(2); + PyTuple_SET_ITEMS(cb_args_xy, PyLong_FromLong(x), PyLong_FromLong(y)); + + PyObject *cb_args_with_xy = PyC_Tuple_CopySized(cb_args, cb_args_len + 1); + PyTuple_SET_ITEM(cb_args_with_xy, cb_args_len, cb_args_xy); + + result = PyObject_CallObject(cb_func, cb_args_with_xy); + + Py_DECREF(cb_args_with_xy); + + if (result) { + Py_DECREF(result); + } + else { + PyErr_Print(); + PyErr_Clear(); + } + + bpy_context_clear((bContext *)C, &gilstate); +} + #if 0 PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args) { @@ -171,11 +223,9 @@ static eSpace_Type rna_Space_refine_reverse(StructRNA *srna) if (srna == &RNA_SpaceTextEditor) return SPACE_TEXT; if (srna == &RNA_SpaceDopeSheetEditor) return SPACE_ACTION; if (srna == &RNA_SpaceNLA) return SPACE_NLA; - if (srna == &RNA_SpaceTimeline) return SPACE_TIME; if (srna == &RNA_SpaceNodeEditor) return SPACE_NODE; - if (srna == &RNA_SpaceLogicEditor) return SPACE_LOGIC; if (srna == &RNA_SpaceConsole) return SPACE_CONSOLE; - if (srna == &RNA_SpaceUserPreferences) return SPACE_USERPREF; + if (srna == &RNA_SpacePreferences) return SPACE_USERPREF; if (srna == &RNA_SpaceClipEditor) return SPACE_CLIP; return SPACE_EMPTY; } @@ -185,10 +235,6 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) void *handle; PyObject *cls; PyObject *cb_func, *cb_args; - const char *cb_regiontype_str; - const char *cb_event_str; - int cb_event; - int cb_regiontype; StructRNA *srna; if (PyTuple_GET_SIZE(args) < 2) { @@ -207,23 +253,78 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) } /* class specific callbacks */ - if (RNA_struct_is_a(srna, &RNA_Space)) { - if (!PyArg_ParseTuple(args, "OOO!ss:Space.draw_handler_add", - &cls, &cb_func, /* already assigned, no matter */ - &PyTuple_Type, &cb_args, &cb_regiontype_str, &cb_event_str)) + + if (srna == &RNA_WindowManager) { + const char *error_prefix = "WindowManager.draw_cursor_add"; + struct { + const char *space_type_str; + const char *region_type_str; + + int space_type; + int region_type; + } params = { + .space_type_str = NULL, + .region_type_str = NULL, + .space_type = SPACE_TYPE_ANY, + .region_type = RGN_TYPE_ANY, + }; + + if (!PyArg_ParseTuple( + args, "OOO!|ss:WindowManager.draw_cursor_add", + &cls, &cb_func, /* already assigned, no matter */ + &PyTuple_Type, &cb_args, ¶ms.space_type_str, ¶ms.region_type_str)) + { + return NULL; + } + + if (params.space_type_str && pyrna_enum_value_from_id( + rna_enum_space_type_items, params.space_type_str, + ¶ms.space_type, error_prefix) == -1) + { + return NULL; + } + else if (params.region_type_str && pyrna_enum_value_from_id( + rna_enum_region_type_items, params.region_type_str, + ¶ms.region_type, error_prefix) == -1) + { + return NULL; + } + + bContext *C = BPy_GetContext(); + struct wmWindowManager *wm = CTX_wm_manager(C); + handle = WM_paint_cursor_activate( + wm, + params.space_type, params.region_type, + NULL, cb_wm_cursor_draw, (void *)args); + } + else if (RNA_struct_is_a(srna, &RNA_Space)) { + const char *error_prefix = "Space.draw_handler_add"; + struct { + const char *region_type_str; + const char *event_str; + + int region_type; + int event; + } params; + + if (!PyArg_ParseTuple( + args, "OOO!ss:Space.draw_handler_add", + &cls, &cb_func, /* already assigned, no matter */ + &PyTuple_Type, &cb_args, + ¶ms.region_type_str, ¶ms.event_str)) { return NULL; } if (pyrna_enum_value_from_id( - region_draw_mode_items, cb_event_str, - &cb_event, "bpy_struct.callback_add()") == -1) + region_draw_mode_items, params.event_str, + ¶ms.event, error_prefix) == -1) { return NULL; } else if (pyrna_enum_value_from_id( - rna_enum_region_type_items, cb_regiontype_str, - &cb_regiontype, "bpy_struct.callback_add()") == -1) + rna_enum_region_type_items, params.region_type_str, + ¶ms.region_type, error_prefix) == -1) { return NULL; } @@ -235,13 +336,12 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) } else { SpaceType *st = BKE_spacetype_from_id(spaceid); - ARegionType *art = BKE_regiontype_from_id(st, cb_regiontype); + ARegionType *art = BKE_regiontype_from_id(st, params.region_type); if (art == NULL) { - PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", cb_regiontype_str); + PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", params.region_type_str); return NULL; } - handle = ED_region_draw_cb_activate(art, cb_region_draw, (void *)args, cb_event); - Py_INCREF(args); + handle = ED_region_draw_cb_activate(art, cb_region_draw, (void *)args, params.event); } } } @@ -250,7 +350,14 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args) return NULL; } - return PyCapsule_New((void *)handle, RNA_CAPSULE_ID, NULL); + PyObject *ret = PyCapsule_New((void *)handle, RNA_CAPSULE_ID, NULL); + + /* Store 'args' in context as well as the handler custom-data, + * because the handle may be freed by Blender (new file, new window... etc) */ + PyCapsule_SetContext(ret, args); + Py_INCREF(args); + + return ret; } PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *args) @@ -258,10 +365,8 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar PyObject *cls; PyObject *py_handle; void *handle; - void *customdata; StructRNA *srna; - const char *cb_regiontype_str; - int cb_regiontype; + bool capsule_clear = false; if (PyTuple_GET_SIZE(args) < 2) { PyErr_SetString(PyExc_ValueError, "callback_remove(handler): expected at least 2 args"); @@ -278,21 +383,39 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar PyErr_SetString(PyExc_ValueError, "callback_remove(handler): NULL handler given, invalid or already removed"); return NULL; } + PyObject *handle_args = PyCapsule_GetContext(py_handle); - if (RNA_struct_is_a(srna, &RNA_Space)) { - if (!PyArg_ParseTuple(args, "OO!s:Space.draw_handler_remove", - &cls, &PyCapsule_Type, &py_handle, /* already assigned, no matter */ - &cb_regiontype_str)) + if (srna == &RNA_WindowManager) { + if (!PyArg_ParseTuple( + args, "OO!:WindowManager.draw_cursor_remove", + &cls, &PyCapsule_Type, &py_handle)) + { + return NULL; + } + bContext *C = BPy_GetContext(); + struct wmWindowManager *wm = CTX_wm_manager(C); + WM_paint_cursor_end(wm, handle); + capsule_clear = true; + } + else if (RNA_struct_is_a(srna, &RNA_Space)) { + const char *error_prefix = "Space.draw_handler_remove"; + struct { + const char *region_type_str; + + int region_type; + } params; + + if (!PyArg_ParseTuple( + args, "OO!s:Space.draw_handler_remove", + &cls, &PyCapsule_Type, &py_handle, /* already assigned, no matter */ + ¶ms.region_type_str)) { return NULL; } - - customdata = ED_region_draw_cb_customdata(handle); - Py_DECREF((PyObject *)customdata); if (pyrna_enum_value_from_id( - rna_enum_region_type_items, cb_regiontype_str, - &cb_regiontype, "bpy_struct.callback_remove()") == -1) + rna_enum_region_type_items, params.region_type_str, + ¶ms.region_type, error_prefix) == -1) { return NULL; } @@ -304,12 +427,13 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar } else { SpaceType *st = BKE_spacetype_from_id(spaceid); - ARegionType *art = BKE_regiontype_from_id(st, cb_regiontype); + ARegionType *art = BKE_regiontype_from_id(st, params.region_type); if (art == NULL) { - PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", cb_regiontype_str); + PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", params.region_type_str); return NULL; } ED_region_draw_cb_exit(art, handle); + capsule_clear = true; } } } @@ -319,7 +443,10 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar } /* don't allow reuse */ - PyCapsule_SetName(py_handle, RNA_CAPSULE_ID_INVALID); + if (capsule_clear) { + Py_DECREF(handle_args); + PyCapsule_SetName(py_handle, RNA_CAPSULE_ID_INVALID); + } Py_RETURN_NONE; } diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c new file mode 100644 index 00000000000..8189431dfc9 --- /dev/null +++ b/source/blender/python/intern/bpy_rna_gizmo.c @@ -0,0 +1,564 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_rna_gizmo.c + * \ingroup pythonintern + * + * . + */ + +#include <Python.h> +#include <stddef.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_alloca.h" + +#include "BKE_main.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "bpy_capi_utils.h" +#include "bpy_rna_gizmo.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "RNA_access.h" +#include "RNA_types.h" +#include "RNA_enum_types.h" + +#include "bpy_rna.h" + + +/* -------------------------------------------------------------------- */ +/** \name Gizmo Target Property Define API + * \{ */ + +enum { + BPY_GIZMO_FN_SLOT_GET = 0, + BPY_GIZMO_FN_SLOT_SET, + BPY_GIZMO_FN_SLOT_RANGE_GET, +}; +#define BPY_GIZMO_FN_SLOT_LEN (BPY_GIZMO_FN_SLOT_RANGE_GET + 1) + +struct BPyGizmoHandlerUserData { + + PyObject *fn_slots[BPY_GIZMO_FN_SLOT_LEN]; +}; + +static void py_rna_gizmo_handler_get_cb( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + void *value_p) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + + struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; + PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_GET], NULL); + if (ret == NULL) { + goto fail; + } + + if (gz_prop->type->data_type == PROP_FLOAT) { + float *value = value_p; + if (gz_prop->type->array_length == 1) { + if ((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) { + goto fail; + } + } + else { + if (PyC_AsArray(value, ret, gz_prop->type->array_length, &PyFloat_Type, false, + "Gizmo get callback: ") == -1) + { + goto fail; + } + } + } + else { + PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type"); + goto fail; + } + + Py_DECREF(ret); + + PyGILState_Release(gilstate); + return; + +fail: + PyErr_Print(); + PyErr_Clear(); + + PyGILState_Release(gilstate); +} + +static void py_rna_gizmo_handler_set_cb( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + const void *value_p) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + + struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; + + PyObject *args = PyTuple_New(1); + + if (gz_prop->type->data_type == PROP_FLOAT) { + const float *value = value_p; + PyObject *py_value; + if (gz_prop->type->array_length == 1) { + py_value = PyFloat_FromDouble(*value); + } + else { + py_value = PyC_Tuple_PackArray_F32(value, gz_prop->type->array_length); + } + if (py_value == NULL) { + goto fail; + } + PyTuple_SET_ITEM(args, 0, py_value); + } + else { + PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type"); + goto fail; + } + + PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_SET], args); + if (ret == NULL) { + goto fail; + } + Py_DECREF(ret); + + PyGILState_Release(gilstate); + return; + +fail: + PyErr_Print(); + PyErr_Clear(); + + Py_DECREF(args); + + PyGILState_Release(gilstate); +} + +static void py_rna_gizmo_handler_range_get_cb( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + void *value_p) +{ + struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; + + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET], NULL); + if (ret == NULL) { + goto fail; + } + + if (!PyTuple_Check(ret)) { + PyErr_Format(PyExc_TypeError, + "Expected a tuple, not %.200s", + Py_TYPE(ret)->tp_name); + goto fail; + } + + if (PyTuple_GET_SIZE(ret) != 2) { + PyErr_Format(PyExc_TypeError, + "Expected a tuple of size 2, not %d", + PyTuple_GET_SIZE(ret)); + goto fail; + } + + if (gz_prop->type->data_type == PROP_FLOAT) { + float range[2]; + for (int i = 0; i < 2; i++) { + if (((range[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(ret, i))) == -1.0f && PyErr_Occurred()) == 0) { + /* pass */ + } + else { + goto fail; + } + } + memcpy(value_p, range, sizeof(range)); + } + else { + PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type"); + goto fail; + } + + Py_DECREF(ret); + PyGILState_Release(gilstate); + return; + +fail: + Py_XDECREF(ret); + + PyErr_Print(); + PyErr_Clear(); + + PyGILState_Release(gilstate); +} + +static void py_rna_gizmo_handler_free_cb( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop) +{ + struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; + + PyGILState_STATE gilstate = PyGILState_Ensure(); + for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) { + Py_XDECREF(data->fn_slots[i]); + } + PyGILState_Release(gilstate); + + MEM_freeN(data); + +} + +PyDoc_STRVAR(bpy_gizmo_target_set_handler_doc, +".. method:: target_set_handler(target, get, set, range=None):\n" +"\n" +" Assigns callbacks to a gizmos property.\n" +"\n" +" :arg get: Function that returns the value for this property (single value or sequence).\n" +" :type get: callable\n" +" :arg set: Function that takes a single value argument and applies it.\n" +" :type set: callable\n" +" :arg range: Function that returns a (min, max) tuple for gizmos that use a range.\n" +" :type range: callable\n" +); +static PyObject *bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + + struct { + PyObject *self; + char *target; + PyObject *py_fn_slots[BPY_GIZMO_FN_SLOT_LEN]; + } params = { + .self = NULL, + .target = NULL, + .py_fn_slots = {NULL}, + }; + + /* Note: this is a counter-part to functions: + * 'Gizmo.target_set_prop & target_set_operator' + * (see: rna_wm_gizmo_api.c). conventions should match. */ + static const char * const _keywords[] = {"self", "target", "get", "set", "range", NULL}; + static _PyArg_Parser _parser = {"Os|$OOO:target_set_handler", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + ¶ms.self, + ¶ms.target, + ¶ms.py_fn_slots[BPY_GIZMO_FN_SLOT_GET], + ¶ms.py_fn_slots[BPY_GIZMO_FN_SLOT_SET], + ¶ms.py_fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET])) + { + goto fail; + } + + wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data; + + const wmGizmoPropertyType *gz_prop_type = + WM_gizmotype_target_property_find(gz->type, params.target); + if (gz_prop_type == NULL) { + PyErr_Format(PyExc_ValueError, + "Gizmo target property '%s.%s' not found", + gz->type->idname, params.target); + goto fail; + } + + { + const int slots_required = 2; + const int slots_start = 2; + for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) { + if (params.py_fn_slots[i] == NULL) { + if (i < slots_required) { + PyErr_Format(PyExc_ValueError, "Argument '%s' not given", _keywords[slots_start + i]); + goto fail; + } + } + else if (!PyCallable_Check(params.py_fn_slots[i])) { + PyErr_Format(PyExc_ValueError, "Argument '%s' not callable", _keywords[slots_start + i]); + goto fail; + } + } + } + + struct BPyGizmoHandlerUserData *data = MEM_callocN(sizeof(*data), __func__); + + for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) { + data->fn_slots[i] = params.py_fn_slots[i]; + Py_XINCREF(params.py_fn_slots[i]); + } + + WM_gizmo_target_property_def_func_ptr( + gz, gz_prop_type, + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = py_rna_gizmo_handler_get_cb, + .value_set_fn = py_rna_gizmo_handler_set_cb, + .range_get_fn = py_rna_gizmo_handler_range_get_cb, + .free_fn = py_rna_gizmo_handler_free_cb, + .user_data = data, + }); + + PyGILState_Release(gilstate); + + Py_RETURN_NONE; + +fail: + PyGILState_Release(gilstate); + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Gizmo Target Property Access API + * \{ */ + +PyDoc_STRVAR(bpy_gizmo_target_get_value_doc, +".. method:: target_get_value(target):\n" +"\n" +" Get the value of this target property.\n" +"\n" +" :arg target: Target property name.\n" +" :type target: string\n" +" :return: The value of the target property.\n" +" :rtype: Single value or array based on the target type\n" +); +static PyObject *bpy_gizmo_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + struct { + PyObject *self; + char *target; + } params = { + .self = NULL, + .target = NULL, + }; + + static const char * const _keywords[] = {"self", "target", NULL}; + static _PyArg_Parser _parser = {"Os:target_get_value", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + ¶ms.self, + ¶ms.target)) + { + goto fail; + } + + wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data; + + wmGizmoProperty *gz_prop = + WM_gizmo_target_property_find(gz, params.target); + if (gz_prop == NULL) { + PyErr_Format(PyExc_ValueError, + "Gizmo target property '%s.%s' not found", + gz->type->idname, params.target); + goto fail; + } + + const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop); + switch (gz_prop->type->data_type) { + case PROP_FLOAT: + { + if (array_len != 0) { + float *value = BLI_array_alloca(value, array_len); + WM_gizmo_target_property_float_get_array(gz, gz_prop, value); + return PyC_Tuple_PackArray_F32(value, array_len); + } + else { + float value = WM_gizmo_target_property_float_get(gz, gz_prop); + return PyFloat_FromDouble(value); + } + break; + } + default: + { + PyErr_SetString(PyExc_RuntimeError, "Not yet supported type"); + goto fail; + } + } + +fail: + return NULL; +} + +PyDoc_STRVAR(bpy_gizmo_target_set_value_doc, +".. method:: target_set_value(target):\n" +"\n" +" Set the value of this target property.\n" +"\n" +" :arg target: Target property name.\n" +" :type target: string\n" +); +static PyObject *bpy_gizmo_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + struct { + PyObject *self; + char *target; + PyObject *value; + } params = { + .self = NULL, + .target = NULL, + .value = NULL, + }; + + static const char * const _keywords[] = {"self", "target", "value", NULL}; + static _PyArg_Parser _parser = {"OsO:target_set_value", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + ¶ms.self, + ¶ms.target, + ¶ms.value)) + { + goto fail; + } + + wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data; + + wmGizmoProperty *gz_prop = + WM_gizmo_target_property_find(gz, params.target); + if (gz_prop == NULL) { + PyErr_Format(PyExc_ValueError, + "Gizmo target property '%s.%s' not found", + gz->type->idname, params.target); + goto fail; + } + + const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop); + switch (gz_prop->type->data_type) { + case PROP_FLOAT: + { + if (array_len != 0) { + float *value = BLI_array_alloca(value, array_len); + if (PyC_AsArray(value, params.value, gz_prop->type->array_length, &PyFloat_Type, false, + "Gizmo target property array") == -1) + { + goto fail; + } + WM_gizmo_target_property_float_set_array(BPy_GetContext(), gz, gz_prop, value); + } + else { + float value; + if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) { + goto fail; + } + WM_gizmo_target_property_float_set(BPy_GetContext(), gz, gz_prop, value); + } + Py_RETURN_NONE; + } + default: + { + PyErr_SetString(PyExc_RuntimeError, "Not yet supported type"); + goto fail; + } + } + +fail: + return NULL; +} + + +PyDoc_STRVAR(bpy_gizmo_target_get_range_doc, +".. method:: target_get_range(target):\n" +"\n" +" Get the range for this target property.\n" +"\n" +" :arg target: Target property name.\n" +" :return: The range of this property (min, max).\n" +" :rtype: tuple pair.\n" +); +static PyObject *bpy_gizmo_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + struct { + PyObject *self; + char *target; + } params = { + .self = NULL, + .target = NULL, + }; + + static const char * const _keywords[] = {"self", "target", NULL}; + static _PyArg_Parser _parser = {"Os:target_get_range", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + ¶ms.self, + ¶ms.target)) + { + goto fail; + } + + wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data; + + wmGizmoProperty *gz_prop = + WM_gizmo_target_property_find(gz, params.target); + if (gz_prop == NULL) { + PyErr_Format(PyExc_ValueError, + "Gizmo target property '%s.%s' not found", + gz->type->idname, params.target); + goto fail; + } + + switch (gz_prop->type->data_type) { + case PROP_FLOAT: + { + float range[2]; + WM_gizmo_target_property_float_range_get(gz, gz_prop, range); + return PyC_Tuple_PackArray_F32(range, 2); + } + default: + { + PyErr_SetString(PyExc_RuntimeError, "Not yet supported type"); + goto fail; + } + } + +fail: + return NULL; +} + +/** \} */ + +int BPY_rna_gizmo_module(PyObject *mod_par) +{ + static PyMethodDef method_def_array[] = { + /* Gizmo Target Property Define API */ + {"target_set_handler", (PyCFunction)bpy_gizmo_target_set_handler, + METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_set_handler_doc}, + /* Gizmo Target Property Access API */ + {"target_get_value", (PyCFunction)bpy_gizmo_target_get_value, + METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_get_value_doc}, + {"target_set_value", (PyCFunction)bpy_gizmo_target_set_value, + METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_set_value_doc}, + {"target_get_range", (PyCFunction)bpy_gizmo_target_get_range, + METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_get_range_doc}, + /* no sentinel needed. */ + }; + + for (int i = 0; i < ARRAY_SIZE(method_def_array); i++) { + PyMethodDef *m = &method_def_array[i]; + PyObject *func = PyCFunction_New(m, NULL); + PyObject *func_inst = PyInstanceMethod_New(func); + char name_prefix[128]; + PyOS_snprintf(name_prefix, sizeof(name_prefix), "_rna_gizmo_%s", m->ml_name); + /* TODO, return a type that binds nearly to a method. */ + PyModule_AddObject(mod_par, name_prefix, func_inst); + } + + return 0; +} diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/intern/bpy_rna_gizmo.h index 0da44a4eb87..68d8c1e052a 100644 --- a/source/blender/python/intern/gpu.h +++ b/source/blender/python/intern/bpy_rna_gizmo.h @@ -15,27 +15,18 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2005 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Benoit Bolsee. + * Contributor(s): Bastien Montagne * * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/python/intern/gpu.h +/** \file blender/python/intern/bpy_rna_gizmo.h * \ingroup pythonintern - * - * Initializes the gpu Python module. */ -#ifndef __GPU_H__ -#define __GPU_H__ - -PyObject *GPU_initPython(void); +#ifndef __BPY_RNA_GIZMO_H__ +#define __BPY_RNA_GIZMO_H__ -PyObject *BPyInit_gpu_offscreen(void); +int BPY_rna_gizmo_module(PyObject *); -#endif /* __GPU_H__ */ +#endif /* __BPY_RNA_GIZMO_H__ */ diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 4806c2266ba..3fc12d4cc54 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -35,9 +35,9 @@ #include "BLI_bitmap.h" #include "BKE_global.h" -#include "BKE_main.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_main.h" #include "DNA_ID.h" /* Those folowing are only to support hack of not listing some internal 'backward' pointers in generated user_map... */ @@ -97,11 +97,11 @@ static int foreach_libblock_id_user_map_callback( } if ((GS(self_id->name) == ID_OB) && (id_p == (ID **)&((Object *)self_id)->proxy_from)) { - /* We skip proxy_from here, since it some internal pointer which is not irrelevant info for py/API level. */ + /* We skip proxy_from here, since it's some internal pointer which is not relevant info for py/API level. */ return IDWALK_RET_NOP; } else if ((GS(self_id->name) == ID_KE) && (id_p == (ID **)&((Key *)self_id)->from)) { - /* We skip from here, since it some internal pointer which is not irrelevant info for py/API level. */ + /* We skip from here, since it's some internal pointer which is not relevant info for py/API level. */ return IDWALK_RET_NOP; } @@ -290,6 +290,79 @@ error: } +PyDoc_STRVAR(bpy_batch_remove_doc, +".. method:: batch_remove(ids=(id1, id2, ...))\n" +"\n" +" Remove (delete) several IDs at once.\n" +"\n" +" WARNING: Considered experimental feature currently.\n" +"\n" +" Note that this function is quicker than individual calls to :func:`remove()` (from :class:`bpy.types.BlendData`\n" +" ID collections), but less safe/versatile (it can break Blender, e.g. by removing all scenes...).\n" +"\n" +" :arg ids: Iterables of IDs (types can be mixed).\n" +" :type subset: sequence\n" +); +static PyObject *bpy_batch_remove(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +{ +#if 0 /* If someone knows how to get a proper 'self' in that case... */ + BPy_StructRNA *pyrna = (BPy_StructRNA *)self; + Main *bmain = pyrna->ptr.data; +#else + Main *bmain = G_MAIN; /* XXX Ugly, but should work! */ +#endif + + PyObject *ids = NULL; + + PyObject *ret = NULL; + + static const char *_keywords[] = {"ids", NULL}; + static _PyArg_Parser _parser = {"O:user_map", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, + &ids)) + { + return ret; + } + + if (ids) { + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + PyObject *ids_fast = PySequence_Fast(ids, "batch_remove"); + if (ids_fast == NULL) { + goto error; + } + + PyObject **ids_array = PySequence_Fast_ITEMS(ids_fast); + Py_ssize_t ids_len = PySequence_Fast_GET_SIZE(ids_fast); + + for (; ids_len; ids_array++, ids_len--) { + ID *id; + if (!pyrna_id_FromPyObject(*ids_array, &id)) { + PyErr_Format(PyExc_TypeError, + "Expected an ID type, not %.200s", + Py_TYPE(*ids_array)->tp_name); + Py_DECREF(ids_fast); + goto error; + } + + id->tag |= LIB_TAG_DOIT; + } + Py_DECREF(ids_fast); + + BKE_id_multi_tagged_delete(bmain); + } + else { + goto error; + } + + Py_INCREF(Py_None); + ret = Py_None; + +error: + return ret; +} + int BPY_rna_id_collection_module(PyObject *mod_par) { static PyMethodDef user_map = { @@ -297,5 +370,10 @@ int BPY_rna_id_collection_module(PyObject *mod_par) PyModule_AddObject(mod_par, "_rna_id_collection_user_map", PyCFunction_New(&user_map, NULL)); + static PyMethodDef batch_remove = { + "batch_remove", (PyCFunction)bpy_batch_remove, METH_VARARGS | METH_KEYWORDS, bpy_batch_remove_doc}; + + PyModule_AddObject(mod_par, "_rna_id_collection_batch_remove", PyCFunction_New(&batch_remove, NULL)); + return 0; } diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c index cbd8b67d1ce..1d1108e1af0 100644 --- a/source/blender/python/intern/bpy_utils_units.c +++ b/source/blender/python/intern/bpy_utils_units.c @@ -323,7 +323,6 @@ PyObject *BPY_utils_units(void) submodule = PyModule_Create(&bpyunits_module); PyDict_SetItemString(PyImport_GetModuleDict(), bpyunits_module.m_name, submodule); - Py_INCREF(submodule); /* Finalize our unit systems and types structseq definitions! */ diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c deleted file mode 100644 index d902b6838f4..00000000000 --- a/source/blender/python/intern/gpu.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2006 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Benoit Bolsee. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/python/intern/gpu.c - * \ingroup pythonintern - * - * This file defines the 'gpu' module, used to get GLSL shader code and data - * from blender materials. - */ - -#include <Python.h> - -#include "DNA_scene_types.h" -#include "DNA_material_types.h" -#include "DNA_ID.h" -#include "DNA_customdata_types.h" - -#include "BLI_listbase.h" -#include "BLI_utildefines.h" - -#include "RNA_access.h" - -#include "bpy_rna.h" - -#include "../generic/py_capi_utils.h" - -#include "GPU_material.h" - -#include "gpu.h" - -#define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, # name, name) - -PyDoc_STRVAR(M_gpu_doc, -"This module provides access to the GLSL shader and Offscreen rendering functionalities." -); -static struct PyModuleDef gpumodule = { - PyModuleDef_HEAD_INIT, - "gpu", /* name of module */ - M_gpu_doc, /* module documentation */ - -1, /* size of per-interpreter state of the module, - * or -1 if the module keeps state in global variables. */ - NULL, NULL, NULL, NULL, NULL -}; - -static PyObject *PyInit_gpu(void) -{ - PyObject *m; - - m = PyModule_Create(&gpumodule); - if (m == NULL) - return NULL; - - - /* Take care to update docs when editing: 'doc/python_api/rst/gpu.rst' */ - - - /* -------------------------------------------------------------------- */ - /* GPUDynamicType */ - - /* device constant groups */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MISC); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_LAMP); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_OBJECT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_SAMPLER); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MIST); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_WORLD); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MAT); - - /* device constants */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_NONE); - /* GPU_DYNAMIC_GROUP_OBJECT */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWMAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_MAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWIMAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_IMAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_COLOR); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE); - /* GPU_DYNAMIC_GROUP_LAMP */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNVEC); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCO); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNIMAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNPERSMAT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNENERGY); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCOL); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT1); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT2); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSCALE); - /* GPU_DYNAMIC_GROUP_SAMPLER */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DSHADOW); - /* GPU_DYNAMIC_GROUP_MIST */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_ENABLE); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_START); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_DISTANCE); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_INTENSITY); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_TYPE); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_COLOR); - /* GPU_DYNAMIC_GROUP_WORLD */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_ZENITH_COLOR); - /* GPU_DYNAMIC_GROUP_MAT */ - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPECRGB); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPEC); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_HARD); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_MIR); - - - /* -------------------------------------------------------------------- */ - /* GPUDataType */ - - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1I); - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1F); - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_2F); - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_3F); - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_4F); - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_9F); - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_16F); - PY_MODULE_ADD_CONSTANT(m, GPU_DATA_4UB); - - - /* -------------------------------------------------------------------- */ - /* CustomDataType - * - * Intentionally only include the subset used by the GPU API. - */ - PY_MODULE_ADD_CONSTANT(m, CD_MTFACE); - PY_MODULE_ADD_CONSTANT(m, CD_ORCO); - PY_MODULE_ADD_CONSTANT(m, CD_TANGENT); - PY_MODULE_ADD_CONSTANT(m, CD_MCOL); - return m; -} - -#define PY_DICT_ADD_STRING(d, s, f) \ - val = PyUnicode_FromString(s->f); \ - PyDict_SetItemString(d, # f, val); \ - Py_DECREF(val) - -#define PY_DICT_ADD_LONG(d, s, f) \ - val = PyLong_FromLong(s->f); \ - PyDict_SetItemString(d, # f, val); \ - Py_DECREF(val) - -#define PY_DICT_ADD_ID(d, s, f) \ - RNA_id_pointer_create((struct ID *)s->f, &tptr); \ - val = pyrna_struct_CreatePyObject(&tptr); \ - PyDict_SetItemString(d, # f, val); \ - Py_DECREF(val) - -#if 0 /* UNUSED */ -#define PY_OBJ_ADD_ID(d, s, f) \ - val = PyUnicode_FromString(&s->f->id.name[2]); \ - PyObject_SetAttrString(d, # f, val); \ - Py_DECREF(val) - -#define PY_OBJ_ADD_LONG(d, s, f) \ - val = PyLong_FromLong(s->f); \ - PyObject_SetAttrString(d, # f, val); \ - Py_DECREF(val) - -#define PY_OBJ_ADD_STRING(d, s, f) \ - val = PyUnicode_FromString(s->f); \ - PyObject_SetAttrString(d, # f, val); \ - Py_DECREF(val) -#endif - -PyDoc_STRVAR(GPU_export_shader_doc, -"export_shader(scene, material)\n" -"\n" -" Returns the GLSL shader that produces the visual effect of material in scene.\n" -"\n" -" :return: Dictionary defining the shader, uniforms and attributes.\n" -" :rtype: Dict" -); -static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kw) -{ - PyObject *pyscene; - PyObject *pymat; - PyObject *result; - PyObject *dict; - PyObject *val; - PyObject *seq; - - int i; - Scene *scene; - PointerRNA tptr; - Material *material; - GPUShaderExport *shader; - GPUInputUniform *uniform; - GPUInputAttribute *attribute; - - static const char *_keywords[] = {"scene", "material", NULL}; - static _PyArg_Parser _parser = {"OO:export_shader", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast( - args, kw, &_parser, - &pyscene, &pymat)) - { - return NULL; - } - scene = (Scene *)PyC_RNA_AsPointer(pyscene, "Scene"); - if (scene == NULL) { - return NULL; - } - - material = (Material *)PyC_RNA_AsPointer(pymat, "Material"); - if (material == NULL) { - return NULL; - } - - /* we can call our internal function at last: */ - shader = GPU_shader_export(scene, material); - if (!shader) { - PyErr_SetString(PyExc_RuntimeError, "cannot export shader"); - return NULL; - } - /* build a dictionary */ - result = PyDict_New(); - if (shader->fragment) { - PY_DICT_ADD_STRING(result, shader, fragment); - } - if (shader->vertex) { - PY_DICT_ADD_STRING(result, shader, vertex); - } - seq = PyList_New(BLI_listbase_count(&shader->uniforms)); - for (i = 0, uniform = shader->uniforms.first; uniform; uniform = uniform->next, i++) { - dict = PyDict_New(); - PY_DICT_ADD_STRING(dict, uniform, varname); - PY_DICT_ADD_LONG(dict, uniform, datatype); - PY_DICT_ADD_LONG(dict, uniform, type); - if (uniform->lamp) { - PY_DICT_ADD_ID(dict, uniform, lamp); - } - if (uniform->material) { - PY_DICT_ADD_ID(dict, uniform, material); - } - if (uniform->image) { - PY_DICT_ADD_ID(dict, uniform, image); - } - if (uniform->type == GPU_DYNAMIC_SAMPLER_2DBUFFER || - uniform->type == GPU_DYNAMIC_SAMPLER_2DIMAGE || - uniform->type == GPU_DYNAMIC_SAMPLER_2DSHADOW) - { - PY_DICT_ADD_LONG(dict, uniform, texnumber); - } - if (uniform->texpixels) { - val = PyByteArray_FromStringAndSize((const char *)uniform->texpixels, uniform->texsize * 4); - PyDict_SetItemString(dict, "texpixels", val); - Py_DECREF(val); - PY_DICT_ADD_LONG(dict, uniform, texsize); - } - PyList_SET_ITEM(seq, i, dict); - } - PyDict_SetItemString(result, "uniforms", seq); - Py_DECREF(seq); - - seq = PyList_New(BLI_listbase_count(&shader->attributes)); - for (i = 0, attribute = shader->attributes.first; attribute; attribute = attribute->next, i++) { - dict = PyDict_New(); - PY_DICT_ADD_STRING(dict, attribute, varname); - PY_DICT_ADD_LONG(dict, attribute, datatype); - PY_DICT_ADD_LONG(dict, attribute, type); - PY_DICT_ADD_LONG(dict, attribute, number); - if (attribute->name) { - if (attribute->name[0] != 0) { - PY_DICT_ADD_STRING(dict, attribute, name); - } - else { - val = PyLong_FromLong(0); - PyDict_SetItemString(dict, "name", val); - Py_DECREF(val); - } - } - PyList_SET_ITEM(seq, i, dict); - } - PyDict_SetItemString(result, "attributes", seq); - Py_DECREF(seq); - - GPU_free_shader_export(shader); - - return result; -} - -static PyMethodDef meth_export_shader[] = { - {"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc} -}; - -/* -------------------------------------------------------------------- */ -/* Initialize Module */ - -PyObject *GPU_initPython(void) -{ - PyObject *module; - PyObject *submodule; - PyObject *sys_modules = PyImport_GetModuleDict(); - - module = PyInit_gpu(); - - PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL)); - - /* gpu.offscreen */ - PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen())); - PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); - - PyDict_SetItem(sys_modules, PyModule_GetNameObject(module), module); - return module; -} diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c deleted file mode 100644 index 3b9b3c70ead..00000000000 --- a/source/blender/python/intern/gpu_offscreen.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright 2015, Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/python/intern/gpu_offscreen.c - * \ingroup pythonintern - * - * This file defines the offscreen functionalities of the 'gpu' module - * used for off-screen OpenGL rendering. - */ - -#include <Python.h> - -#include "MEM_guardedalloc.h" - -#include "BLI_utildefines.h" - -#include "WM_types.h" - -#include "BKE_global.h" -#include "BKE_library.h" - -#include "ED_screen.h" - -#include "GPU_compositing.h" -#include "GPU_framebuffer.h" - -#include "../mathutils/mathutils.h" - -#include "../generic/py_capi_utils.h" - -#include "gpu.h" - -#include "ED_view3d.h" - -/* -------------------------------------------------------------------- */ -/* GPU Offscreen PyObject */ - -typedef struct { - PyObject_HEAD - GPUOffScreen *ofs; -} BPy_GPUOffScreen; - -static int bpy_gpu_offscreen_valid_check(BPy_GPUOffScreen *py_gpu_ofs) -{ - if (UNLIKELY(py_gpu_ofs->ofs == NULL)) { - PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid"); - return -1; - } - return 0; -} - -#define BPY_GPU_OFFSCREEN_CHECK_OBJ(pygpu) { \ - if (UNLIKELY(bpy_gpu_offscreen_valid_check(pygpu) == -1)) { \ - return NULL; \ - } \ -} ((void)0) - -PyDoc_STRVAR(pygpu_offscreen_width_doc, "Texture width.\n\n:type: int"); -static PyObject *pygpu_offscreen_width_get(BPy_GPUOffScreen *self, void *UNUSED(type)) -{ - BPY_GPU_OFFSCREEN_CHECK_OBJ(self); - return PyLong_FromLong(GPU_offscreen_width(self->ofs)); -} - -PyDoc_STRVAR(pygpu_offscreen_height_doc, "Texture height.\n\n:type: int"); -static PyObject *pygpu_offscreen_height_get(BPy_GPUOffScreen *self, void *UNUSED(type)) -{ - BPY_GPU_OFFSCREEN_CHECK_OBJ(self); - return PyLong_FromLong(GPU_offscreen_height(self->ofs)); -} - -PyDoc_STRVAR(pygpu_offscreen_color_texture_doc, "Color texture.\n\n:type: int"); -static PyObject *pygpu_offscreen_color_texture_get(BPy_GPUOffScreen *self, void *UNUSED(type)) -{ - BPY_GPU_OFFSCREEN_CHECK_OBJ(self); - return PyLong_FromLong(GPU_offscreen_color_texture(self->ofs)); -} - -PyDoc_STRVAR(pygpu_offscreen_bind_doc, -"bind(save=True)\n" -"\n" -" Bind the offscreen object.\n" -"\n" -" :param save: save OpenGL current states.\n" -" :type save: bool\n" -); -static PyObject *pygpu_offscreen_bind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = {"save", NULL}; - bool save = true; - - BPY_GPU_OFFSCREEN_CHECK_OBJ(self); - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "|O&:bind", (char **)(kwlist), - PyC_ParseBool, &save)) - { - return NULL; - } - - GPU_offscreen_bind(self->ofs, save); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pygpu_offscreen_unbind_doc, -"unbind(restore=True)\n" -"\n" -" Unbind the offscreen object.\n" -"\n" -" :param restore: restore OpenGL previous states.\n" -" :type restore: bool\n" -); -static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = {"restore", NULL}; - bool restore = true; - - BPY_GPU_OFFSCREEN_CHECK_OBJ(self); - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "|O&:unbind", (char **)(kwlist), - PyC_ParseBool, &restore)) - { - return NULL; - } - - GPU_offscreen_unbind(self->ofs, restore); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc, -"draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n" -"\n" -" Draw the 3d viewport in the offscreen object.\n" -"\n" -" :param scene: Scene to draw.\n" -" :type scene: :class:`bpy.types.Scene`\n" -" :param view3d: 3D View to get the drawing settings from.\n" -" :type view3d: :class:`bpy.types.SpaceView3D`\n" -" :param region: Region of the 3D View.\n" -" :type region: :class:`bpy.types.Region`\n" -" :param modelview_matrix: ModelView Matrix.\n" -" :type modelview_matrix: :class:`mathutils.Matrix`\n" -" :param projection_matrix: Projection Matrix.\n" -" :type projection_matrix: :class:`mathutils.Matrix`\n" -); -static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = {"scene", "view3d", "region", "projection_matrix", "modelview_matrix", NULL}; - - MatrixObject *py_mat_modelview, *py_mat_projection; - PyObject *py_scene, *py_region, *py_view3d; - - struct Main *bmain = G_MAIN; /* XXX UGLY! */ - Scene *scene; - View3D *v3d; - ARegion *ar; - GPUFX *fx; - GPUFXSettings fx_settings; - struct RV3DMatrixStore *rv3d_mats; - - BPY_GPU_OFFSCREEN_CHECK_OBJ(self); - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "OOOO&O&:draw_view3d", (char **)(kwlist), - &py_scene, &py_view3d, &py_region, - Matrix_Parse4x4, &py_mat_projection, - Matrix_Parse4x4, &py_mat_modelview) || - (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) || - !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) || - !(ar = PyC_RNA_AsPointer(py_region, "Region")))) - { - return NULL; - } - - BLI_assert(BKE_id_is_in_gobal_main(&scene->id)); - - fx = GPU_fx_compositor_create(); - - fx_settings = v3d->fx_settings; /* full copy */ - - ED_view3d_draw_offscreen_init(bmain, scene, v3d); - - rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata); - - GPU_offscreen_bind(self->ofs, true); /* bind */ - - ED_view3d_draw_offscreen( - bmain, scene, v3d, ar, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs), - (float(*)[4])py_mat_modelview->matrix, (float(*)[4])py_mat_projection->matrix, - false, true, true, "", - fx, &fx_settings, - self->ofs); - - GPU_fx_compositor_destroy(fx); - GPU_offscreen_unbind(self->ofs, true); /* unbind */ - - ED_view3d_mats_rv3d_restore(ar->regiondata, rv3d_mats); - MEM_freeN(rv3d_mats); - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(pygpu_offscreen_free_doc, -"free()\n" -"\n" -" Free the offscreen object\n" -" The framebuffer, texture and render objects will no longer be accessible.\n" -); -static PyObject *pygpu_offscreen_free(BPy_GPUOffScreen *self) -{ - BPY_GPU_OFFSCREEN_CHECK_OBJ(self); - - GPU_offscreen_free(self->ofs); - self->ofs = NULL; - Py_RETURN_NONE; -} - -static void BPy_GPUOffScreen__tp_dealloc(BPy_GPUOffScreen *self) -{ - if (self->ofs) - GPU_offscreen_free(self->ofs); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyGetSetDef bpy_gpu_offscreen_getseters[] = { - {(char *)"color_texture", (getter)pygpu_offscreen_color_texture_get, (setter)NULL, pygpu_offscreen_color_texture_doc, NULL}, - {(char *)"width", (getter)pygpu_offscreen_width_get, (setter)NULL, pygpu_offscreen_width_doc, NULL}, - {(char *)"height", (getter)pygpu_offscreen_height_get, (setter)NULL, pygpu_offscreen_height_doc, NULL}, - {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ -}; - -static struct PyMethodDef bpy_gpu_offscreen_methods[] = { - {"bind", (PyCFunction)pygpu_offscreen_bind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_bind_doc}, - {"unbind", (PyCFunction)pygpu_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_unbind_doc}, - {"draw_view3d", (PyCFunction)pygpu_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_draw_view3d_doc}, - {"free", (PyCFunction)pygpu_offscreen_free, METH_NOARGS, pygpu_offscreen_free_doc}, - {NULL, NULL, 0, NULL} -}; - -PyDoc_STRVAR(py_gpu_offscreen_doc, -".. class:: GPUOffscreen" -"\n" -" This object gives access to off screen buffers.\n" -); -static PyTypeObject BPy_GPUOffScreen_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "GPUOffScreen", /* tp_name */ - sizeof(BPy_GPUOffScreen), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)BPy_GPUOffScreen__tp_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - NULL, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL, /* tp_hash */ - NULL, /* tp_call */ - NULL, /* tp_str */ - NULL, /* tp_getattro */ - NULL, /* tp_setattro */ - NULL, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - py_gpu_offscreen_doc, /* Documentation string */ - NULL, /* tp_traverse */ - NULL, /* tp_clear */ - NULL, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - NULL, /* tp_iter */ - NULL, /* tp_iternext */ - bpy_gpu_offscreen_methods, /* tp_methods */ - NULL, /* tp_members */ - bpy_gpu_offscreen_getseters, /* tp_getset */ - NULL, /* tp_base */ - NULL, /* tp_dict */ - NULL, /* tp_descr_get */ - NULL, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - NULL, /* tp_alloc */ - NULL, /* tp_new */ - (freefunc)0, /* tp_free */ - NULL, /* tp_is_gc */ - NULL, /* tp_bases */ - NULL, /* tp_mro */ - NULL, /* tp_cache */ - NULL, /* tp_subclasses */ - NULL, /* tp_weaklist */ - (destructor) NULL /* tp_del */ -}; - -/* -------------------------------------------------------------------- */ -/* GPU offscreen methods */ - -static PyObject *BPy_GPU_OffScreen_CreatePyObject(GPUOffScreen *ofs) -{ - BPy_GPUOffScreen *self; - self = PyObject_New(BPy_GPUOffScreen, &BPy_GPUOffScreen_Type); - self->ofs = ofs; - return (PyObject *)self; -} - -PyDoc_STRVAR(pygpu_offscreen_new_doc, -"new(width, height, samples=0)\n" -"\n" -" Return a GPUOffScreen.\n" -"\n" -" :param width: Horizontal dimension of the buffer.\n" -" :type width: int`\n" -" :param height: Vertical dimension of the buffer.\n" -" :type height: int`\n" -" :param samples: OpenGL samples to use for MSAA or zero to disable.\n" -" :type samples: int\n" -" :return: Newly created off-screen buffer.\n" -" :rtype: :class:`gpu.GPUOffscreen`\n" -); -static PyObject *pygpu_offscreen_new(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = {"width", "height", "samples", NULL}; - - GPUOffScreen *ofs; - int width, height, samples = 0; - char err_out[256]; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "ii|i:new", (char **)(kwlist), - &width, &height, &samples)) - { - return NULL; - } - - ofs = GPU_offscreen_create(width, height, samples, err_out); - - if (ofs == NULL) { - PyErr_Format(PyExc_RuntimeError, - "gpu.offscreen.new(...) failed with '%s'", - err_out[0] ? err_out : "unknown error"); - return NULL; - } - - return BPy_GPU_OffScreen_CreatePyObject(ofs); -} - -static struct PyMethodDef BPy_GPU_offscreen_methods[] = { - {"new", (PyCFunction)pygpu_offscreen_new, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_new_doc}, - {NULL, NULL, 0, NULL} -}; - -PyDoc_STRVAR(BPy_GPU_offscreen_doc, -"This module provides access to offscreen rendering functions." -); -static PyModuleDef BPy_GPU_offscreen_module_def = { - PyModuleDef_HEAD_INIT, - "gpu.offscreen", /* m_name */ - BPy_GPU_offscreen_doc, /* m_doc */ - 0, /* m_size */ - BPy_GPU_offscreen_methods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; - -PyObject *BPyInit_gpu_offscreen(void) -{ - PyObject *submodule; - - /* Register the 'GPUOffscreen' class */ - if (PyType_Ready(&BPy_GPUOffScreen_Type)) { - return NULL; - } - - submodule = PyModule_Create(&BPy_GPU_offscreen_module_def); - -#define MODULE_TYPE_ADD(s, t) \ - PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t) - - MODULE_TYPE_ADD(submodule, BPy_GPUOffScreen_Type); - -#undef MODULE_TYPE_ADD - - return submodule; -} - -#undef BPY_GPU_OFFSCREEN_CHECK_OBJ diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt index adf7c85d7c9..811cc1acbab 100644 --- a/source/blender/python/mathutils/CMakeLists.txt +++ b/source/blender/python/mathutils/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../../blenlib ../../blenkernel ../../bmesh + ../../depsgraph ../../makesdna ../../../../intern/guardedalloc ) diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 566bac9cb09..07905d2be89 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -645,30 +645,25 @@ PyMODINIT_FUNC PyInit_mathutils(void) * 'from mathutils.geometry import PolyFill' * ...fails without this. */ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate())); /* XXX, python doesnt do imports with this usefully yet * 'from mathutils.geometry import PolyFill' * ...fails without this. */ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); #ifndef MATH_STANDALONE /* Noise submodule */ PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); /* BVHTree submodule */ PyModule_AddObject(mod, "bvhtree", (submodule = PyInit_mathutils_bvhtree())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); /* KDTree submodule */ PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); - Py_INCREF(submodule); #endif mathutils_matrix_row_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_row_cb); diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index 286dd9f0750..ab78009ff89 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -62,7 +62,7 @@ enum { float *_data; /* array of data (alias), wrapped status depends on wrapped status */ \ PyObject *cb_user; /* if this vector references another object, otherwise NULL, \ * *Note* this owns its reference */ \ - unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ \ + unsigned char cb_type; /* which user funcs do we adhere to, RNA, etc */ \ unsigned char cb_subtype; /* subtype: location, rotation... \ * to avoid defining many new functions for every attribute of the same type */ \ unsigned char flag /* wrapped data type? */ \ diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index d4f9e5e80e2..c033a990901 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -2321,7 +2321,7 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2) return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1)); } /*------------------------obj * obj------------------------------ - * multiplication */ + * element-wise multiplication */ static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar) { float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; @@ -2332,7 +2332,6 @@ static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar) static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) { float scalar; - int vec_size; MatrixObject *mat1 = NULL, *mat2 = NULL; @@ -2348,9 +2347,118 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) } if (mat1 && mat2) { +#ifdef USE_MATHUTILS_ELEM_MUL /* MATRIX * MATRIX */ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; + if ((mat1->num_row != mat2->num_row) || (mat1->num_col != mat2->num_col)) { + PyErr_SetString(PyExc_ValueError, + "matrix1 * matrix2: matrix1 number of rows/columns " + "and the matrix2 number of rows/columns must be the same"); + return NULL; + } + + mul_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row); + + return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1)); +#endif + } + else if (mat2) { + /*FLOAT/INT * MATRIX */ + if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) { + return matrix_mul_float(mat2, scalar); + } + } + else if (mat1) { + /* MATRIX * FLOAT/INT */ + if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) { + return matrix_mul_float(mat1, scalar); + } + } + + PyErr_Format(PyExc_TypeError, + "Element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); + return NULL; +} +/*------------------------obj *= obj------------------------------ + * Inplace element-wise multiplication */ +static PyObject *Matrix_imul(PyObject *m1, PyObject *m2) +{ + float scalar; + + MatrixObject *mat1 = NULL, *mat2 = NULL; + + if (MatrixObject_Check(m1)) { + mat1 = (MatrixObject *)m1; + if (BaseMath_ReadCallback(mat1) == -1) + return NULL; + } + if (MatrixObject_Check(m2)) { + mat2 = (MatrixObject *)m2; + if (BaseMath_ReadCallback(mat2) == -1) + return NULL; + } + + if (mat1 && mat2) { +#ifdef USE_MATHUTILS_ELEM_MUL + /* MATRIX *= MATRIX */ + if ((mat1->num_row != mat2->num_row) || (mat1->num_col != mat2->num_col)) { + PyErr_SetString(PyExc_ValueError, + "matrix1 *= matrix2: matrix1 number of rows/columns " + "and the matrix2 number of rows/columns must be the same"); + return NULL; + } + + mul_vn_vn(mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row); +#else + PyErr_Format(PyExc_TypeError, + "Inplace element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); + return NULL; +#endif + } + else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) { + /* MATRIX *= FLOAT/INT */ + mul_vn_fl(mat1->matrix, mat1->num_row * mat1->num_col, scalar); + } + else { + PyErr_Format(PyExc_TypeError, + "Inplace element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); + return NULL; + } + + (void)BaseMath_WriteCallback(mat1); + Py_INCREF(m1); + return m1; +} +/*------------------------obj @ obj------------------------------ + * matrix multiplication */ +static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2) +{ + int vec_size; + + MatrixObject *mat1 = NULL, *mat2 = NULL; + + if (MatrixObject_Check(m1)) { + mat1 = (MatrixObject *)m1; + if (BaseMath_ReadCallback(mat1) == -1) + return NULL; + } + if (MatrixObject_Check(m2)) { + mat2 = (MatrixObject *)m2; + if (BaseMath_ReadCallback(mat2) == -1) + return NULL; + } + + if (mat1 && mat2) { + /* MATRIX @ MATRIX */ + float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; + int col, row, item; if (mat1->num_col != mat2->num_row) { @@ -2372,14 +2480,8 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1)); } - else if (mat2) { - /*FLOAT/INT * MATRIX */ - if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) { - return matrix_mul_float(mat2, scalar); - } - } else if (mat1) { - /* MATRIX * VECTOR */ + /* MATRIX @ VECTOR */ if (VectorObject_Check(m2)) { VectorObject *vec2 = (VectorObject *)m2; float tvec[MATRIX_MAX_DIM]; @@ -2398,13 +2500,6 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(m2)); } - /*FLOAT/INT * MATRIX */ - else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) { - return matrix_mul_float(mat1, scalar); - } - } - else { - BLI_assert(!"internal error"); } PyErr_Format(PyExc_TypeError, @@ -2413,6 +2508,62 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); return NULL; } +/*------------------------obj @= obj------------------------------ + * inplace matrix multiplication */ +static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2) +{ + MatrixObject *mat1 = NULL, *mat2 = NULL; + + if (MatrixObject_Check(m1)) { + mat1 = (MatrixObject *)m1; + if (BaseMath_ReadCallback(mat1) == -1) + return NULL; + } + if (MatrixObject_Check(m2)) { + mat2 = (MatrixObject *)m2; + if (BaseMath_ReadCallback(mat2) == -1) + return NULL; + } + + if (mat1 && mat2) { + /* MATRIX @= MATRIX */ + float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; + int col, row, item; + + if (mat1->num_col != mat2->num_row) { + PyErr_SetString(PyExc_ValueError, + "matrix1 * matrix2: matrix1 number of columns " + "and the matrix2 number of rows must be the same"); + return NULL; + } + + for (col = 0; col < mat2->num_col; col++) { + for (row = 0; row < mat1->num_row; row++) { + double dot = 0.0f; + for (item = 0; item < mat1->num_col; item++) { + dot += (double)(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col)); + } + /* store in new matrix as overwriting original at this point will cause + * subsequent iterations to use incorrect values */ + mat[(col * mat1->num_row) + row] = (float)dot; + } + } + + /* copy matrix back */ + memcpy(mat1->matrix, mat, (mat1->num_row * mat1->num_col) * sizeof(float)); + } + else { + PyErr_Format(PyExc_TypeError, + "Inplace matrix multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); + return NULL; + } + + (void)BaseMath_WriteCallback(mat1); + Py_INCREF(m1); + return m1; +} /*-----------------PROTOCOL DECLARATIONS--------------------------*/ static PySequenceMethods Matrix_SeqMethods = { @@ -2527,7 +2678,7 @@ static PyNumberMethods Matrix_NumMethods = { NULL, /*nb_float*/ NULL, /* nb_inplace_add */ NULL, /* nb_inplace_subtract */ - NULL, /* nb_inplace_multiply */ + (binaryfunc) Matrix_imul, /* nb_inplace_multiply */ NULL, /* nb_inplace_remainder */ NULL, /* nb_inplace_power */ NULL, /* nb_inplace_lshift */ @@ -2540,6 +2691,8 @@ static PyNumberMethods Matrix_NumMethods = { NULL, /* nb_inplace_floor_divide */ NULL, /* nb_inplace_true_divide */ NULL, /* nb_index */ + (binaryfunc) Matrix_matmul, /* nb_matrix_multiply */ + (binaryfunc) Matrix_imatmul, /* nb_inplace_matrix_multiply */ }; PyDoc_STRVAR(Matrix_translation_doc, diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 645fa96c22e..a2b4480584a 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -834,7 +834,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar) * multiplication */ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) { - float quat[QUAT_SIZE], scalar; + float scalar; QuaternionObject *quat1 = NULL, *quat2 = NULL; if (QuaternionObject_Check(q1)) { @@ -848,9 +848,12 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) return NULL; } - if (quat1 && quat2) { /* QUAT * QUAT (cross product) */ - mul_qt_qtqt(quat, quat1->quat, quat2->quat); + if (quat1 && quat2) { /* QUAT * QUAT (element-wise product) */ +#ifdef USE_MATHUTILS_ELEM_MUL + float quat[QUAT_SIZE]; + mul_vn_vnvn(quat, quat1->quat, quat2->quat, QUAT_SIZE); return Quaternion_CreatePyObject(quat, Py_TYPE(q1)); +#endif } /* the only case this can happen (for a supported type is "FLOAT * QUAT") */ else if (quat2) { /* FLOAT * QUAT */ @@ -858,8 +861,87 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) return quat_mul_float(quat2, scalar); } } + else if (quat1) { /* QUAT * FLOAT */ + if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) { + return quat_mul_float(quat1, scalar); + } + } + + PyErr_Format(PyExc_TypeError, + "Element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); + return NULL; +} +/*------------------------obj *= obj------------------------------ + * inplace multiplication */ +static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2) +{ + float scalar; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if (QuaternionObject_Check(q1)) { + quat1 = (QuaternionObject *)q1; + if (BaseMath_ReadCallback(quat1) == -1) + return NULL; + } + if (QuaternionObject_Check(q2)) { + quat2 = (QuaternionObject *)q2; + if (BaseMath_ReadCallback(quat2) == -1) + return NULL; + } + + if (quat1 && quat2) { /* QUAT *= QUAT (inplace element-wise product) */ +#ifdef USE_MATHUTILS_ELEM_MUL + mul_vn_vn(quat1->quat, quat2->quat, QUAT_SIZE); +#else + PyErr_Format(PyExc_TypeError, + "Inplace element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); + return NULL; +#endif + } + else if (quat1 && (((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) { + /* QUAT *= FLOAT */ + mul_qt_fl(quat1->quat, scalar); + } + else { + PyErr_Format(PyExc_TypeError, + "Element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); + return NULL; + } + + (void)BaseMath_WriteCallback(quat1); + Py_INCREF(q1); + return q1; +} +/*------------------------obj @ obj------------------------------ + * quaternion multiplication */ +static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2) +{ + float quat[QUAT_SIZE]; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if (QuaternionObject_Check(q1)) { + quat1 = (QuaternionObject *)q1; + if (BaseMath_ReadCallback(quat1) == -1) + return NULL; + } + if (QuaternionObject_Check(q2)) { + quat2 = (QuaternionObject *)q2; + if (BaseMath_ReadCallback(quat2) == -1) + return NULL; + } + + if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */ + mul_qt_qtqt(quat, quat1->quat, quat2->quat); + return Quaternion_CreatePyObject(quat, Py_TYPE(q1)); + } else if (quat1) { - /* QUAT * VEC */ + /* QUAT @ VEC */ if (VectorObject_Check(q2)) { VectorObject *vec2 = (VectorObject *)q2; float tvec[3]; @@ -880,13 +962,6 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec2)); } - /* QUAT * FLOAT */ - else if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) { - return quat_mul_float(quat1, scalar); - } - } - else { - BLI_assert(!"internal error"); } PyErr_Format(PyExc_TypeError, @@ -895,6 +970,40 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); return NULL; } +/*------------------------obj @= obj------------------------------ + * inplace quaternion multiplication */ +static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2) +{ + float quat[QUAT_SIZE]; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if (QuaternionObject_Check(q1)) { + quat1 = (QuaternionObject *)q1; + if (BaseMath_ReadCallback(quat1) == -1) + return NULL; + } + if (QuaternionObject_Check(q2)) { + quat2 = (QuaternionObject *)q2; + if (BaseMath_ReadCallback(quat2) == -1) + return NULL; + } + + if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */ + mul_qt_qtqt(quat, quat1->quat, quat2->quat); + copy_qt_qt(quat1->quat, quat); + } + else { + PyErr_Format(PyExc_TypeError, + "Inplace quaternion multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); + return NULL; + } + + (void)BaseMath_WriteCallback(quat1); + Py_INCREF(q1); + return q1; +} /* -obj * returns the negative of this object*/ @@ -952,7 +1061,7 @@ static PyNumberMethods Quaternion_NumMethods = { NULL, /*nb_float*/ NULL, /* nb_inplace_add */ NULL, /* nb_inplace_subtract */ - NULL, /* nb_inplace_multiply */ + (binaryfunc) Quaternion_imul, /* nb_inplace_multiply */ NULL, /* nb_inplace_remainder */ NULL, /* nb_inplace_power */ NULL, /* nb_inplace_lshift */ @@ -965,6 +1074,8 @@ static PyNumberMethods Quaternion_NumMethods = { NULL, /* nb_inplace_floor_divide */ NULL, /* nb_inplace_true_divide */ NULL, /* nb_index */ + (binaryfunc) Quaternion_matmul, /* nb_matrix_multiply */ + (binaryfunc) Quaternion_imatmul, /* nb_inplace_matrix_multiply */ }; PyDoc_STRVAR(Quaternion_axis_doc, diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index e7776f836aa..16a242fc718 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -1706,12 +1706,25 @@ static PyObject *vector_mul_float(VectorObject *vec, const float scalar) mul_vn_vn_fl(tvec, vec->vec, vec->size, scalar); return Vector_CreatePyObject_alloc(tvec, vec->size, Py_TYPE(vec)); } +#ifdef USE_MATHUTILS_ELEM_MUL +static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2) +{ + float *tvec = PyMem_Malloc(vec1->size * sizeof(float)); + if (tvec == NULL) { + PyErr_SetString(PyExc_MemoryError, + "vec * vec: " + "problem allocating pointer space"); + return NULL; + } + mul_vn_vnvn(tvec, vec1->vec, vec2->vec, vec1->size); + return Vector_CreatePyObject_alloc(tvec, vec1->size, Py_TYPE(vec1)); +} +#endif static PyObject *Vector_mul(PyObject *v1, PyObject *v2) { VectorObject *vec1 = NULL, *vec2 = NULL; float scalar; - int vec_size; if (VectorObject_Check(v1)) { vec1 = (VectorObject *)v1; @@ -1729,6 +1742,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) /* make sure v1 is always the vector */ if (vec1 && vec2) { +#ifdef USE_MATHUTILS_ELEM_MUL if (vec1->size != vec2->size) { PyErr_SetString(PyExc_ValueError, "Vector multiplication: " @@ -1736,30 +1750,12 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) return NULL; } - /*dot product*/ - return PyFloat_FromDouble(dot_vn_vn(vec1->vec, vec2->vec, vec1->size)); + /* element-wise product */ + return vector_mul_vec(vec1, vec2); +#endif } else if (vec1) { - if (MatrixObject_Check(v2)) { - /* VEC * MATRIX */ - float tvec[MAX_DIMENSIONS]; - - if (BaseMath_ReadCallback((MatrixObject *)v2) == -1) - return NULL; - if (row_vector_multiplication(tvec, vec1, (MatrixObject *)v2) == -1) { - return NULL; - } - - if (((MatrixObject *)v2)->num_row == 4 && vec1->size == 3) { - vec_size = 3; - } - else { - vec_size = ((MatrixObject *)v2)->num_col; - } - - return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(vec1)); - } - else if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */ + if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */ return vector_mul_float(vec1, scalar); } } @@ -1768,12 +1764,9 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) return vector_mul_float(vec2, scalar); } } - else { - BLI_assert(!"internal error"); - } PyErr_Format(PyExc_TypeError, - "Vector multiplication: " + "Element-wise multiplication: " "not supported between '%.200s' and '%.200s' types", Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); return NULL; @@ -1782,32 +1775,129 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) /* multiplication in-place: obj *= obj */ static PyObject *Vector_imul(PyObject *v1, PyObject *v2) { - VectorObject *vec = (VectorObject *)v1; + VectorObject *vec1 = NULL, *vec2 = NULL; float scalar; - if (BaseMath_ReadCallback_ForWrite(vec) == -1) + if (VectorObject_Check(v1)) { + vec1 = (VectorObject *)v1; + if (BaseMath_ReadCallback(vec1) == -1) + return NULL; + } + if (VectorObject_Check(v2)) { + vec2 = (VectorObject *)v2; + if (BaseMath_ReadCallback(vec2) == -1) + return NULL; + } + + if (BaseMath_ReadCallback_ForWrite(vec1) == -1) return NULL; /* Intentionally don't support (Quaternion, Matrix) here, uses reverse order instead. */ - /* only support 'vec *= float' - * vec*=vec result is a float so that wont work */ - if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC *= FLOAT */ - mul_vn_fl(vec->vec, vec->size, scalar); + if (vec1 && vec2) { +#ifdef USE_MATHUTILS_ELEM_MUL + if (vec1->size != vec2->size) { + PyErr_SetString(PyExc_ValueError, + "Vector multiplication: " + "vectors must have the same dimensions for this operation"); + return NULL; + } + + /* element-wise product inplace */ + mul_vn_vn(vec1->vec, vec2->vec, vec1->size); +#else + PyErr_Format(PyExc_TypeError, + "Inplace element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); + return NULL; +#endif + } + else if (vec1 && (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0)) { /* VEC *= FLOAT */ + mul_vn_fl(vec1->vec, vec1->size, scalar); } else { PyErr_Format(PyExc_TypeError, - "Vector multiplication: (%s *= %s) " - "invalid type for this operation", + "Inplace element-wise multiplication: " + "not supported between '%.200s' and '%.200s' types", Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); return NULL; } - (void)BaseMath_WriteCallback(vec); + (void)BaseMath_WriteCallback(vec1); Py_INCREF(v1); return v1; } +static PyObject *Vector_matmul(PyObject *v1, PyObject *v2) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + int vec_size; + + if (VectorObject_Check(v1)) { + vec1 = (VectorObject *)v1; + if (BaseMath_ReadCallback(vec1) == -1) + return NULL; + } + if (VectorObject_Check(v2)) { + vec2 = (VectorObject *)v2; + if (BaseMath_ReadCallback(vec2) == -1) + return NULL; + } + + + /* Intentionally don't support (Quaternion) here, uses reverse order instead. */ + + /* make sure v1 is always the vector */ + if (vec1 && vec2) { + if (vec1->size != vec2->size) { + PyErr_SetString(PyExc_ValueError, + "Vector multiplication: " + "vectors must have the same dimensions for this operation"); + return NULL; + } + + /*dot product*/ + return PyFloat_FromDouble(dot_vn_vn(vec1->vec, vec2->vec, vec1->size)); + } + else if (vec1) { + if (MatrixObject_Check(v2)) { + /* VEC @ MATRIX */ + float tvec[MAX_DIMENSIONS]; + + if (BaseMath_ReadCallback((MatrixObject *)v2) == -1) + return NULL; + if (row_vector_multiplication(tvec, vec1, (MatrixObject *)v2) == -1) { + return NULL; + } + + if (((MatrixObject *)v2)->num_row == 4 && vec1->size == 3) { + vec_size = 3; + } + else { + vec_size = ((MatrixObject *)v2)->num_col; + } + + return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(vec1)); + } + } + + PyErr_Format(PyExc_TypeError, + "Vector multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); + return NULL; +} + +static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2) +{ + PyErr_Format(PyExc_TypeError, + "Inplace vector multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); + return NULL; +} + /* divid: obj / obj */ static PyObject *Vector_div(PyObject *v1, PyObject *v2) { @@ -2119,6 +2209,8 @@ static PyNumberMethods Vector_NumMethods = { NULL, /* nb_inplace_floor_divide */ Vector_idiv, /* nb_inplace_true_divide */ NULL, /* nb_index */ + (binaryfunc) Vector_matmul, /* nb_matrix_multiply */ + (binaryfunc) Vector_imatmul, /* nb_inplace_matrix_multiply */ }; /*------------------PY_OBECT DEFINITION--------------------------*/ diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 36727fb91ae..fce0dd7d2af 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -48,10 +48,16 @@ #ifndef MATH_STANDALONE #include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" #include "BKE_editmesh_bvh.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" + +#include "DEG_depsgraph_query.h" #include "bmesh.h" @@ -1045,88 +1051,98 @@ static PyObject *C_BVHTree_FromBMesh(PyObject *UNUSED(cls), PyObject *args, PyOb } /* return various derived meshes based on requested settings */ -static DerivedMesh *bvh_get_derived_mesh( - const char *funcname, struct Scene *scene, Object *ob, - bool use_deform, bool use_render, bool use_cage) +static Mesh *bvh_get_mesh( + const char *funcname, struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, + const bool use_deform, const bool use_cage, bool *r_free_mesh) { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); /* we only need minimum mesh data for topology and vertex locations */ CustomDataMask mask = CD_MASK_BAREMESH; + const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER; + *r_free_mesh = false; /* Write the display mesh into the dummy mesh */ if (use_deform) { if (use_render) { if (use_cage) { PyErr_Format(PyExc_ValueError, - "%s(...): cage arg is unsupported when (render=True)", funcname); + "%s(...): cage arg is unsupported when dependency graph evaluation mode is RENDER", funcname); return NULL; } else { - return mesh_create_derived_render(scene, ob, mask); + *r_free_mesh = true; + return mesh_create_eval_final_render(depsgraph, scene, ob, mask); } } - else { + else if (ob_eval != NULL) { if (use_cage) { - return mesh_get_derived_deform(scene, ob, mask); /* ob->derivedDeform */ + return mesh_get_eval_deform(depsgraph, scene, ob_eval, mask); /* ob->derivedDeform */ } else { - return mesh_get_derived_final(scene, ob, mask); /* ob->derivedFinal */ + return mesh_get_eval_final(depsgraph, scene, ob_eval, mask); /* ob->derivedFinal */ } } + else { + PyErr_Format(PyExc_ValueError, + "%s(...): Cannot get evaluated data from given dependency graph / object pair", funcname); + return NULL; + } } else { /* !use_deform */ if (use_render) { if (use_cage) { PyErr_Format(PyExc_ValueError, - "%s(...): cage arg is unsupported when (render=True)", funcname); + "%s(...): cage arg is unsupported when dependency graph evaluation mode is RENDER", funcname); return NULL; } else { - return mesh_create_derived_no_deform_render(scene, ob, NULL, mask); + *r_free_mesh = true; + return mesh_create_eval_no_deform_render(depsgraph, scene, ob, NULL, mask); } } else { if (use_cage) { PyErr_Format(PyExc_ValueError, - "%s(...): cage arg is unsupported when (deform=False, render=False)", funcname); + "%s(...): cage arg is unsupported when deform=False and dependency graph evaluation mode is not RENDER", funcname); return NULL; } else { - return mesh_create_derived_no_deform(scene, ob, NULL, mask); + *r_free_mesh = true; + return mesh_create_eval_no_deform(depsgraph, scene, ob, NULL, mask); } } } } PyDoc_STRVAR(C_BVHTree_FromObject_doc, -".. classmethod:: FromObject(object, scene, deform=True, render=False, cage=False, epsilon=0.0)\n" +".. classmethod:: FromObject(object, depsgraph, deform=True, render=False, cage=False, epsilon=0.0)\n" "\n" " BVH tree based on :class:`Object` data.\n" "\n" " :arg object: Object data.\n" " :type object: :class:`Object`\n" -" :arg scene: Scene data to use for evaluating the mesh.\n" -" :type scene: :class:`Scene`\n" +" :arg depsgraph: Depsgraph to use for evaluating the mesh.\n" +" :type depsgraph: :class:`Depsgraph`\n" " :arg deform: Use mesh with deformations.\n" " :type deform: bool\n" -" :arg render: Use render settings.\n" -" :type render: bool\n" -" :arg cage: Use render settings.\n" +" :arg cage: Use modifiers cage.\n" " :type cage: bool\n" PYBVH_FROM_GENERIC_EPSILON_DOC ); static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyObject *kwargs) { /* note, options here match 'bpy_bmesh_from_object' */ - const char *keywords[] = {"object", "scene", "deform", "render", "cage", "epsilon", NULL}; + const char *keywords[] = {"object", "depsgraph", "deform", "cage", "epsilon", NULL}; - PyObject *py_ob, *py_scene; + PyObject *py_ob, *py_depsgraph; Object *ob; + struct Depsgraph *depsgraph; struct Scene *scene; - DerivedMesh *dm; + Mesh *mesh; bool use_deform = true; - bool use_render = false; bool use_cage = false; + bool free_mesh = false; const MLoopTri *lt; const MLoop *mloop; @@ -1137,36 +1153,40 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO float epsilon = 0.0f; if (!PyArg_ParseTupleAndKeywords( - args, kwargs, (char *)"OO|$O&O&O&f:BVHTree.FromObject", (char **)keywords, - &py_ob, &py_scene, + args, kwargs, (char *)"OO|$O&O&f:BVHTree.FromObject", (char **)keywords, + &py_ob, &py_depsgraph, PyC_ParseBool, &use_deform, - PyC_ParseBool, &use_render, PyC_ParseBool, &use_cage, &epsilon) || ((ob = PyC_RNA_AsPointer(py_ob, "Object")) == NULL) || - ((scene = PyC_RNA_AsPointer(py_scene, "Scene")) == NULL)) + ((depsgraph = PyC_RNA_AsPointer(py_depsgraph, "Depsgraph")) == NULL)) { return NULL; } - dm = bvh_get_derived_mesh("BVHTree", scene, ob, use_deform, use_render, use_cage); - if (dm == NULL) { + scene = DEG_get_evaluated_scene(depsgraph); + mesh = bvh_get_mesh("BVHTree", depsgraph, scene, ob, use_deform, use_cage, &free_mesh); + + if (mesh == NULL) { return NULL; } /* Get data for tessellation */ { - lt = dm->getLoopTriArray(dm); + lt = BKE_mesh_runtime_looptri_ensure(mesh); - tris_len = (unsigned int)dm->getNumLoopTri(dm); - coords_len = (unsigned int)dm->getNumVerts(dm); + tris_len = (unsigned int)BKE_mesh_runtime_looptri_len(mesh); + coords_len = (unsigned int)mesh->totvert; coords = MEM_mallocN(sizeof(*coords) * (size_t)coords_len, __func__); tris = MEM_mallocN(sizeof(*tris) * (size_t)tris_len, __func__); - dm->getVertCos(dm, coords); + MVert *mv = mesh->mvert; + for (int i = 0; i < mesh->totvert; i++, mv++) { + copy_v3_v3(coords[i], mv->co); + } - mloop = dm->getLoopArray(dm); + mloop = mesh->mloop; } { @@ -1179,7 +1199,8 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO tree = BLI_bvhtree_new((int)tris_len, epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT); if (tree) { orig_index = MEM_mallocN(sizeof(*orig_index) * (size_t)tris_len, __func__); - orig_normal = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */ + CustomData *pdata = &mesh->pdata; + orig_normal = CustomData_get_layer(pdata, CD_NORMAL); /* can be NULL */ if (orig_normal) { orig_normal = MEM_dupallocN(orig_normal); } @@ -1202,7 +1223,9 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO BLI_bvhtree_balance(tree); } - dm->release(dm); + if (free_mesh) { + BKE_id_free(NULL, mesh); + } return bvhtree_CreatePyObject( tree, epsilon, diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c index 834322c0aed..5e3e86c8ddf 100644 --- a/source/blender/python/mathutils/mathutils_noise.c +++ b/source/blender/python/mathutils/mathutils_noise.c @@ -40,18 +40,11 @@ #include "DNA_texture_types.h" +#include "../generic/py_capi_utils.h" + #include "mathutils.h" #include "mathutils_noise.h" -/* 2.6 update - * Moved to submodule of mathutils. - * All vector functions now return mathutils.Vector - * Updated docs to be compatible with autodocs generation. - * Updated vector functions to use nD array functions. - * noise.vl_vector --> noise.variable_lacunarity - * noise.vector --> noise.noise_vector - */ - /*-----------------------------------------*/ /* 'mersenne twister' random number generator */ @@ -198,6 +191,48 @@ static float frand(void) /* Utility Functions */ /*------------------------------------------------------------*/ +#define BPY_NOISE_BASIS_ENUM_DOC \ +" :arg noise_basis: Enumerator in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', " \ + "'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', " \ + "'CELLNOISE'].\n" \ +" :type noise_basis: string\n" \ + +#define BPY_NOISE_METRIC_ENUM_DOC \ +" :arg distance_metric: Enumerator in ['DISTANCE', 'DISTANCE_SQUARED', 'MANHATTAN', 'CHEBYCHEV', " \ + "'MINKOVSKY', 'MINKOVSKY_HALF', 'MINKOVSKY_FOUR'].\n" \ +" :type distance_metric: string\n" \ + +/* Noise basis enum */ +#define DEFAULT_NOISE_TYPE TEX_STDPERLIN + +static PyC_FlagSet bpy_noise_types[] = { + {TEX_BLENDER, "BLENDER"}, + {TEX_STDPERLIN, "PERLIN_ORIGINAL"}, + {TEX_NEWPERLIN, "PERLIN_NEW"}, + {TEX_VORONOI_F1, "VORONOI_F1"}, + {TEX_VORONOI_F2, "VORONOI_F2"}, + {TEX_VORONOI_F3, "VORONOI_F3"}, + {TEX_VORONOI_F4, "VORONOI_F4"}, + {TEX_VORONOI_F2F1, "VORONOI_F2F1"}, + {TEX_VORONOI_CRACKLE, "VORONOI_CRACKLE"}, + {TEX_CELLNOISE, "CELLNOISE"}, + {0, NULL} +}; + +/* Metric basis enum */ +#define DEFAULT_METRIC_TYPE TEX_DISTANCE + +static PyC_FlagSet bpy_noise_metrics[] = { + {TEX_DISTANCE, "DISTANCE"}, + {TEX_DISTANCE_SQUARED, "DISTANCE_SQUARED"}, + {TEX_MANHATTAN, "MANHATTAN"}, + {TEX_CHEBYCHEV, "CHEBYCHEV"}, + {TEX_MINKOVSKY, "MINKOVSKY"}, + {TEX_MINKOVSKY_HALF, "MINKOVSKY_HALF"}, + {TEX_MINKOVSKY_FOUR, "MINKOVSKY_FOUR"}, + {0, NULL} +}; + /* Fills an array of length size with random numbers in the range (-1, 1)*/ static void rand_vn(float *array_tar, const int size) { @@ -218,8 +253,9 @@ static void noise_vector(float x, float y, float z, int nb, float v[3]) } /* Returns a turbulence value for a given position (x, y, z) */ -static float turb(float x, float y, float z, int oct, int hard, int nb, - float ampscale, float freqscale) +static float turb( + float x, float y, float z, int oct, int hard, int nb, + float ampscale, float freqscale) { float amp, out, t; int i; @@ -242,8 +278,9 @@ static float turb(float x, float y, float z, int oct, int hard, int nb, /* Fills an array of length 3 with the turbulence vector for a given * position (x, y, z) */ -static void vTurb(float x, float y, float z, int oct, int hard, int nb, - float ampscale, float freqscale, float v[3]) +static void vTurb( + float x, float y, float z, int oct, int hard, int nb, + float ampscale, float freqscale, float v[3]) { float amp, t[3]; int i; @@ -283,7 +320,7 @@ PyDoc_STRVAR(M_Noise_doc, PyDoc_STRVAR(M_Noise_random_doc, ".. function:: random()\n" "\n" -" Returns a random number in the range [0, 1].\n" +" Returns a random number in the range [0, 1).\n" "\n" " :return: The random number.\n" " :rtype: float\n" @@ -298,71 +335,81 @@ PyDoc_STRVAR(M_Noise_random_unit_vector_doc, "\n" " Returns a unit vector with random entries.\n" "\n" -" :arg size: The size of the vector to be produced.\n" -" :type size: Int\n" +" :arg size: The size of the vector to be produced, in the range [2, 4].\n" +" :type size: int\n" " :return: The random unit vector.\n" " :rtype: :class:`mathutils.Vector`\n" ); -static PyObject *M_Noise_random_unit_vector(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_random_unit_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"size", NULL}; float vec[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float norm = 2.0f; int size = 3; - if (!PyArg_ParseTuple(args, "|i:random_vector", &size)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "|$i:random_unit_vector", (char **)kwlist, + &size)) + { return NULL; + } if (size > 4 || size < 2) { PyErr_SetString(PyExc_ValueError, "Vector(): invalid size"); return NULL; } - while (norm == 0.0f || norm >= 1.0f) { + while (norm == 0.0f || norm > 1.0f) { rand_vn(vec, size); norm = normalize_vn(vec, size); } return Vector_CreatePyObject(vec, size, NULL); } -/* This is dumb, most people will want a unit vector anyway, since this doesn't have uniform distribution over a sphere*/ -#if 0 + PyDoc_STRVAR(M_Noise_random_vector_doc, ".. function:: random_vector(size=3)\n" "\n" -" Returns a vector with random entries in the range [0, 1).\n" +" Returns a vector with random entries in the range (-1, 1).\n" "\n" " :arg size: The size of the vector to be produced.\n" -" :type size: Int\n" +" :type size: int\n" " :return: The random vector.\n" " :rtype: :class:`mathutils.Vector`\n" ); -static PyObject *M_Noise_random_vector(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_random_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - float vec[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + static const char *kwlist[] = {"size", NULL}; + float *vec = NULL; int size = 3; - if (!PyArg_ParseTuple(args, "|i:random_vector", &size)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "|$i:random_vector", (char **)kwlist, + &size)) + { return NULL; + } - if (size > 4 || size < 2) { + if (size < 2) { PyErr_SetString(PyExc_ValueError, "Vector(): invalid size"); return NULL; } + vec = PyMem_New(float, size); + rand_vn(vec, size); - return Vector_CreatePyObject(vec, size, NULL); + return Vector_CreatePyObject_alloc(vec, size, NULL); } -#endif PyDoc_STRVAR(M_Noise_seed_set_doc, ".. function:: seed_set(seed)\n" "\n" -" Sets the random seed used for random_unit_vector, random_vector and random.\n" +" Sets the random seed used for random_unit_vector, and random.\n" "\n" " :arg seed: Seed used for the random generator.\n" " When seed is zero, the current time will be used instead.\n" -" :type seed: Int\n" +" :type seed: int\n" ); static PyObject *M_Noise_seed_set(PyObject *UNUSED(self), PyObject *args) { @@ -374,139 +421,198 @@ static PyObject *M_Noise_seed_set(PyObject *UNUSED(self), PyObject *args) } PyDoc_STRVAR(M_Noise_noise_doc, -".. function:: noise(position, noise_basis=noise.types.STDPERLIN)\n" +".. function:: noise(position, noise_basis='PERLIN_ORIGINAL')\n" "\n" " Returns noise value from the noise basis at the position specified.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :return: The noise value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_noise(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_noise(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "noise_basis", NULL}; PyObject *value; float vec[3]; - int nb = 1; - if (!PyArg_ParseTuple(args, "O|i:noise", &value, &nb)) + const char *noise_basis_str = NULL; + int noise_basis_enum = DEFAULT_NOISE_TYPE; + + if (!PyArg_ParseTupleAndKeywords( + args, kw, "O|$s:noise", (char **)kwlist, + &value, &noise_basis_str)) + { + return NULL; + } + + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "noise") == -1) + { return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "noise: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble((2.0f * BLI_gNoise(1.0f, vec[0], vec[1], vec[2], 0, nb) - 1.0f)); + return PyFloat_FromDouble((2.0f * BLI_gNoise(1.0f, vec[0], vec[1], vec[2], 0, noise_basis_enum) - 1.0f)); } PyDoc_STRVAR(M_Noise_noise_vector_doc, -".. function:: noise_vector(position, noise_basis=noise.types.STDPERLIN)\n" +".. function:: noise_vector(position, noise_basis='PERLIN_ORIGINAL')\n" "\n" " Returns the noise vector from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :return: The noise vector.\n" " :rtype: :class:`mathutils.Vector`\n" ); -static PyObject *M_Noise_noise_vector(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_noise_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "noise_basis", NULL}; PyObject *value; float vec[3], r_vec[3]; - int nb = 1; + const char *noise_basis_str = NULL; + int noise_basis_enum = DEFAULT_NOISE_TYPE; - if (!PyArg_ParseTuple(args, "O|i:noise_vector", &value, &nb)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "O|$s:noise_vector", (char **)kwlist, + &value, &noise_basis_str)) + { + return NULL; + } + + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "noise_vector") == -1) + { return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "noise_vector: invalid 'position' arg") == -1) return NULL; - noise_vector(vec[0], vec[1], vec[2], nb, r_vec); + noise_vector(vec[0], vec[1], vec[2], noise_basis_enum, r_vec); return Vector_CreatePyObject(r_vec, 3, NULL); } PyDoc_STRVAR(M_Noise_turbulence_doc, -".. function:: turbulence(position, octaves, hard, noise_basis=noise.types.STDPERLIN, amplitude_scale=0.5, frequency_scale=2.0)\n" +".. function:: turbulence(position, octaves, hard, noise_basis='PERLIN_ORIGINAL', amplitude_scale=0.5, frequency_scale=2.0)\n" "\n" " Returns the turbulence value from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg octaves: The number of different noise frequencies used.\n" " :type octaves: int\n" " :arg hard: Specifies whether returned turbulence is hard (sharp transitions) or soft (smooth transitions).\n" -" :type hard: :boolean\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in mathutils.noise.types or int\n" +" :type hard: boolean\n" +BPY_NOISE_BASIS_ENUM_DOC " :arg amplitude_scale: The amplitude scaling factor.\n" " :type amplitude_scale: float\n" " :arg frequency_scale: The frequency scaling factor\n" -" :type frequency_scale: Value in noise.types or int\n" +" :type frequency_scale: float\n" " :return: The turbulence value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_turbulence(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_turbulence(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "", "noise_basis", "amplitude_scale", "frequency_scale", NULL}; PyObject *value; float vec[3]; - int oct, hd, nb = 1; + const char *noise_basis_str = NULL; + int oct, hd, noise_basis_enum = DEFAULT_NOISE_TYPE; float as = 0.5f, fs = 2.0f; - if (!PyArg_ParseTuple(args, "Oii|iff:turbulence", &value, &oct, &hd, &nb, &as, &fs)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Oii|$sff:turbulence", (char **)kwlist, + &value, &oct, &hd, &noise_basis_str, &as, &fs)) + { return NULL; + } + + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "turbulence") == -1) + { + return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "turbulence: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble(turb(vec[0], vec[1], vec[2], oct, hd, nb, as, fs)); + return PyFloat_FromDouble(turb(vec[0], vec[1], vec[2], oct, hd, noise_basis_enum, as, fs)); } PyDoc_STRVAR(M_Noise_turbulence_vector_doc, -".. function:: turbulence_vector(position, octaves, hard, noise_basis=noise.types.STDPERLIN, amplitude_scale=0.5, frequency_scale=2.0)\n" +".. function:: turbulence_vector(position, octaves, hard, noise_basis='PERLIN_ORIGINAL', amplitude_scale=0.5, frequency_scale=2.0)\n" "\n" " Returns the turbulence vector from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg octaves: The number of different noise frequencies used.\n" " :type octaves: int\n" " :arg hard: Specifies whether returned turbulence is hard (sharp transitions) or soft (smooth transitions).\n" " :type hard: :boolean\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in mathutils.noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :arg amplitude_scale: The amplitude scaling factor.\n" " :type amplitude_scale: float\n" " :arg frequency_scale: The frequency scaling factor\n" -" :type frequency_scale: Value in noise.types or int\n" +" :type frequency_scale: float\n" " :return: The turbulence vector.\n" " :rtype: :class:`mathutils.Vector`\n" ); -static PyObject *M_Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "", "noise_basis", "amplitude_scale", "frequency_scale", NULL}; PyObject *value; float vec[3], r_vec[3]; - int oct, hd, nb = 1; + const char *noise_basis_str = NULL; + int oct, hd, noise_basis_enum = DEFAULT_NOISE_TYPE; float as = 0.5f, fs = 2.0f; - if (!PyArg_ParseTuple(args, "Oii|iff:turbulence_vector", &value, &oct, &hd, &nb, &as, &fs)) + + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Oii|$sff:turbulence_vector", (char **)kwlist, + &value, &oct, &hd, &noise_basis_str, &as, &fs)) + { return NULL; + } + + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "turbulence_vector") == -1) + { + return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "turbulence_vector: invalid 'position' arg") == -1) return NULL; - vTurb(vec[0], vec[1], vec[2], oct, hd, nb, as, fs, r_vec); + vTurb(vec[0], vec[1], vec[2], oct, hd, noise_basis_enum, as, fs, r_vec); + return Vector_CreatePyObject(r_vec, 3, NULL); } /* F. Kenton Musgrave's fractal functions */ PyDoc_STRVAR(M_Noise_fractal_doc, -".. function:: fractal(position, H, lacunarity, octaves, noise_basis=noise.types.STDPERLIN)\n" +".. function:: fractal(position, H, lacunarity, octaves, noise_basis='PERLIN_ORIGINAL')\n" "\n" " Returns the fractal Brownian motion (fBm) noise value from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg H: The fractal increment factor.\n" " :type H: float\n" @@ -514,33 +620,47 @@ PyDoc_STRVAR(M_Noise_fractal_doc, " :type lacunarity: float\n" " :arg octaves: The number of different noise frequencies used.\n" " :type octaves: int\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :return: The fractal Brownian motion noise value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_fractal(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "", "", "noise_basis", NULL}; PyObject *value; float vec[3]; + const char *noise_basis_str = NULL; float H, lac, oct; - int nb = 1; + int noise_basis_enum = DEFAULT_NOISE_TYPE; - if (!PyArg_ParseTuple(args, "Offf|i:fractal", &value, &H, &lac, &oct, &nb)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Offf|$s:fractal", (char **)kwlist, + &value, &H, &lac, &oct, &noise_basis_str)) + { return NULL; + } + + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "fractal") == -1) + { + return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "fractal: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble(mg_fBm(vec[0], vec[1], vec[2], H, lac, oct, nb)); + return PyFloat_FromDouble(mg_fBm(vec[0], vec[1], vec[2], H, lac, oct, noise_basis_enum)); } PyDoc_STRVAR(M_Noise_multi_fractal_doc, -".. function:: multi_fractal(position, H, lacunarity, octaves, noise_basis=noise.types.STDPERLIN)\n" +".. function:: multi_fractal(position, H, lacunarity, octaves, noise_basis='PERLIN_ORIGINAL')\n" "\n" " Returns multifractal noise value from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg H: The fractal increment factor.\n" " :type H: float\n" @@ -548,65 +668,107 @@ PyDoc_STRVAR(M_Noise_multi_fractal_doc, " :type lacunarity: float\n" " :arg octaves: The number of different noise frequencies used.\n" " :type octaves: int\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :return: The multifractal noise value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_multi_fractal(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_multi_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "", "", "noise_basis", NULL}; PyObject *value; float vec[3]; + const char *noise_basis_str = NULL; float H, lac, oct; - int nb = 1; + int noise_basis_enum = DEFAULT_NOISE_TYPE; + + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Offf|$s:multi_fractal", (char **)kwlist, + &value, &H, &lac, &oct, &noise_basis_str)) + { + return NULL; + } - if (!PyArg_ParseTuple(args, "Offf|i:multi_fractal", &value, &H, &lac, &oct, &nb)) + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "multi_fractal") == -1) + { return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "multi_fractal: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble(mg_MultiFractal(vec[0], vec[1], vec[2], H, lac, oct, nb)); + return PyFloat_FromDouble(mg_MultiFractal(vec[0], vec[1], vec[2], H, lac, oct, noise_basis_enum)); } PyDoc_STRVAR(M_Noise_variable_lacunarity_doc, -".. function:: variable_lacunarity(position, distortion, noise_type1=noise.types.STDPERLIN, noise_type2=noise.types.STDPERLIN)\n" +".. function:: variable_lacunarity(position, distortion, noise_type1='PERLIN_ORIGINAL', noise_type2='PERLIN_ORIGINAL')\n" "\n" " Returns variable lacunarity noise value, a distorted variety of noise, from noise type 1 distorted by noise type 2 at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg distortion: The amount of distortion.\n" " :type distortion: float\n" -" :arg noise_type1: The type of noise to be distorted.\n" -" :type noise_type1: Value in noise.types or int\n" -" :arg noise_type2: The type of noise used to distort noise_type1.\n" -" :type noise_type2: Value in noise.types or int\n" +" :arg noise_type1: Enumerator in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', " \ + "'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', " \ + "'CELLNOISE'].\n" +" :type noise_type1: string\n" +" :arg noise_type2: Enumerator in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', " \ + "'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', " \ + "'CELLNOISE'].\n" +" :type noise_type2: string\n" " :return: The variable lacunarity noise value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_variable_lacunarity(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_variable_lacunarity(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "noise_type1", "noise_type2", NULL}; PyObject *value; float vec[3]; + const char *noise_type1_str = NULL, *noise_type2_str = NULL; float d; - int nt1 = 1, nt2 = 1; + int noise_type1_enum = DEFAULT_NOISE_TYPE, noise_type2_enum = DEFAULT_NOISE_TYPE; - if (!PyArg_ParseTuple(args, "Of|ii:variable_lacunarity", &value, &d, &nt1, &nt2)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Of|$ss:variable_lacunarity", (char **)kwlist, + &value, &d, &noise_type1_str, &noise_type2_str)) + { return NULL; + } + + if (!noise_type1_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_type1_str, &noise_type1_enum, "variable_lacunarity") == -1) + { + return NULL; + } + + if (!noise_type2_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_type2_str, &noise_type2_enum, "variable_lacunarity") == -1) + { + return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "variable_lacunarity: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble(mg_VLNoise(vec[0], vec[1], vec[2], d, nt1, nt2)); + return PyFloat_FromDouble(mg_VLNoise(vec[0], vec[1], vec[2], d, noise_type1_enum, noise_type2_enum)); } PyDoc_STRVAR(M_Noise_hetero_terrain_doc, -".. function:: hetero_terrain(position, H, lacunarity, octaves, offset, noise_basis=noise.types.STDPERLIN)\n" +".. function:: hetero_terrain(position, H, lacunarity, octaves, offset, noise_basis='PERLIN_ORIGINAL')\n" "\n" " Returns the heterogeneous terrain value from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg H: The fractal dimension of the roughest areas.\n" " :type H: float\n" @@ -616,33 +778,47 @@ PyDoc_STRVAR(M_Noise_hetero_terrain_doc, " :type octaves: int\n" " :arg offset: The height of the terrain above 'sea level'.\n" " :type offset: float\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :return: The heterogeneous terrain value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_hetero_terrain(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_hetero_terrain(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "", "", "", "noise_basis", NULL}; PyObject *value; float vec[3]; + const char *noise_basis_str = NULL; float H, lac, oct, ofs; - int nb = 1; + int noise_basis_enum = DEFAULT_NOISE_TYPE; - if (!PyArg_ParseTuple(args, "Offff|i:hetero_terrain", &value, &H, &lac, &oct, &ofs, &nb)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Offff|$s:hetero_terrain", (char **)kwlist, + &value, &H, &lac, &oct, &ofs, &noise_basis_str)) + { + return NULL; + } + + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "hetero_terrain") == -1) + { return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "hetero_terrain: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble(mg_HeteroTerrain(vec[0], vec[1], vec[2], H, lac, oct, ofs, nb)); + return PyFloat_FromDouble(mg_HeteroTerrain(vec[0], vec[1], vec[2], H, lac, oct, ofs, noise_basis_enum)); } PyDoc_STRVAR(M_Noise_hybrid_multi_fractal_doc, -".. function:: hybrid_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis=noise.types.STDPERLIN)\n" +".. function:: hybrid_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis='PERLIN_ORIGINAL')\n" "\n" " Returns hybrid multifractal value from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg H: The fractal dimension of the roughest areas.\n" " :type H: float\n" @@ -654,33 +830,47 @@ PyDoc_STRVAR(M_Noise_hybrid_multi_fractal_doc, " :type offset: float\n" " :arg gain: Scaling applied to the values.\n" " :type gain: float\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :return: The hybrid multifractal value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_hybrid_multi_fractal(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_hybrid_multi_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "", "", "", "", "noise_basis", NULL}; PyObject *value; float vec[3]; + const char *noise_basis_str = NULL; float H, lac, oct, ofs, gn; - int nb = 1; + int noise_basis_enum = DEFAULT_NOISE_TYPE; - if (!PyArg_ParseTuple(args, "Offfff|i:hybrid_multi_fractal", &value, &H, &lac, &oct, &ofs, &gn, &nb)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Offfff|$s:hybrid_multi_fractal", (char **)kwlist, + &value, &H, &lac, &oct, &ofs, &gn, &noise_basis_str)) + { return NULL; + } + + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "hybrid_multi_fractal") == -1) + { + return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "hybrid_multi_fractal: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble(mg_HybridMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, nb)); + return PyFloat_FromDouble(mg_HybridMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, noise_basis_enum)); } PyDoc_STRVAR(M_Noise_ridged_multi_fractal_doc, -".. function:: ridged_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis=noise.types.STDPERLIN)\n" +".. function:: ridged_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis='PERLIN_ORIGINAL')\n" "\n" " Returns ridged multifractal value from the noise basis at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :arg H: The fractal dimension of the roughest areas.\n" " :type H: float\n" @@ -692,67 +882,94 @@ PyDoc_STRVAR(M_Noise_ridged_multi_fractal_doc, " :type offset: float\n" " :arg gain: Scaling applied to the values.\n" " :type gain: float\n" -" :arg noise_basis: The type of noise to be evaluated.\n" -" :type noise_basis: Value in noise.types or int\n" +BPY_NOISE_BASIS_ENUM_DOC " :return: The ridged multifractal value.\n" " :rtype: float\n" ); -static PyObject *M_Noise_ridged_multi_fractal(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_ridged_multi_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "", "", "", "", "", "noise_basis", NULL}; PyObject *value; float vec[3]; + const char *noise_basis_str = NULL; float H, lac, oct, ofs, gn; - int nb = 1; + int noise_basis_enum = DEFAULT_NOISE_TYPE; + + if (!PyArg_ParseTupleAndKeywords( + args, kw, "Offfff|$s:ridged_multi_fractal", (char **)kwlist, + &value, &H, &lac, &oct, &ofs, &gn, &noise_basis_str)) + { + return NULL; + } - if (!PyArg_ParseTuple(args, "Offfff|i:ridged_multi_fractal", &value, &H, &lac, &oct, &ofs, &gn, &nb)) + if (!noise_basis_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_types, noise_basis_str, &noise_basis_enum, "ridged_multi_fractal") == -1) + { return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "ridged_multi_fractal: invalid 'position' arg") == -1) return NULL; - return PyFloat_FromDouble(mg_RidgedMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, nb)); + return PyFloat_FromDouble(mg_RidgedMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, noise_basis_enum)); } PyDoc_STRVAR(M_Noise_voronoi_doc, -".. function:: voronoi(position, distance_metric=noise.distance_metrics.DISTANCE, exponent=2.5)\n" +".. function:: voronoi(position, distance_metric='DISTANCE', exponent=2.5)\n" "\n" " Returns a list of distances to the four closest features and their locations.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" -" :arg distance_metric: Method of measuring distance.\n" -" :type distance_metric: Value in noise.distance_metrics or int\n" +BPY_NOISE_METRIC_ENUM_DOC " :arg exponent: The exponent for Minkowski distance metric.\n" " :type exponent: float\n" " :return: A list of distances to the four closest features and their locations.\n" " :rtype: list of four floats, list of four :class:`mathutils.Vector` types\n" ); -static PyObject *M_Noise_voronoi(PyObject *UNUSED(self), PyObject *args) +static PyObject *M_Noise_voronoi(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"", "distance_metric", "exponent", NULL}; PyObject *value; PyObject *list; PyObject *ret; float vec[3]; + const char *metric_str = NULL; float da[4], pa[12]; - int dtype = 0; + int metric_enum = DEFAULT_METRIC_TYPE; float me = 2.5f; /* default minkowski exponent */ int i; - if (!PyArg_ParseTuple(args, "O|if:voronoi", &value, &dtype, &me)) + if (!PyArg_ParseTupleAndKeywords( + args, kw, "O|$sf:voronoi", (char **)kwlist, + &value, &metric_str, &me)) + { return NULL; + } + + if (!metric_str) { + /* pass through */ + } + else if (PyC_FlagSet_ValueFromID( + bpy_noise_metrics, metric_str, &metric_enum, "voronoi") == -1) + { + return NULL; + } if (mathutils_array_parse(vec, 3, 3, value, "voronoi: invalid 'position' arg") == -1) return NULL; list = PyList_New(4); - voronoi(vec[0], vec[1], vec[2], da, pa, me, dtype); + voronoi(vec[0], vec[1], vec[2], da, pa, me, metric_enum); for (i = 0; i < 4; i++) { PyObject *v = Vector_CreatePyObject(pa + 3 * i, 3, NULL); PyList_SET_ITEM(list, i, v); - Py_DECREF(v); } ret = Py_BuildValue("[[ffff]O]", da[0], da[1], da[2], da[3], list); @@ -765,7 +982,7 @@ PyDoc_STRVAR(M_Noise_cell_doc, "\n" " Returns cell noise value at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :return: The cell noise value.\n" " :rtype: float\n" @@ -789,7 +1006,7 @@ PyDoc_STRVAR(M_Noise_cell_vector_doc, "\n" " Returns cell noise vector at the specified position.\n" "\n" -" :arg position: The position to evaluate the selected noise function at.\n" +" :arg position: The position to evaluate the selected noise function.\n" " :type position: :class:`mathutils.Vector`\n" " :return: The cell noise vector.\n" " :rtype: :class:`mathutils.Vector`\n" @@ -812,19 +1029,19 @@ static PyObject *M_Noise_cell_vector(PyObject *UNUSED(self), PyObject *args) static PyMethodDef M_Noise_methods[] = { {"seed_set", (PyCFunction) M_Noise_seed_set, METH_VARARGS, M_Noise_seed_set_doc}, {"random", (PyCFunction) M_Noise_random, METH_NOARGS, M_Noise_random_doc}, - {"random_unit_vector", (PyCFunction) M_Noise_random_unit_vector, METH_VARARGS, M_Noise_random_unit_vector_doc}, - /*{"random_vector", (PyCFunction) M_Noise_random_vector, METH_VARARGS, M_Noise_random_vector_doc},*/ - {"noise", (PyCFunction) M_Noise_noise, METH_VARARGS, M_Noise_noise_doc}, - {"noise_vector", (PyCFunction) M_Noise_noise_vector, METH_VARARGS, M_Noise_noise_vector_doc}, - {"turbulence", (PyCFunction) M_Noise_turbulence, METH_VARARGS, M_Noise_turbulence_doc}, - {"turbulence_vector", (PyCFunction) M_Noise_turbulence_vector, METH_VARARGS, M_Noise_turbulence_vector_doc}, - {"fractal", (PyCFunction) M_Noise_fractal, METH_VARARGS, M_Noise_fractal_doc}, - {"multi_fractal", (PyCFunction) M_Noise_multi_fractal, METH_VARARGS, M_Noise_multi_fractal_doc}, - {"variable_lacunarity", (PyCFunction) M_Noise_variable_lacunarity, METH_VARARGS, M_Noise_variable_lacunarity_doc}, - {"hetero_terrain", (PyCFunction) M_Noise_hetero_terrain, METH_VARARGS, M_Noise_hetero_terrain_doc}, - {"hybrid_multi_fractal", (PyCFunction) M_Noise_hybrid_multi_fractal, METH_VARARGS, M_Noise_hybrid_multi_fractal_doc}, - {"ridged_multi_fractal", (PyCFunction) M_Noise_ridged_multi_fractal, METH_VARARGS, M_Noise_ridged_multi_fractal_doc}, - {"voronoi", (PyCFunction) M_Noise_voronoi, METH_VARARGS, M_Noise_voronoi_doc}, + {"random_unit_vector", (PyCFunction) M_Noise_random_unit_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_random_unit_vector_doc}, + {"random_vector", (PyCFunction) M_Noise_random_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_random_vector_doc}, + {"noise", (PyCFunction) M_Noise_noise, METH_VARARGS | METH_KEYWORDS, M_Noise_noise_doc}, + {"noise_vector", (PyCFunction) M_Noise_noise_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_noise_vector_doc}, + {"turbulence", (PyCFunction) M_Noise_turbulence, METH_VARARGS | METH_KEYWORDS, M_Noise_turbulence_doc}, + {"turbulence_vector", (PyCFunction) M_Noise_turbulence_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_turbulence_vector_doc}, + {"fractal", (PyCFunction) M_Noise_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_fractal_doc}, + {"multi_fractal", (PyCFunction) M_Noise_multi_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_multi_fractal_doc}, + {"variable_lacunarity", (PyCFunction) M_Noise_variable_lacunarity, METH_VARARGS | METH_KEYWORDS, M_Noise_variable_lacunarity_doc}, + {"hetero_terrain", (PyCFunction) M_Noise_hetero_terrain, METH_VARARGS | METH_KEYWORDS, M_Noise_hetero_terrain_doc}, + {"hybrid_multi_fractal", (PyCFunction) M_Noise_hybrid_multi_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_hybrid_multi_fractal_doc}, + {"ridged_multi_fractal", (PyCFunction) M_Noise_ridged_multi_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_ridged_multi_fractal_doc}, + {"voronoi", (PyCFunction) M_Noise_voronoi, METH_VARARGS | METH_KEYWORDS, M_Noise_voronoi_doc}, {"cell", (PyCFunction) M_Noise_cell, METH_VARARGS, M_Noise_cell_doc}, {"cell_vector", (PyCFunction) M_Noise_cell_vector, METH_VARARGS, M_Noise_cell_vector_doc}, {NULL, NULL, 0, NULL} @@ -845,78 +1062,10 @@ static struct PyModuleDef M_Noise_module_def = { /*----------------------------MODULE INIT-------------------------*/ PyMODINIT_FUNC PyInit_mathutils_noise(void) { - PyObject *sys_modules = PyImport_GetModuleDict(); PyObject *submodule = PyModule_Create(&M_Noise_module_def); - PyObject *item_types, *item_metrics; /* use current time as seed for random number generator by default */ setRndSeed(0); - PyModule_AddObject(submodule, "types", (item_types = PyInit_mathutils_noise_types())); - PyDict_SetItemString(sys_modules, "noise.types", item_types); - Py_INCREF(item_types); - - PyModule_AddObject(submodule, "distance_metrics", (item_metrics = PyInit_mathutils_noise_metrics())); - PyDict_SetItemString(sys_modules, "noise.distance_metrics", item_metrics); - Py_INCREF(item_metrics); - - return submodule; -} - -/*----------------------------SUBMODULE INIT-------------------------*/ -static struct PyModuleDef M_NoiseTypes_module_def = { - PyModuleDef_HEAD_INIT, - "mathutils.noise.types", /* m_name */ - NULL, /* m_doc */ - 0, /* m_size */ - NULL, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; - -PyMODINIT_FUNC PyInit_mathutils_noise_types(void) -{ - PyObject *submodule = PyModule_Create(&M_NoiseTypes_module_def); - - PyModule_AddIntConstant(submodule, "BLENDER", TEX_BLENDER); - PyModule_AddIntConstant(submodule, "STDPERLIN", TEX_STDPERLIN); - PyModule_AddIntConstant(submodule, "NEWPERLIN", TEX_NEWPERLIN); - PyModule_AddIntConstant(submodule, "VORONOI_F1", TEX_VORONOI_F1); - PyModule_AddIntConstant(submodule, "VORONOI_F2", TEX_VORONOI_F2); - PyModule_AddIntConstant(submodule, "VORONOI_F3", TEX_VORONOI_F3); - PyModule_AddIntConstant(submodule, "VORONOI_F4", TEX_VORONOI_F4); - PyModule_AddIntConstant(submodule, "VORONOI_F2F1", TEX_VORONOI_F2F1); - PyModule_AddIntConstant(submodule, "VORONOI_CRACKLE", TEX_VORONOI_CRACKLE); - PyModule_AddIntConstant(submodule, "CELLNOISE", TEX_CELLNOISE); - - return submodule; -} - -static struct PyModuleDef M_NoiseMetrics_module_def = { - PyModuleDef_HEAD_INIT, - "mathutils.noise.distance_metrics", /* m_name */ - NULL, /* m_doc */ - 0, /* m_size */ - NULL, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ -}; - -PyMODINIT_FUNC PyInit_mathutils_noise_metrics(void) -{ - PyObject *submodule = PyModule_Create(&M_NoiseMetrics_module_def); - - PyModule_AddIntConstant(submodule, "DISTANCE", TEX_DISTANCE); - PyModule_AddIntConstant(submodule, "DISTANCE_SQUARED", TEX_DISTANCE_SQUARED); - PyModule_AddIntConstant(submodule, "MANHATTAN", TEX_MANHATTAN); - PyModule_AddIntConstant(submodule, "CHEBYCHEV", TEX_CHEBYCHEV); - PyModule_AddIntConstant(submodule, "MINKOVSKY_HALF", TEX_MINKOVSKY_HALF); - PyModule_AddIntConstant(submodule, "MINKOVSKY_FOUR", TEX_MINKOVSKY_FOUR); - PyModule_AddIntConstant(submodule, "MINKOVSKY", TEX_MINKOVSKY); - return submodule; } diff --git a/source/blender/python/mathutils/mathutils_noise.h b/source/blender/python/mathutils/mathutils_noise.h index f2218b28f8f..469cd9636e6 100644 --- a/source/blender/python/mathutils/mathutils_noise.h +++ b/source/blender/python/mathutils/mathutils_noise.h @@ -28,7 +28,5 @@ #define __MATHUTILS_NOISE_H__ PyMODINIT_FUNC PyInit_mathutils_noise(void); -PyMODINIT_FUNC PyInit_mathutils_noise_types(void); -PyMODINIT_FUNC PyInit_mathutils_noise_metrics(void); #endif /* __MATHUTILS_NOISE_H__ */ diff --git a/source/blender/python/simple_enum_gen.py b/source/blender/python/simple_enum_gen.py index 4f3159b9b25..3a9c1847fc7 100644 --- a/source/blender/python/simple_enum_gen.py +++ b/source/blender/python/simple_enum_gen.py @@ -34,7 +34,7 @@ defs = """ SPACE_ACTION, SPACE_NLA, SPACE_SCRIPT, #Deprecated - SPACE_TIME, + SPACE_TIME, #Deprecated SPACE_NODE, SPACEICONMAX """ |