diff --git a/doc/python_api/rst/info_overview.rst b/doc/python_api/rst/info_overview.rst index ba2e6949b81..721374cd472 100644 --- a/doc/python_api/rst/info_overview.rst +++ b/doc/python_api/rst/info_overview.rst @@ -5,23 +5,25 @@ Python API Overview ******************* -This document is to give an understanding of how Python and Blender fit together, -covering some of the functionality that isn't obvious from reading the API reference and example scripts. +The purpose of this document is to explain how Python and Blender fit together, +covering some of the functionality that may not be obvious from reading the API +references and example scripts. Python in Blender ================= -Blender embeds a Python interpreter which is started with Blender and stays active. -This interpreter runs scripts to draw the user interface and is used for some of Blender's internal tools too. +Blender has an embedded Python interpreter which is loaded when Blender is started and stays +active while Blender is running. This interpreter runs scripts to draw the user interface +and is used for some of Blender’s internal tools as well. -This is a typical Python environment so tutorials on how to write Python scripts -will work running the scripts in Blender too. -Blender provides the :mod:`bpy` module to the Python interpreter. -This module can be imported in a script and gives access to Blender data, classes, and functions. -Scripts that deal with Blender data will need to import this module. +Blender's embedded interpreter provides a typical Python environment, so code from tutorials +on how to write Python scripts can also be run with Blender’s interpreter. Blender provides its +Python modules, such as :mod:`bpy` and :mod:`mathutils`, to the embedded interpreter so they can +be imported into a script and give access to Blender's data, classes, and functions. Scripts that +deal with Blender data will need to import the modules to work. -Here is a simple example of moving a vertex of the object named **Cube**: +Here is a simple example which moves a vertex attached to an object named **Cube**: .. code-block:: python @@ -49,15 +51,17 @@ See the :ref:`directory layout docs >> bpy.ops.object.operator_1() Hello World OBJECT_OT_operator_1 diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp index 462947f32a3..81891d853d2 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ b/source/blender/compositor/nodes/COM_ImageNode.cpp @@ -99,6 +99,11 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name)); int view = 0; + if (STREQ(storage->pass_name, RE_PASSNAME_COMBINED) && STREQ(bnodeSocket->name, "Alpha")) { + /* Alpha output is already handled with the associated combined output. */ + continue; + } + /* returns the image view to use for the current active view */ if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) { const int view_image = imageuser->view; @@ -140,16 +145,24 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo converter.addPreview(operation->getOutputSocket()); } if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) { - BLI_assert(operation != NULL); - BLI_assert(index < numberOfOutputs - 1); - NodeOutput *outputSocket = this->getOutputSocket(index + 1); - SeparateChannelOperation *separate_operation; - separate_operation = new SeparateChannelOperation(); - separate_operation->setChannel(3); - converter.addOperation(separate_operation); - converter.addLink(operation->getOutputSocket(), separate_operation->getInputSocket(0)); - converter.mapOutputSocket(outputSocket, separate_operation->getOutputSocket()); - index++; + for (int alphaIndex = 0; alphaIndex < numberOfOutputs; alphaIndex++) { + NodeOutput *alphaSocket = this->getOutputSocket(alphaIndex); + bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket(); + if (!STREQ(bnodeAlphaSocket->name, "Alpha")) { + continue; + } + NodeImageLayer *alphaStorage = (NodeImageLayer *)bnodeSocket->storage; + if (!STREQ(alphaStorage->pass_name, RE_PASSNAME_COMBINED)) { + continue; + } + SeparateChannelOperation *separate_operation; + separate_operation = new SeparateChannelOperation(); + separate_operation->setChannel(3); + converter.addOperation(separate_operation); + converter.addLink(operation->getOutputSocket(), separate_operation->getInputSocket(0)); + converter.mapOutputSocket(alphaSocket, separate_operation->getOutputSocket()); + break; + } } } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 03dd2a5aef5..2c05ba52fe0 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -3088,19 +3088,13 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) /** \name Transform Shear * \{ */ -static void postInputShear(TransInfo *UNUSED(t), float values[3]) -{ - mul_v3_fl(values, 0.05f); -} - static void initShear(TransInfo *t) { t->mode = TFM_SHEAR; t->transform = applyShear; t->handleEvent = handleEventShear; - - setInputPostFct(&t->mouse, postInputShear); - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); t->idx_max = 0; t->num.idx_max = 0; @@ -3122,24 +3116,24 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event) if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) { /* Use custom.mode.data pointer to signal Shear direction */ if (t->custom.mode.data == NULL) { - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO); t->custom.mode.data = (void *)1; } else { - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); t->custom.mode.data = NULL; } status = TREDRAW_HARD; } else if (event->type == XKEY && event->val == KM_PRESS) { - initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); t->custom.mode.data = NULL; status = TREDRAW_HARD; } else if (event->type == YKEY && event->val == KM_PRESS) { - initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO); t->custom.mode.data = (void *)1; status = TREDRAW_HARD; diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 22c39d6ed0c..5f2e5a99090 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -86,12 +86,11 @@ static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const double mv output[1] *= mi->factor; } -static void InputHorizontalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3]) +static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { const int winx = t->ar ? t->ar->winx : 1; - const double pad = winx / 10; - output[0] = (mval[0] - pad) / (winx - 2 * pad); + output[0] = ((mval[0] - mi->imval[0]) / winx) * 2.0f; } static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) @@ -104,12 +103,11 @@ static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double m output[0] = dot_v3v3(t->viewinv[0], vec) * 2.0f; } -static void InputVerticalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3]) +static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) { const int winy = t->ar ? t->ar->winy : 1; - const double pad = winy / 10; - output[0] = (mval[1] - pad) / (winy - 2 * pad); + output[0] = ((mval[1] - mi->imval[1]) / winy) * 2.0f; } static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3]) @@ -314,7 +312,6 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode) t->helpline = HLP_TRACKBALL; break; case INPUT_HORIZONTAL_RATIO: - mi->factor = (float)(mi->center[0] - mi->imval[0]); mi->apply = InputHorizontalRatio; t->helpline = HLP_HARROW; break; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index e958ab9a3dc..a95a99449fd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -116,6 +116,10 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree, bNode *node, } else { sock = BLI_findlink(&node->outputs, sock_index); + NodeImageLayer *sockdata = sock->storage; + if(sockdata) { + BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name)); + } } BLI_linklist_append(available_sockets, sock); @@ -158,14 +162,11 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNod else type = SOCK_RGBA; + cmp_node_image_add_pass_output(ntree, node, rpass->name, rpass->name, -1, type, false, available_sockets, &prev_index); /* Special handling for the Combined pass to ensure compatibility. */ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) { - cmp_node_image_add_pass_output(ntree, node, "Image", rpass->name, -1, type, false, available_sockets, &prev_index); cmp_node_image_add_pass_output(ntree, node, "Alpha", rpass->name, -1, SOCK_FLOAT, false, available_sockets, &prev_index); } - else { - cmp_node_image_add_pass_output(ntree, node, rpass->name, rpass->name, -1, type, false, available_sockets, &prev_index); - } } BKE_image_release_ibuf(ima, ibuf, NULL); return; @@ -173,13 +174,10 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNod } } - cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, RRES_OUT_IMAGE, SOCK_RGBA, false, available_sockets, &prev_index); - cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, RRES_OUT_ALPHA, SOCK_FLOAT, false, available_sockets, &prev_index); + cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, -1, SOCK_RGBA, false, available_sockets, &prev_index); + cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, -1, SOCK_FLOAT, false, available_sockets, &prev_index); if (ima) { - if (!ima->rr) { - cmp_node_image_add_pass_output(ntree, node, RE_PASSNAME_Z, RE_PASSNAME_Z, RRES_OUT_Z, SOCK_FLOAT, false, available_sockets, &prev_index); - } BKE_image_release_ibuf(ima, ibuf, NULL); } } @@ -276,7 +274,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl for (link = ntree->links.first; link; link = link->next) { if (link->fromsock == sock) break; } - if (!link && sock_index > 30) { + if (!link && (!rlayer || sock_index > 30)) { MEM_freeN(sock->storage); nodeRemoveSocket(ntree, node, sock); } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 3a6d5c9f972..6ca8b178ff7 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7265,15 +7265,12 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v { const ListBase *lb; Link *link; - FunctionRNA *func; - PropertyRNA *prop; const char *class_type = RNA_struct_identifier(srna); StructRNA *srna_base = RNA_struct_base(srna); PyObject *py_class = (PyObject *)py_data; PyObject *base_class = RNA_struct_py_type_get(srna); PyObject *item; - int i, flag, arg_count, func_arg_count, func_arg_min_count = 0; - bool is_staticmethod; + int i, arg_count, func_arg_count, func_arg_min_count = 0; const char *py_class_name = ((PyTypeObject *)py_class)->tp_name; /* __name__ */ if (srna_base) { @@ -7294,9 +7291,12 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v lb = RNA_struct_type_functions(srna); i = 0; for (link = lb->first; link; link = link->next) { - func = (FunctionRNA *)link; - flag = RNA_function_flag(func); - is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE); + FunctionRNA *func = (FunctionRNA *)link; + const int flag = RNA_function_flag(func); + /* TODO(campbell): this is used for classmethod's too, + * even though class methods should have 'FUNC_USE_SELF_TYPE' set, see Operator.poll for eg. + * Keep this as-is since its working but we should be using 'FUNC_USE_SELF_TYPE' for many functions. */ + const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE); if (!(flag & FUNC_REGISTER)) continue; @@ -7322,7 +7322,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v if (is_staticmethod) { if (PyMethod_Check(item) == 0) { PyErr_Format(PyExc_TypeError, - "expected %.200s, %.200s class \"%.200s\" attribute to be a method, not a %.200s", + "expected %.200s, %.200s class \"%.200s\" " + "attribute to be a static/class method, not a %.200s", class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name); return -1; } @@ -7331,7 +7332,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v else { if (PyFunction_Check(item) == 0) { PyErr_Format(PyExc_TypeError, - "expected %.200s, %.200s class \"%.200s\" attribute to be a function, not a %.200s", + "expected %.200s, %.200s class \"%.200s\" " + "attribute to be a function, not a %.200s", class_type, py_class_name, RNA_function_identifier(func), Py_TYPE(item)->tp_name); return -1; } @@ -7374,8 +7376,8 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v lb = RNA_struct_type_properties(srna); for (link = lb->first; link; link = link->next) { const char *identifier; - prop = (PropertyRNA *)link; - flag = RNA_property_flag(prop); + PropertyRNA *prop = (PropertyRNA *)link; + const int flag = RNA_property_flag(prop); if (!(flag & PROP_REGISTER)) continue; diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 65e348336b4..986a09b8f79 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -49,7 +49,8 @@ endif() # for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no set(TEST_BLENDER_EXE_BARE ${TEST_BLENDER_EXE}) -set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) +set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) +set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} ${TEST_BLENDER_EXE_PARAMS} ) # ------------------------------------------------------------------------------ @@ -458,12 +459,6 @@ if(WITH_ALEMBIC) get_filename_component(real_include_dir ${ALEMBIC_INCLUDE_DIR} REALPATH) get_filename_component(ALEMBIC_ROOT_DIR ${real_include_dir} DIRECTORY) - add_test(script_alembic_import ${TEST_BLENDER_EXE} - --python ${CMAKE_CURRENT_LIST_DIR}/bl_alembic_import_test.py - -- - --testdir "${TEST_SRC_DIR}/alembic" - ) - if(MSVC) add_test(NAME alembic_tests COMMAND @@ -473,6 +468,14 @@ if(WITH_ALEMBIC) --testdir "${TEST_SRC_DIR}/alembic" --alembic-root "${ALEMBIC_ROOT_DIR}" ) + add_test(NAME script_alembic_import + COMMAND + "$" ${TEST_BLENDER_EXE_PARAMS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_alembic_import_test.py + -- + --testdir "${TEST_SRC_DIR}/alembic" + ) + else() add_test(alembic_tests ${CMAKE_CURRENT_LIST_DIR}/alembic_tests.py @@ -480,6 +483,12 @@ if(WITH_ALEMBIC) --testdir "${TEST_SRC_DIR}/alembic" --alembic-root "${ALEMBIC_ROOT_DIR}" ) + add_test(script_alembic_import ${TEST_BLENDER_EXE} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_alembic_import_test.py + -- + --testdir "${TEST_SRC_DIR}/alembic" + ) + endif() endif()