Merge branch 'blender-v4.5-release'

This commit is contained in:
Bastien Montagne
2025-06-16 16:31:38 +02:00
6 changed files with 58 additions and 58 deletions

View File

@@ -447,9 +447,22 @@ Using low-level functions:
.. code-block:: python .. code-block:: python
obj = bpy.context.object obj = bpy.context.object
obj.animation_data_create()
obj.animation_data.action = bpy.data.actions.new(name="MyAction") # Create the action, with a slot for the object, a layer, and a keyframe strip:
fcu_z = obj.animation_data.action.fcurves.new(data_path="location", index=2) action = bpy.data.actions.new(name="MyAction")
slot = action.slots.new(obj.id_type, obj.name)
strip = action.layers.new("MyLayer").strips.new(type='KEYFRAME')
# Create a channelbag to hold the F-Curves for the slot:
channelbag = strip.channelbag(slot, ensure=True)
# Create the F-Curve with two keyframes:
fcu_z = channelbag.fcurves.new(data_path="location", index=2)
fcu_z.keyframe_points.add(2) fcu_z.keyframe_points.add(2)
fcu_z.keyframe_points[0].co = 10.0, 0.0 fcu_z.keyframe_points[0].co = 10.0, 0.0
fcu_z.keyframe_points[1].co = 20.0, 1.0 fcu_z.keyframe_points[1].co = 20.0, 1.0
# Assign the action and the slot to the object:
adt = obj.animation_data_create()
adt.action = action
adt.action_slot = slot

View File

@@ -12,7 +12,6 @@
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include <cstdarg> #include <cstdarg>
#include <optional>
#include "bmesh_class.hh" #include "bmesh_class.hh"
@@ -240,15 +239,6 @@ union eBMOpSlotSubType_Union {
eBMOpSlotSubType_Int intg; eBMOpSlotSubType_Int intg;
}; };
enum eBMOpSlotFlag : uint8_t {
/**
* This flag is set when the operators value has been set.
* Use this so it's possible to have non-zero defaults for properties.
*/
BMO_OP_SLOT_FLAG_IS_SET = (1 << 0),
};
ENUM_OPERATORS(eBMOpSlotFlag, BMO_OP_SLOT_FLAG_IS_SET)
struct BMO_FlagSet { struct BMO_FlagSet {
int value; int value;
const char *identifier; const char *identifier;
@@ -262,8 +252,8 @@ struct BMOpSlot {
eBMOpSlotType slot_type; eBMOpSlotType slot_type;
eBMOpSlotSubType_Union slot_subtype; eBMOpSlotSubType_Union slot_subtype;
eBMOpSlotFlag flag;
int len; int len;
// int flag; /* UNUSED */
// int index; /* index within slot array */ /* UNUSED */ // int index; /* index within slot array */ /* UNUSED */
union { union {
int i; int i;
@@ -559,16 +549,10 @@ void BMO_op_flag_disable(BMesh *bm, BMOperator *op, int op_flag);
void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float f); void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float f);
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
std::optional<float> BMO_slot_float_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name);
void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int i); void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int i);
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
std::optional<int> BMO_slot_int_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name);
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, bool i); void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, bool i);
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
std::optional<bool> BMO_slot_bool_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name);
/** /**
* Return a copy of the element buffer. * Return a copy of the element buffer.
*/ */

View File

