From e084874db7d05be84303c551b46179a7b115fb3c Mon Sep 17 00:00:00 2001 From: Jaume Bellet Date: Mon, 20 Nov 2023 23:02:08 +0100 Subject: [PATCH] added mb-0014 and mb-0015 --- mblender/applied/mb-0008-mblender-core.patch | 6 +- mblender/applied/mb-0014-bpy-images.patch | 319 ++++++++++++++++++ mblender/applied/mb-0015-image-ui.patch | 99 ++++++ mblender/apply.py | 24 -- mblender/patches.py | 3 +- mblender/unapply.py | 17 - scripts/modules/bpy/utils/images.py | 49 +++ .../blender/editors/include/UI_interface_c.hh | 3 + .../editors/interface/interface_templates.cc | 27 ++ source/blender/makesrna/intern/rna_ui_api.cc | 15 + source/blender/mblender/patches/MB_0014.h | 1 + source/blender/mblender/patches/MB_0015.h | 1 + source/blender/python/BPY_extern.h | 2 + source/blender/python/intern/CMakeLists.txt | 2 + source/blender/python/intern/bpy.cc | 2 + .../blender/python/intern/bpy_utils_images.cc | 173 ++++++++++ .../blender/python/intern/bpy_utils_images.h | 19 ++ 17 files changed, 717 insertions(+), 45 deletions(-) create mode 100644 mblender/applied/mb-0014-bpy-images.patch create mode 100644 mblender/applied/mb-0015-image-ui.patch delete mode 100644 mblender/apply.py delete mode 100644 mblender/unapply.py create mode 100644 scripts/modules/bpy/utils/images.py create mode 100644 source/blender/mblender/patches/MB_0014.h create mode 100644 source/blender/mblender/patches/MB_0015.h create mode 100644 source/blender/python/intern/bpy_utils_images.cc create mode 100644 source/blender/python/intern/bpy_utils_images.h diff --git a/mblender/applied/mb-0008-mblender-core.patch b/mblender/applied/mb-0008-mblender-core.patch index 2eabe81de76..dc7cf6b63f4 100644 --- a/mblender/applied/mb-0008-mblender-core.patch +++ b/mblender/applied/mb-0008-mblender-core.patch @@ -354,12 +354,12 @@ index ab73ab435ca..cba61b7a15d 100644 if(HAVE_FEENABLEEXCEPT) diff --git a/source/creator/creator.cc b/source/creator/creator.cc -index 7e6815ee286..3fe843a6a5c 100644 +index 70c7003661d..ad44b3048ad 100644 --- a/source/creator/creator.cc +++ b/source/creator/creator.cc @@ -57,6 +57,8 @@ #include "BKE_vfont.h" - #include "BKE_volume.h" + #include "BKE_volume.hh" +#include "MB_blender.h" + @@ -376,7 +376,7 @@ index 7e6815ee286..3fe843a6a5c 100644 /* The settings pass includes: * - Background-mode assignment (#Global.background), checked by other subsystems diff --git a/source/creator/creator_args.cc b/source/creator/creator_args.cc -index 502f7f37267..6dd68668b18 100644 +index b13875d19de..84d66f7312b 100644 --- a/source/creator/creator_args.cc +++ b/source/creator/creator_args.cc @@ -47,6 +47,8 @@ diff --git a/mblender/applied/mb-0014-bpy-images.patch b/mblender/applied/mb-0014-bpy-images.patch new file mode 100644 index 00000000000..7393bccba88 --- /dev/null +++ b/mblender/applied/mb-0014-bpy-images.patch @@ -0,0 +1,319 @@ +diff --git a/scripts/modules/bpy/utils/images.py b/scripts/modules/bpy/utils/images.py +new file mode 100644 +index 00000000000..b4bd02b395c +--- /dev/null ++++ b/scripts/modules/bpy/utils/images.py +@@ -0,0 +1,49 @@ ++# SPDX-FileCopyrightText: 2015-2023 Blender Authors ++# ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++""" ++This module contains utility functions to handle custom images. ++""" ++ ++__all__ = ( ++ "load", ++ "release" ++ "list", ++) ++ ++from _bpy import _utils_images ++ ++ ++list = [] ++ ++ ++def load(name, path): ++ r = _utils_images.load(name, path) ++ if r != None: ++ data = {'id' : r , 'name' : name, 'path' : path} ++ list.append(data) ++ return data; ++ else: ++ return None; ++ ++load.__doc__ = _utils_images.load.__doc__; ++ ++def release(image_id): ++ r = _utils_images.release(image_id) ++ if r == True: ++ for data in list: ++ if data.get('id') == image_id: ++ list.remove(data) ++ ++ return r; ++release.__doc__ = _utils_images.release.__doc__ ++ ++import atexit ++ ++def exit_clear(): ++ while len(list): ++ release(list[0].get('id')) ++ ++atexit.register(exit_clear) ++del atexit, exit_clear +diff --git a/source/blender/mblender/patches/MB_0014.h b/source/blender/mblender/patches/MB_0014.h +new file mode 100644 +index 00000000000..ddf2a41c228 +--- /dev/null ++++ b/source/blender/mblender/patches/MB_0014.h +@@ -0,0 +1 @@ ++/* Empty File */ +diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h +index db70947b683..3a00f2767f2 100644 +--- a/source/blender/python/BPY_extern.h ++++ b/source/blender/python/BPY_extern.h +@@ -133,6 +133,8 @@ bool BPY_string_is_keyword(const char *str); + void BPY_callback_screen_free(struct ARegionType *art); + void BPY_callback_wm_free(struct wmWindowManager *wm); + ++void* BPY_utils_images_get(int image_id); ++ + /* I18n for addons */ + #ifdef WITH_INTERNATIONAL + const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid); +diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt +index fd5a04369b7..3a364ff773e 100644 +--- a/source/blender/python/intern/CMakeLists.txt ++++ b/source/blender/python/intern/CMakeLists.txt +@@ -70,6 +70,7 @@ set(SRC + bpy_rna_ui.cc + bpy_traceback.cc + bpy_utils_previews.cc ++ bpy_utils_images.cc + bpy_utils_units.cc + stubs.cc + +@@ -112,6 +113,7 @@ set(SRC + bpy_rna_ui.h + bpy_traceback.h + bpy_utils_previews.h ++ bpy_utils_images.h + bpy_utils_units.h + ../BPY_extern.h + ../BPY_extern_clog.h +diff --git a/source/blender/python/intern/bpy.cc b/source/blender/python/intern/bpy.cc +index 30568703cc3..9ba51867d28 100644 +--- a/source/blender/python/intern/bpy.cc ++++ b/source/blender/python/intern/bpy.cc +@@ -46,6 +46,7 @@ + #include "bpy_rna_id_collection.h" + #include "bpy_rna_types_capi.h" + #include "bpy_utils_previews.h" ++#include "bpy_utils_images.h" + #include "bpy_utils_units.h" + + #include "../generic/py_capi_utils.h" +@@ -686,6 +687,7 @@ void BPy_init_modules(bContext *C) + 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, "_utils_images", BPY_utils_images_module()); + PyModule_AddObject(mod, "msgbus", BPY_msgbus_module()); + + PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, C); +diff --git a/source/blender/python/intern/bpy_utils_images.cc b/source/blender/python/intern/bpy_utils_images.cc +new file mode 100644 +index 00000000000..a35ae852fb7 +--- /dev/null ++++ b/source/blender/python/intern/bpy_utils_images.cc +@@ -0,0 +1,173 @@ ++/* SPDX-FileCopyrightText: 2023 Blender Authors ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/** \file ++ * \ingroup pythonintern ++ * ++ * This file defines a singleton py object accessed via 'bpy.utils.images', ++ */ ++ ++#include ++#include ++ ++#include ++ ++#include "BLI_utildefines.h" ++#include "BLI_listbase.h" ++#include "BLI_string.h" ++ ++#include "RNA_access.hh" ++#include "RNA_prototypes.h" ++#include "RNA_types.hh" ++ ++#include "BPY_extern.h" ++#include "bpy_rna.h" ++#include "bpy_utils_images.h" ++ ++#include "../generic/py_capi_utils.h" ++ ++#include "MEM_guardedalloc.h" ++ ++#include "IMB_imbuf.h" ++ ++#include "../generic/python_utildefines.h" ++ ++ ++struct bpy_image_data{ ++ bpy_image_data *prev; ++ bpy_image_data *next; ++ ++ int id; ++ ImBuf *ibuf; ++ std::string name; ++ std::string path; ++}; ++ ++int bpy_images_last_id = 0; ++ListBase bpy_images_list; ++ ++ ++bpy_image_data* BPY_utils_images_get_data(int image_id) { ++ return (bpy_image_data *)BLI_listbase_bytes_find( ++ &bpy_images_list, &image_id, sizeof(int), sizeof(bpy_image_data *) * 2); ++} ++ ++void* BPY_utils_images_get(int image_id) ++{ ++ bpy_image_data *el = BPY_utils_images_get_data(image_id); ++ return (el != nullptr) ? el->ibuf : nullptr; ++} ++ ++PyDoc_STRVAR(bpy_utils_images_load_doc, ++ ".. method:: load(name, filepath)\n" ++ "\n" ++ " Generate a new preview from given file path.\n" ++ "\n" ++ " :arg name: The name identifying the image.\n" ++ " :type name: string\n" ++ " :arg filepath: The file path to the image.\n" ++ " :type filepath: string or bytes\n" ++ " :return: image id.\n" ++ " :rtype: long`\n"); ++static PyObject *bpy_utils_images_load(PyObject * /*self*/, PyObject *args) ++{ ++ char *name = NULL; ++ PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr}; ++ ++ if (!PyArg_ParseTuple(args, ++ "s" /* `name` */ ++ "O&" /* `filepath` */ ++ ":load", ++ &name, ++ PyC_ParseUnicodeAsBytesAndSize, ++ &filepath_data, ++ 0)) ++ { ++ return nullptr; ++ } ++ ++ if (!filepath_data.value || !name) { ++ Py_RETURN_NONE; ++ } ++ ++ ImBuf *ibuf = IMB_loadiffname(filepath_data.value, 0, nullptr); ++ ++ if (ibuf) { ++ bpy_image_data *data = MEM_new(__func__); ++ data->id = ++bpy_images_last_id; ++ data->ibuf = ibuf; ++ data->name = name; ++ data->path = filepath_data.value; ++ ++ BLI_addtail(&bpy_images_list, data); ++ ++ return PyLong_FromLong(data->id); ++ } ++ else { ++ Py_RETURN_NONE; ++ } ++} ++ ++PyDoc_STRVAR(bpy_utils_images_release_doc, ++ ".. method:: release(image_id)\n" ++ "\n" ++ " Release (free) a previously added image.\n" ++ "\n" ++ "\n" ++ " :arg image_id: The id identifying the image.\n" ++ " :type name: long\n" ++ " :return: true if release.\n" ++ " :rtype: bool`\n"); ++static PyObject *bpy_utils_images_release(PyObject * /*self*/, PyObject *args) ++{ ++ int image_id = -1; ++ ++ if (!PyArg_ParseTuple(args, "i:release", &image_id)) { ++ return nullptr; ++ } ++ ++ bpy_image_data *el = BPY_utils_images_get_data(image_id); ++ ++ if (el != nullptr) { ++ BLI_remlink(&bpy_images_list, el); ++ IMB_freeImBuf(el->ibuf); ++ MEM_freeN(el); ++ Py_RETURN_TRUE; ++ } ++ else { ++ Py_RETURN_FALSE; ++ } ++} ++ ++static PyMethodDef bpy_utils_images_methods[] = { ++ /* Can't use METH_KEYWORDS alone, see http://bugs.python.org/issue11587 */ ++ {"load", (PyCFunction)bpy_utils_images_load, METH_VARARGS, bpy_utils_images_load_doc}, ++ {"release",(PyCFunction)bpy_utils_images_release,METH_VARARGS, bpy_utils_images_release_doc}, ++ {nullptr, nullptr, 0, nullptr}, ++}; ++ ++PyDoc_STRVAR( ++ bpy_utils_images_doc, ++ "This object contains basic static methods to handle cached (non-ID) previews in Blender\n" ++ "(low-level API, not exposed to final users)."); ++static PyModuleDef bpy_utils_images_module = { ++ /*m_base*/ PyModuleDef_HEAD_INIT, ++ /*m_name*/ "bpy._utils_images", ++ /*m_doc*/ bpy_utils_images_doc, ++ /*m_size*/ 0, ++ /*m_methods*/ bpy_utils_images_methods, ++ /*m_slots*/ nullptr, ++ /*m_traverse*/ nullptr, ++ /*m_clear*/ nullptr, ++ /*m_free*/ nullptr, ++}; ++ ++PyObject *BPY_utils_images_module() ++{ ++ PyObject *submodule; ++ ++ submodule = PyModule_Create(&bpy_utils_images_module); ++ ++ return submodule; ++} +diff --git a/source/blender/python/intern/bpy_utils_images.h b/source/blender/python/intern/bpy_utils_images.h +new file mode 100644 +index 00000000000..6e27babe26a +--- /dev/null ++++ b/source/blender/python/intern/bpy_utils_images.h +@@ -0,0 +1,19 @@ ++/* SPDX-FileCopyrightText: 2023 Blender Authors ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++/** \file ++ * \ingroup pythonintern ++ */ ++ ++#pragma once ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++PyObject *BPY_utils_images_module(void); ++ ++#ifdef __cplusplus ++} ++#endif diff --git a/mblender/applied/mb-0015-image-ui.patch b/mblender/applied/mb-0015-image-ui.patch new file mode 100644 index 00000000000..aec1c4f41b8 --- /dev/null +++ b/mblender/applied/mb-0015-image-ui.patch @@ -0,0 +1,99 @@ +diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh +index b736a2d7cf0..a2b5bf9b6b0 100644 +--- a/source/blender/editors/include/UI_interface_c.hh ++++ b/source/blender/editors/include/UI_interface_c.hh +@@ -2433,6 +2433,9 @@ void uiTemplatePreview(uiLayout *layout, + MTex *slot, + const char *preview_id); + void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, bool expand); ++ ++void uiTemplateImageUI(uiLayout *layout, int image_id, float image_scale); ++ + /** + * \param icon_scale: Scale of the icon, 1x == button height. + */ +diff --git a/source/blender/editors/interface/interface_templates.cc b/source/blender/editors/interface/interface_templates.cc +index 16bd571818b..db80180a653 100644 +--- a/source/blender/editors/interface/interface_templates.cc ++++ b/source/blender/editors/interface/interface_templates.cc +@@ -78,6 +78,9 @@ + #include "ED_render.hh" + #include "ED_screen.hh" + #include "ED_undo.hh" ++#include "ED_datafiles.h" ++ ++#include "IMB_imbuf.h" + + #include "RE_engine.h" + +@@ -93,6 +96,8 @@ + #include "UI_view2d.hh" + #include "interface_intern.hh" + ++#include "BPY_extern.h" ++ + #include "PIL_time.h" + + /* we may want to make this optional, disable for now. */ +@@ -3369,6 +3374,28 @@ void uiTemplatePreview(uiLayout *layout, + + /** \} */ + ++void uiTemplateImageUI(uiLayout* layout, int image_id,float image_scale) { ++ ++ ImBuf *ibuf = IMB_dupImBuf((ImBuf *) BPY_utils_images_get(image_id)); ++ ++ if (ibuf) { ++ int width = ibuf->x * image_scale; ++ int height = (width * ibuf->y) / ibuf->x; ++ ++ IMB_premultiply_alpha(ibuf); ++ IMB_scaleImBuf(ibuf, width, height); ++ ++ bTheme *btheme = UI_GetTheme(); ++ uchar *color = btheme->tui.wcol_menu_back.text_sel; ++ //color = btheme->tui.wcol_box.inner; ++ ++ uiBlock *block = uiLayoutAbsoluteBlock(layout); ++ ++ uiBut *but = uiDefButImage(block, ibuf, 0, U.widget_unit, width, height, color); ++ ++ } ++} ++ + /* -------------------------------------------------------------------- */ + /** \name ColorRamp Template + * \{ */ +diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc +index b04e1ba5c3b..88311532e05 100644 +--- a/source/blender/makesrna/intern/rna_ui_api.cc ++++ b/source/blender/makesrna/intern/rna_ui_api.cc +@@ -1666,6 +1666,21 @@ void RNA_api_ui_layout(StructRNA *srna) + 1.0f, + 100.0f); + ++ ++ func = RNA_def_function(srna, "template_image_ui", "uiTemplateImageUI"); ++ RNA_def_function_ui_description(func, "A image on UI"); ++ parm = RNA_def_int(func, "image_value", 0, 0, INT_MAX, "image to display", "", 0, INT_MAX); ++ RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); ++ RNA_def_float(func, ++ "scale", ++ 1.0f, ++ 1.0f, ++ 100.0f, ++ "Scale", ++ "Scale the icon size (by the button size)", ++ 1.0f, ++ 100.0f); ++ + func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView"); + RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews"); + api_ui_item_rna_common(func); +diff --git a/source/blender/mblender/patches/MB_0015.h b/source/blender/mblender/patches/MB_0015.h +new file mode 100644 +index 00000000000..ddf2a41c228 +--- /dev/null ++++ b/source/blender/mblender/patches/MB_0015.h +@@ -0,0 +1 @@ ++/* Empty File */ diff --git a/mblender/apply.py b/mblender/apply.py deleted file mode 100644 index 27a60b5b721..00000000000 --- a/mblender/apply.py +++ /dev/null @@ -1,24 +0,0 @@ - -import subprocess -import os - -import patches - -url = "https://mechanicalblender.org/mblender_patches/patches/" - -path = os.path.join(os.path.dirname(__file__),"applied") - -if not os.path.exists(path): - os.makedirs(path) - -for name in patches.names: - file = name + ".patch" - remote = url + file - local = os.path.join(path, file) - #curl --ssl-no-revoke https://mechanicalblender.org/mblender_patches/patches/mb-0007-transform-flags.patch > mblender\applied\mb-0007-transform-flags.patch - print (remote) - with open (local, "wb") as pfile: - subprocess.run(['curl', '--ssl-no-revoke', remote], stdout=pfile) - - subprocess.run(['git', 'apply', local]) - diff --git a/mblender/patches.py b/mblender/patches.py index 9575902bb1b..7945e654f2d 100644 --- a/mblender/patches.py +++ b/mblender/patches.py @@ -5,4 +5,5 @@ names.append("mb-0008-mblender-core") names.append("mb-0009-addon-menu-references") names.append("mb-0010-url-presets") names.append("mb-0012-custom-splash") - +names.append("mb-0014-bpy-images") +names.append("mb-0015-image-ui") diff --git a/mblender/unapply.py b/mblender/unapply.py deleted file mode 100644 index c8085ac69cf..00000000000 --- a/mblender/unapply.py +++ /dev/null @@ -1,17 +0,0 @@ -import subprocess -import os - -import patches - -path = os.path.join(os.path.dirname(__file__),"applied") - -for name in patches.names: - file = name + ".patch" - local = os.path.join(path, file) - if (os.path.isfile (local)): - subprocess.run(['git', 'apply', '-R', local]) - os.remove(local) - -os.remove (__file__) -os.remove(os.path.join(os.path.dirname(__file__), "apply.py")) -os.remove(os.path.join(os.path.dirname(__file__), "patches.py")) diff --git a/scripts/modules/bpy/utils/images.py b/scripts/modules/bpy/utils/images.py new file mode 100644 index 00000000000..b4bd02b395c --- /dev/null +++ b/scripts/modules/bpy/utils/images.py @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: 2015-2023 Blender Authors +# +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +This module contains utility functions to handle custom images. +""" + +__all__ = ( + "load", + "release" + "list", +) + +from _bpy import _utils_images + + +list = [] + + +def load(name, path): + r = _utils_images.load(name, path) + if r != None: + data = {'id' : r , 'name' : name, 'path' : path} + list.append(data) + return data; + else: + return None; + +load.__doc__ = _utils_images.load.__doc__; + +def release(image_id): + r = _utils_images.release(image_id) + if r == True: + for data in list: + if data.get('id') == image_id: + list.remove(data) + + return r; +release.__doc__ = _utils_images.release.__doc__ + +import atexit + +def exit_clear(): + while len(list): + release(list[0].get('id')) + +atexit.register(exit_clear) +del atexit, exit_clear diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index 0b8e7ce79fc..abe2704f604 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -2435,6 +2435,9 @@ void uiTemplatePreview(uiLayout *layout, MTex *slot, const char *preview_id); void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, bool expand); + +void uiTemplateImageUI(uiLayout *layout, int image_id, float image_scale); + /** * \param icon_scale: Scale of the icon, 1x == button height. */ diff --git a/source/blender/editors/interface/interface_templates.cc b/source/blender/editors/interface/interface_templates.cc index fa6f58246b2..d6d7cacf89f 100644 --- a/source/blender/editors/interface/interface_templates.cc +++ b/source/blender/editors/interface/interface_templates.cc @@ -78,6 +78,9 @@ #include "ED_render.hh" #include "ED_screen.hh" #include "ED_undo.hh" +#include "ED_datafiles.h" + +#include "IMB_imbuf.h" #include "RE_engine.h" @@ -93,6 +96,8 @@ #include "UI_view2d.hh" #include "interface_intern.hh" +#include "BPY_extern.h" + #include "PIL_time.h" /* we may want to make this optional, disable for now. */ @@ -3369,6 +3374,28 @@ void uiTemplatePreview(uiLayout *layout, /** \} */ +void uiTemplateImageUI(uiLayout* layout, int image_id,float image_scale) { + + ImBuf *ibuf = IMB_dupImBuf((ImBuf *) BPY_utils_images_get(image_id)); + + if (ibuf) { + int width = ibuf->x * image_scale; + int height = (width * ibuf->y) / ibuf->x; + + IMB_premultiply_alpha(ibuf); + IMB_scaleImBuf(ibuf, width, height); + + bTheme *btheme = UI_GetTheme(); + uchar *color = btheme->tui.wcol_menu_back.text_sel; + //color = btheme->tui.wcol_box.inner; + + uiBlock *block = uiLayoutAbsoluteBlock(layout); + + uiBut *but = uiDefButImage(block, ibuf, 0, U.widget_unit, width, height, color); + + } +} + /* -------------------------------------------------------------------- */ /** \name ColorRamp Template * \{ */ diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index ec1d51f9b0c..b83e798366a 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -1782,6 +1782,21 @@ void RNA_api_ui_layout(StructRNA *srna) 1.0f, 100.0f); + + func = RNA_def_function(srna, "template_image_ui", "uiTemplateImageUI"); + RNA_def_function_ui_description(func, "A image on UI"); + parm = RNA_def_int(func, "image_value", 0, 0, INT_MAX, "image to display", "", 0, INT_MAX); + RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); + RNA_def_float(func, + "scale", + 1.0f, + 1.0f, + 100.0f, + "Scale", + "Scale the icon size (by the button size)", + 1.0f, + 100.0f); + func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView"); RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews"); api_ui_item_rna_common(func); diff --git a/source/blender/mblender/patches/MB_0014.h b/source/blender/mblender/patches/MB_0014.h new file mode 100644 index 00000000000..ddf2a41c228 --- /dev/null +++ b/source/blender/mblender/patches/MB_0014.h @@ -0,0 +1 @@ +/* Empty File */ diff --git a/source/blender/mblender/patches/MB_0015.h b/source/blender/mblender/patches/MB_0015.h new file mode 100644 index 00000000000..ddf2a41c228 --- /dev/null +++ b/source/blender/mblender/patches/MB_0015.h @@ -0,0 +1 @@ +/* Empty File */ diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index db70947b683..3a00f2767f2 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -133,6 +133,8 @@ bool BPY_string_is_keyword(const char *str); void BPY_callback_screen_free(struct ARegionType *art); void BPY_callback_wm_free(struct wmWindowManager *wm); +void* BPY_utils_images_get(int image_id); + /* I18n for addons */ #ifdef WITH_INTERNATIONAL const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index fd5a04369b7..3a364ff773e 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -70,6 +70,7 @@ set(SRC bpy_rna_ui.cc bpy_traceback.cc bpy_utils_previews.cc + bpy_utils_images.cc bpy_utils_units.cc stubs.cc @@ -112,6 +113,7 @@ set(SRC bpy_rna_ui.h bpy_traceback.h bpy_utils_previews.h + bpy_utils_images.h bpy_utils_units.h ../BPY_extern.h ../BPY_extern_clog.h diff --git a/source/blender/python/intern/bpy.cc b/source/blender/python/intern/bpy.cc index 30568703cc3..9ba51867d28 100644 --- a/source/blender/python/intern/bpy.cc +++ b/source/blender/python/intern/bpy.cc @@ -46,6 +46,7 @@ #include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" #include "bpy_utils_previews.h" +#include "bpy_utils_images.h" #include "bpy_utils_units.h" #include "../generic/py_capi_utils.h" @@ -686,6 +687,7 @@ void BPy_init_modules(bContext *C) 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, "_utils_images", BPY_utils_images_module()); PyModule_AddObject(mod, "msgbus", BPY_msgbus_module()); PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, C); diff --git a/source/blender/python/intern/bpy_utils_images.cc b/source/blender/python/intern/bpy_utils_images.cc new file mode 100644 index 00000000000..a35ae852fb7 --- /dev/null +++ b/source/blender/python/intern/bpy_utils_images.cc @@ -0,0 +1,173 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup pythonintern + * + * This file defines a singleton py object accessed via 'bpy.utils.images', + */ + +#include +#include + +#include + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "RNA_access.hh" +#include "RNA_prototypes.h" +#include "RNA_types.hh" + +#include "BPY_extern.h" +#include "bpy_rna.h" +#include "bpy_utils_images.h" + +#include "../generic/py_capi_utils.h" + +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf.h" + +#include "../generic/python_utildefines.h" + + +struct bpy_image_data{ + bpy_image_data *prev; + bpy_image_data *next; + + int id; + ImBuf *ibuf; + std::string name; + std::string path; +}; + +int bpy_images_last_id = 0; +ListBase bpy_images_list; + + +bpy_image_data* BPY_utils_images_get_data(int image_id) { + return (bpy_image_data *)BLI_listbase_bytes_find( + &bpy_images_list, &image_id, sizeof(int), sizeof(bpy_image_data *) * 2); +} + +void* BPY_utils_images_get(int image_id) +{ + bpy_image_data *el = BPY_utils_images_get_data(image_id); + return (el != nullptr) ? el->ibuf : nullptr; +} + +PyDoc_STRVAR(bpy_utils_images_load_doc, + ".. method:: load(name, filepath)\n" + "\n" + " Generate a new preview from given file path.\n" + "\n" + " :arg name: The name identifying the image.\n" + " :type name: string\n" + " :arg filepath: The file path to the image.\n" + " :type filepath: string or bytes\n" + " :return: image id.\n" + " :rtype: long`\n"); +static PyObject *bpy_utils_images_load(PyObject * /*self*/, PyObject *args) +{ + char *name = NULL; + PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr}; + + if (!PyArg_ParseTuple(args, + "s" /* `name` */ + "O&" /* `filepath` */ + ":load", + &name, + PyC_ParseUnicodeAsBytesAndSize, + &filepath_data, + 0)) + { + return nullptr; + } + + if (!filepath_data.value || !name) { + Py_RETURN_NONE; + } + + ImBuf *ibuf = IMB_loadiffname(filepath_data.value, 0, nullptr); + + if (ibuf) { + bpy_image_data *data = MEM_new(__func__); + data->id = ++bpy_images_last_id; + data->ibuf = ibuf; + data->name = name; + data->path = filepath_data.value; + + BLI_addtail(&bpy_images_list, data); + + return PyLong_FromLong(data->id); + } + else { + Py_RETURN_NONE; + } +} + +PyDoc_STRVAR(bpy_utils_images_release_doc, + ".. method:: release(image_id)\n" + "\n" + " Release (free) a previously added image.\n" + "\n" + "\n" + " :arg image_id: The id identifying the image.\n" + " :type name: long\n" + " :return: true if release.\n" + " :rtype: bool`\n"); +static PyObject *bpy_utils_images_release(PyObject * /*self*/, PyObject *args) +{ + int image_id = -1; + + if (!PyArg_ParseTuple(args, "i:release", &image_id)) { + return nullptr; + } + + bpy_image_data *el = BPY_utils_images_get_data(image_id); + + if (el != nullptr) { + BLI_remlink(&bpy_images_list, el); + IMB_freeImBuf(el->ibuf); + MEM_freeN(el); + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +static PyMethodDef bpy_utils_images_methods[] = { + /* Can't use METH_KEYWORDS alone, see http://bugs.python.org/issue11587 */ + {"load", (PyCFunction)bpy_utils_images_load, METH_VARARGS, bpy_utils_images_load_doc}, + {"release",(PyCFunction)bpy_utils_images_release,METH_VARARGS, bpy_utils_images_release_doc}, + {nullptr, nullptr, 0, nullptr}, +}; + +PyDoc_STRVAR( + bpy_utils_images_doc, + "This object contains basic static methods to handle cached (non-ID) previews in Blender\n" + "(low-level API, not exposed to final users)."); +static PyModuleDef bpy_utils_images_module = { + /*m_base*/ PyModuleDef_HEAD_INIT, + /*m_name*/ "bpy._utils_images", + /*m_doc*/ bpy_utils_images_doc, + /*m_size*/ 0, + /*m_methods*/ bpy_utils_images_methods, + /*m_slots*/ nullptr, + /*m_traverse*/ nullptr, + /*m_clear*/ nullptr, + /*m_free*/ nullptr, +}; + +PyObject *BPY_utils_images_module() +{ + PyObject *submodule; + + submodule = PyModule_Create(&bpy_utils_images_module); + + return submodule; +} diff --git a/source/blender/python/intern/bpy_utils_images.h b/source/blender/python/intern/bpy_utils_images.h new file mode 100644 index 00000000000..6e27babe26a --- /dev/null +++ b/source/blender/python/intern/bpy_utils_images.h @@ -0,0 +1,19 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup pythonintern + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject *BPY_utils_images_module(void); + +#ifdef __cplusplus +} +#endif