@@ -295,8 +295,6 @@ void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
else { else {
slot_dst->data = slot_src->data; slot_dst->data = slot_src->data;
} }
slot_dst->flag = slot_src->flag;
} }
/* /*
@@ -314,7 +312,6 @@ void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_n
} }
slot->data.f = f; slot->data.f = f;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
} }
void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i) void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i)
@@ -326,7 +323,6 @@ void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
} }
slot->data.i = i; slot->data.i = i;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
} }
void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i) void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i)
@@ -338,7 +334,6 @@ void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na
} }
slot->data.i = i; slot->data.i = i;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
} }
void BMO_slot_mat_set(BMOperator *op, void BMO_slot_mat_set(BMOperator *op,
@@ -367,7 +362,6 @@ void BMO_slot_mat_set(BMOperator *op,
zero_m4(static_cast<float(*)[4]>(slot->data.p)); zero_m4(static_cast<float(*)[4]>(slot->data.p));
} }
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
} }
void BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], void BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -415,7 +409,6 @@ void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_nam
} }
slot->data.p = p; slot->data.p = p;
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
} }
void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
@@ -429,51 +422,31 @@ void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
} }
copy_v3_v3(slot->data.vec, vec); copy_v3_v3(slot->data.vec, vec);
slot->flag |= BMO_OP_SLOT_FLAG_IS_SET;
} }
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name) float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
{
return BMO_slot_float_get_optional(slot_args, slot_name).value_or(0.0f);
}
std::optional<float> BMO_slot_float_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name)
{ {
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name); BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT); BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
if (!(slot->slot_type == BMO_OP_SLOT_FLT)) { if (!(slot->slot_type == BMO_OP_SLOT_FLT)) {
return std::nullopt; return 0.0f;
}
if ((slot->flag & BMO_OP_SLOT_FLAG_IS_SET) == 0) {
return std::nullopt;
} }
return slot->data.f; return slot->data.f;
} }
std::optional<int> BMO_slot_int_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
const char *slot_name)
{ {
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name); BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BLI_assert(slot->slot_type == BMO_OP_SLOT_INT); BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
if (!(slot->slot_type == BMO_OP_SLOT_INT)) { if (!(slot->slot_type == BMO_OP_SLOT_INT)) {
return std::nullopt; return 0;
}
if ((slot->flag & BMO_OP_SLOT_FLAG_IS_SET) == 0) {
return std::nullopt;
} }
return slot->data.i; return slot->data.i;
} }
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name) bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
{
return BMO_slot_int_get_optional(slot_args, slot_name).value_or(0);
}
std::optional<bool> BMO_slot_bool_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name)
{ {
BMOpSlot *slot = BMO_slot_get(slot_args, slot_name); BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL); BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
@@ -483,10 +456,6 @@ std::optional<bool> BMO_slot_bool_get_optional(BMOpSlot slot_args[BMO_OP_MAX_SLO
return slot->data.i; return slot->data.i;
} }
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
{
return BMO_slot_bool_get_optional(slot_args, slot_name).value_or(false);
}
void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len) void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
{ {

View File

@@ -387,9 +387,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
* This lets the test ignore that tiny bit of math error so users won't notice. */ * This lets the test ignore that tiny bit of math error so users won't notice. */
const float angle_epsilon = RAD2DEGF(0.0001f); const float angle_epsilon = RAD2DEGF(0.0001f);
/* When unset, don't limit dissolving vertices at all. */ const float angle_threshold = BMO_slot_float_get(op->slots_in, "angle_threshold");
const float angle_threshold =
BMO_slot_float_get_optional(op->slots_in, "angle_threshold").value_or(M_PI);
/* Use verts when told to... except, do *not* use verts when angle_threshold is 0.0. */ /* Use verts when told to... except, do *not* use verts when angle_threshold is 0.0. */
const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts") && const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts") &&

View File

@@ -261,6 +261,11 @@ add_blender_test(
--python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_text.py --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_text.py
) )
add_blender_test(
script_pyapi_bmesh
--python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bmesh.py
)
add_blender_test( add_blender_test(
script_pyapi_grease_pencil script_pyapi_grease_pencil
--python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_grease_pencil.py --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_grease_pencil.py

View File

@@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: 2025 Blender Authors
#
# SPDX-License-Identifier: Apache-2.0
# ./blender.bin --background --python tests/python/bl_pyapi_bmesh.py -- --verbose
import bmesh
import unittest
class TestBMeshBasic(unittest.TestCase):
def test_create_uvsphere(self):
bm = bmesh.new()
bmesh.ops.create_uvsphere(
bm,
u_segments=8,
v_segments=5,
radius=1.0,
)
self.assertEqual(len(bm.verts), 34)
self.assertEqual(len(bm.edges), 72)
self.assertEqual(len(bm.faces), 40)
bm.free()
if __name__ == "__main__":
import sys
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
unittest.main()