Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-05-13 17:43:21 +02:00
commit 72aad83780
112 changed files with 2679 additions and 576 deletions

View File

@ -1029,7 +1029,6 @@ def pymodule2sphinx(basepath, module_name, module, title, module_all_extra):
context_type_map = {
# context_member: (RNA type, is_collection)
"active_annotation_layer": ("GPencilLayer", False),
"active_base": ("ObjectBase", False),
"active_bone": ("EditBone", False),
"active_gpencil_frame": ("GreasePencilLayer", True),
"active_gpencil_layer": ("GPencilLayer", True),
@ -1549,8 +1548,8 @@ def pyrna2sphinx(basepath):
fw(".. hlist::\n")
fw(" :columns: 2\n\n")
# context does its own thing
# "active_base": ("ObjectBase", False),
# Context does its own thing.
# "active_object": ("Object", False),
for ref_attr, (ref_type, ref_is_seq) in sorted(context_type_map.items()):
if ref_type == struct_id:
fw(" * :mod:`bpy.context.%s`\n" % ref_attr)

View File

@ -96,7 +96,49 @@ bool BlenderSync::object_is_light(BL::Object &b_ob)
return (b_ob_data && b_ob_data.is_a(&RNA_Light));
}
/* Object */
void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
{
/* Initialize motion blur for object, detecting if it's enabled and creating motion
* steps array if so. */
array<Transform> motion;
object->set_motion(motion);
Scene::MotionType need_motion = scene->need_motion();
if (need_motion == Scene::MOTION_NONE || !object->get_geometry()) {
return;
}
Geometry *geom = object->get_geometry();
geom->set_use_motion_blur(false);
geom->set_motion_steps(0);
uint motion_steps;
if (need_motion == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
geom->set_motion_steps(motion_steps);
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
geom->set_use_motion_blur(true);
}
}
else {
motion_steps = 3;
geom->set_motion_steps(motion_steps);
}
motion.resize(motion_steps, transform_empty());
if (motion_steps) {
motion[motion_steps / 2] = object->get_tfm();
/* update motion socket before trying to access object->motion_time */
object->set_motion(motion);
for (size_t step = 0; step < motion_steps; step++) {
motion_times.insert(object->motion_time(step));
}
}
}
Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
BL::ViewLayer &b_view_layer,
@ -277,43 +319,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
object->set_pass_id(b_ob.pass_index());
object->set_color(get_float3(b_ob.color()));
object->set_tfm(tfm);
array<Transform> motion;
object->set_motion(motion);
/* motion blur */
Scene::MotionType need_motion = scene->need_motion();
if (need_motion != Scene::MOTION_NONE && object->get_geometry()) {
Geometry *geom = object->get_geometry();
geom->set_use_motion_blur(false);
geom->set_motion_steps(0);
uint motion_steps;
if (need_motion == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
geom->set_motion_steps(motion_steps);
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
geom->set_use_motion_blur(true);
}
}
else {
motion_steps = 3;
geom->set_motion_steps(motion_steps);
}
motion.resize(motion_steps, transform_empty());
if (motion_steps) {
motion[motion_steps / 2] = tfm;
/* update motion socket before trying to access object->motion_time */
object->set_motion(motion);
for (size_t step = 0; step < motion_steps; step++) {
motion_times.insert(object->motion_time(step));
}
}
}
/* dupli texture coordinates and random_id */
if (is_instance) {
@ -331,6 +336,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
object->tag_update(scene);
}
sync_object_motion_init(b_parent, b_ob, object);
if (is_instance) {
/* Sync possible particle data. */
sync_dupli_particle(b_parent, b_instance, object);
@ -613,7 +620,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
if (b_cam) {
sync_camera_motion(b_render, b_cam, width, height, 0.0f);
}
sync_objects(b_depsgraph, b_v3d, 0.0f);
sync_objects(b_depsgraph, b_v3d);
}
/* Insert motion times from camera. Motion times from other objects

View File

@ -739,12 +739,18 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
* caches to be releases from blender side in order to reduce peak memory
* footprint during synchronization process.
*/
const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface();
const bool can_free_caches = (BlenderSession::headless || is_interface_locked) &&
/* Baking re-uses the depsgraph multiple times, clearing crashes
* reading un-evaluated mesh data which isn't aligned with the
* geometry we're baking, see T71012. */
!scene->bake_manager->get_baking();
const bool is_persistent_data = b_engine.render() && b_engine.render().use_persistent_data();
const bool can_free_caches =
(BlenderSession::headless || is_interface_locked) &&
/* Baking re-uses the depsgraph multiple times, clearing crashes
* reading un-evaluated mesh data which isn't aligned with the
* geometry we're baking, see T71012. */
!scene->bake_manager->get_baking() &&
/* Persistent data must main caches for performance and correctness. */
!is_persistent_data;
if (!can_free_caches) {
return;
}

View File

@ -150,6 +150,7 @@ class BlenderSync {
BlenderObjectCulling &culling,
bool *use_portal,
TaskPool *geom_task_pool);
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);

View File

@ -57,14 +57,24 @@ ccl_device ccl_addr_space void *closure_alloc_extra(ShaderData *sd, int size)
ccl_device_inline ShaderClosure *bsdf_alloc(ShaderData *sd, int size, float3 weight)
{
ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
kernel_assert(isfinite3_safe(weight));
if (sc == NULL)
return NULL;
const float sample_weight = fabsf(average(weight));
float sample_weight = fabsf(average(weight));
sc->sample_weight = sample_weight;
return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL;
/* Use comparison this way to help dealing with non-finite weight: if the average is not finite
* we will not allocate new closure. */
if (sample_weight >= CLOSURE_WEIGHT_CUTOFF) {
ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
if (sc == NULL) {
return NULL;
}
sc->sample_weight = sample_weight;
return sc;
}
return NULL;
}
#ifdef __OSL__
@ -73,17 +83,27 @@ ccl_device_inline ShaderClosure *bsdf_alloc_osl(ShaderData *sd,
float3 weight,
void *data)
{
ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
kernel_assert(isfinite3_safe(weight));
if (!sc)
return NULL;
const float sample_weight = fabsf(average(weight));
memcpy((void *)sc, data, size);
/* Use comparison this way to help dealing with non-finite weight: if the average is not finite
* we will not allocate new closure. */
if (sample_weight >= CLOSURE_WEIGHT_CUTOFF) {
ShaderClosure *sc = closure_alloc(sd, size, CLOSURE_NONE_ID, weight);
if (!sc) {
return NULL;
}
float sample_weight = fabsf(average(weight));
sc->weight = weight;
sc->sample_weight = sample_weight;
return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? sc : NULL;
memcpy((void *)sc, data, size);
sc->weight = weight;
sc->sample_weight = sample_weight;
return sc;
}
return NULL;
}
#endif

View File

@ -25,8 +25,9 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float3
subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, float r, bool all)
{
/* this is the veach one-sample model with balance heuristic, some pdf
* factors drop out when using balance heuristic weighting */
/* This is the Veach one-sample model with balance heuristic, some pdf
* factors drop out when using balance heuristic weighting. For branched
* path tracing (all) we sample all closure and don't use MIS. */
float3 eval_sum = zero_float3();
float pdf_sum = 0.0f;
float sample_weight_inv = 0.0f;
@ -65,6 +66,30 @@ subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, f
return (pdf_sum > 0.0f) ? eval_sum / pdf_sum : zero_float3();
}
ccl_device_inline float3 subsurface_scatter_walk_eval(ShaderData *sd,
const ShaderClosure *sc,
float3 throughput,
bool all)
{
/* This is the Veach one-sample model with balance heuristic, some pdf
* factors drop out when using balance heuristic weighting. For branched
* path tracing (all) we sample all closure and don't use MIS. */
if (!all) {
float bssrdf_weight = 0.0f;
float weight = sc->sample_weight;
for (int i = 0; i < sd->num_closure; i++) {
sc = &sd->closure[i];
if (CLOSURE_IS_BSSRDF(sc->type)) {
bssrdf_weight += sc->sample_weight;
}
}
throughput *= bssrdf_weight / weight;
}
return throughput;
}
/* replace closures with a single diffuse bsdf closure after scatter step */
ccl_device void subsurface_scatter_setup_diffuse_bsdf(
KernelGlobals *kg, ShaderData *sd, ClosureType type, float roughness, float3 weight, float3 N)
@ -437,7 +462,8 @@ ccl_device_noinline
ccl_addr_space PathState *state,
const ShaderClosure *sc,
const float bssrdf_u,
const float bssrdf_v)
const float bssrdf_v,
bool all)
{
/* Sample diffuse surface scatter into the object. */
float3 D;
@ -669,7 +695,7 @@ ccl_device_noinline
/* TODO: gain back performance lost from merging with disk BSSRDF. We
* only need to return on hit so this indirect ray push/pop overhead
* is not actually needed, but it does keep the code simpler. */
ss_isect->weight[0] = throughput;
ss_isect->weight[0] = subsurface_scatter_walk_eval(sd, sc, throughput, all);
#ifdef __SPLIT_KERNEL__
ss_isect->ray = *ray;
#endif
@ -691,7 +717,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect(KernelGlobals *kg,
return subsurface_scatter_disk(kg, ss_isect, sd, sc, lcg_state, bssrdf_u, bssrdf_v, all);
}
else {
return subsurface_random_walk(kg, ss_isect, sd, state, sc, bssrdf_u, bssrdf_v);
return subsurface_random_walk(kg, ss_isect, sd, state, sc, bssrdf_u, bssrdf_v, all);
}
}

View File

@ -370,10 +370,13 @@ ccl_device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack
if (direction_type == NODE_TANGENT_UVMAP) {
/* UV map */
if (desc.offset == ATTR_STD_NOT_FOUND)
tangent = make_float3(0.0f, 0.0f, 0.0f);
else
if (desc.offset == ATTR_STD_NOT_FOUND) {
stack_store_float3(stack, tangent_offset, zero_float3());
return;
}
else {
tangent = attribute_value;
}
}
else {
/* radial */

View File

@ -72,9 +72,9 @@ class OSLShaderManager : public ShaderManager {
static void free_memory();
void reset(Scene *scene);
void reset(Scene *scene) override;
bool use_osl()
bool use_osl() override
{
return true;
}
@ -83,7 +83,7 @@ class OSLShaderManager : public ShaderManager {
DeviceScene *dscene,
Scene *scene,
Progress &progress) override;
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene, Scene *scene) override;
/* osl compile and query */
static bool osl_compile(const string &inputfile, const string &outputfile);

View File

@ -44,13 +44,13 @@ class SVMShaderManager : public ShaderManager {
SVMShaderManager();
~SVMShaderManager();
void reset(Scene *scene);
void reset(Scene *scene) override;
void device_update_specific(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress) override;
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene, Scene *scene) override;
protected:
void device_update_shader(Scene *scene,

View File

@ -55,7 +55,6 @@ void *GHOST_XrContext::s_error_handler_customdata = nullptr;
/* -------------------------------------------------------------------- */
/** \name Create, Initialize and Destruct
*
* \{ */
GHOST_XrContext::GHOST_XrContext(const GHOST_XrContextCreateInfo *create_info)
@ -153,7 +152,6 @@ void GHOST_XrContext::storeInstanceProperties()
/* -------------------------------------------------------------------- */
/** \name Debug Printing
*
* \{ */
void GHOST_XrContext::printInstanceInfo()
@ -242,7 +240,6 @@ void GHOST_XrContext::initDebugMessenger()
/* -------------------------------------------------------------------- */
/** \name Error handling
*
* \{ */
void GHOST_XrContext::dispatchErrorMessage(const GHOST_XrException *exception) const
@ -273,7 +270,6 @@ void GHOST_XrContext::setErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *c
/* -------------------------------------------------------------------- */
/** \name OpenXR API-Layers and Extensions
*
* \{ */
/**
@ -564,7 +560,6 @@ bool GHOST_XrContext::needsUpsideDownDrawing() const
/* -------------------------------------------------------------------- */
/** \name Ghost Internal Accessors and Mutators
*
* \{ */
GHOST_TXrOpenXRRuntimeID GHOST_XrContext::getOpenXRRuntimeID() const

View File

@ -59,7 +59,6 @@ struct GHOST_XrDrawInfo {
/* -------------------------------------------------------------------- */
/** \name Create, Initialize and Destruct
*
* \{ */
GHOST_XrSession::GHOST_XrSession(GHOST_XrContext &xr_context)
@ -110,7 +109,6 @@ void GHOST_XrSession::initSystem()
/* -------------------------------------------------------------------- */
/** \name State Management
*
* \{ */
static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose &base_pose)
@ -245,7 +243,6 @@ GHOST_XrSession::LifeExpectancy GHOST_XrSession::handleStateChangeEvent(
/* -------------------------------------------------------------------- */
/** \name Drawing
*
* \{ */
void GHOST_XrSession::prepareDrawing()
@ -457,7 +454,6 @@ bool GHOST_XrSession::needsUpsideDownDrawing() const
/* -------------------------------------------------------------------- */
/** \name State Queries
*
* \{ */
bool GHOST_XrSession::isRunning() const

View File

@ -29,10 +29,10 @@ class Version:
def get_download_file_names(version: Version):
yield f"blender-{version}-linux64.tar.xz"
yield f"blender-{version}-macOS.dmg"
yield f"blender-{version}-windows64.msi"
yield f"blender-{version}-windows64.zip"
yield f"blender-{version}-linux-x86_64.tar.xz"
yield f"blender-{version}-darwin-x86_64.dmg"
yield f"blender-{version}-windows-amd64.msi"
yield f"blender-{version}-windows-amd64.zip"
def get_download_url(version: Version, file_name: str) -> str:

View File

@ -543,22 +543,6 @@ def module_bl_info(mod, info_basis=None):
if not addon_info["name"]:
addon_info["name"] = mod.__name__
# Replace 'wiki_url' with 'doc_url'.
doc_url = addon_info.pop("wiki_url", None)
if doc_url is not None:
# Unlikely, but possible that both are set.
if not addon_info["doc_url"]:
addon_info["doc_url"] = doc_url
if _bpy.app.debug:
print(
"Warning: add-on \"%s\": 'wiki_url' in 'bl_info' "
"is deprecated please use 'doc_url' instead!\n"
" %s" % (
addon_info['name'],
getattr(mod, "__file__", None),
)
)
doc_url = addon_info["doc_url"]
if doc_url:
doc_url_prefix = "{BLENDER_MANUAL_URL}"

View File

@ -370,7 +370,7 @@ def module_names(path, recursive=False):
def basename(path):
"""
Equivalent to os.path.basename, but skips a "//" prefix.
Equivalent to ``os.path.basename``, but skips a "//" prefix.
Use for Windows compatibility.
"""

View File

@ -3333,8 +3333,6 @@ def km_weight_paint(params):
*_template_paint_radial_control("weight_paint"),
("wm.context_toggle", {"type": 'M', "value": 'PRESS'},
{"properties": [("data_path", 'weight_paint_object.data.use_paint_mask')]}),
("wm.context_toggle", {"type": 'V', "value": 'PRESS'},
{"properties": [("data_path", 'weight_paint_object.data.use_paint_mask_vertex')]}),
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.weight_paint.brush.use_smooth_stroke')]}),
*_template_items_context_panel("VIEW3D_PT_paint_weight_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),

View File

@ -590,7 +590,7 @@ class PREFERENCES_OT_addon_install(Operator):
name="Target Path",
items=(
('DEFAULT', "Default", ""),
('PREFS', "User Prefs", ""),
('PREFS', "Preferences", ""),
),
)

View File

@ -292,10 +292,15 @@ class BONE_PT_display_custom_shape(BoneButtonsPanel, Panel):
sub = col.column()
sub.active = bool(pchan and pchan.custom_shape)
sub.separator()
sub.prop(pchan, "custom_shape_scale", text="Scale")
sub.prop(pchan, "custom_shape_scale_xyz", text="Scale")
sub.prop(pchan, "custom_shape_translation", text="Translation")
sub.prop(pchan, "custom_shape_rotation_euler", text="Rotation")
sub.prop_search(pchan, "custom_shape_transform",
ob.pose, "bones", text="Override Transform")
sub.prop(pchan, "use_custom_shape_bone_size")
sub.separator()
sub.prop(bone, "show_wire", text="Wireframe")

View File

@ -494,6 +494,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeProximity"),
NodeItem("GeometryNodeAttributeColorRamp"),
NodeItem("GeometryNodeAttributeVectorMath"),
NodeItem("GeometryNodeAttributeVectorRotate"),
NodeItem("GeometryNodeAttributeSampleTexture"),
NodeItem("GeometryNodeAttributeCombineXYZ"),
NodeItem("GeometryNodeAttributeSeparateXYZ"),

View File

@ -227,8 +227,10 @@ template<typename T> class SimpleMixer {
}
};
/** This mixer accumulates values in a type that is different from the one that is mixed. Some
* types cannot encode the floating point weights in their values (e.g. int and bool). */
/**
* This mixer accumulates values in a type that is different from the one that is mixed.
* Some types cannot encode the floating point weights in their values (e.g. int and bool).
*/
template<typename T, typename AccumulationT, T (*ConvertToT)(const AccumulationT &value)>
class SimpleMixerWithAccumulationType {
private:

View File

@ -325,6 +325,7 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
float r_uv[2],
float r_ofs[2]);
int BKE_image_find_nearest_tile(const struct Image *image, const float co[2]);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *r_width, int *r_height);
void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float r_size[2]);

View File

@ -1421,6 +1421,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_TO_MESH 1045
#define GEO_NODE_ATTRIBUTE_CURVE_MAP 1046
#define GEO_NODE_CURVE_RESAMPLE 1047
#define GEO_NODE_ATTRIBUTE_VECTOR_ROTATE 1048
/** \} */

View File

@ -95,8 +95,16 @@ struct AvailableAttributeInfo {
};
struct NodeUIStorage {
std::mutex mutex;
blender::Vector<NodeWarning> warnings;
blender::Set<AvailableAttributeInfo> attribute_hints;
NodeUIStorage() = default;
/* Needed because the mutex can't be moved or copied. */
NodeUIStorage(NodeUIStorage &&other)
: warnings(std::move(other.warnings)), attribute_hints(std::move(other.attribute_hints))
{
}
};
struct NodeTreeUIStorage {

View File

@ -47,7 +47,7 @@ typedef struct BodyPoint {
} BodyPoint;
/* allocates and initializes general main data */
extern struct SoftBody *sbNew(struct Scene *scene);
extern struct SoftBody *sbNew(void);
/* frees internal data and soft-body itself */
extern void sbFree(struct Object *ob);

View File

@ -64,11 +64,6 @@ class Spline {
Poly,
};
protected:
Type type_;
bool is_cyclic_ = false;
public:
enum NormalCalculationMode {
ZUp,
Minimum,
@ -78,6 +73,9 @@ class Spline {
NormalCalculationMode normal_mode;
protected:
Type type_;
bool is_cyclic_ = false;
/** Direction of the spline at each evaluated point. */
mutable blender::Vector<blender::float3> evaluated_tangents_cache_;
mutable std::mutex tangent_cache_mutex_;
@ -99,7 +97,7 @@ class Spline {
{
}
Spline(Spline &other)
: type_(other.type_), is_cyclic_(other.is_cyclic_), normal_mode(other.normal_mode)
: normal_mode(other.normal_mode), type_(other.type_), is_cyclic_(other.is_cyclic_)
{
}
@ -198,15 +196,21 @@ class BezierSpline final : public Spline {
};
private:
blender::Vector<HandleType> handle_types_left_;
blender::Vector<blender::float3> handle_positions_left_;
blender::Vector<blender::float3> positions_;
blender::Vector<HandleType> handle_types_right_;
blender::Vector<blender::float3> handle_positions_right_;
blender::Vector<float> radii_;
blender::Vector<float> tilts_;
int resolution_;
blender::Vector<HandleType> handle_types_left_;
blender::Vector<HandleType> handle_types_right_;
/* These are mutable to allow lazy recalculation of #Auto and #Vector handle positions. */
mutable blender::Vector<blender::float3> handle_positions_left_;
mutable blender::Vector<blender::float3> handle_positions_right_;
mutable std::mutex auto_handle_mutex_;
mutable bool auto_handles_dirty_ = true;
/** Start index in evaluated points array for every control point. */
mutable blender::Vector<int> offset_cache_;
mutable std::mutex offset_cache_mutex_;
@ -229,14 +233,14 @@ class BezierSpline final : public Spline {
}
BezierSpline(const BezierSpline &other)
: Spline((Spline &)other),
handle_types_left_(other.handle_types_left_),
handle_positions_left_(other.handle_positions_left_),
positions_(other.positions_),
handle_types_right_(other.handle_types_right_),
handle_positions_right_(other.handle_positions_right_),
radii_(other.radii_),
tilts_(other.tilts_),
resolution_(other.resolution_)
resolution_(other.resolution_),
handle_types_left_(other.handle_types_left_),
handle_types_right_(other.handle_types_right_),
handle_positions_left_(other.handle_positions_left_),
handle_positions_right_(other.handle_positions_right_)
{
}
@ -294,12 +298,12 @@ class BezierSpline final : public Spline {
const blender::fn::GVArray &source_data) const override;
private:
void ensure_auto_handles() const;
void correct_end_tangents() const final;
bool segment_is_vector(const int start_index) const;
void evaluate_bezier_segment(const int index,
const int next_index,
blender::MutableSpan<blender::float3> positions) const;
blender::Array<int> evaluated_point_offsets() const;
};
/**
@ -424,12 +428,10 @@ class NURBSpline final : public Spline {
* points does not change it.
*/
class PolySpline final : public Spline {
public:
blender::Vector<blender::float3> positions_;
blender::Vector<float> radii_;
blender::Vector<float> tilts_;
private:
public:
SplinePtr copy() const final;
PolySpline() : Spline(Type::Poly)
@ -472,8 +474,15 @@ class PolySpline final : public Spline {
* more of the data is stored in the splines, but also just to be different than the name in DNA.
*/
class CurveEval {
private:
blender::Vector<SplinePtr> splines_;
public:
blender::Vector<SplinePtr> splines;
blender::Span<SplinePtr> splines() const;
blender::MutableSpan<SplinePtr> splines();
void add_spline(SplinePtr spline);
void remove_splines(blender::IndexMask mask);
CurveEval *copy();

View File

@ -656,7 +656,9 @@ bPoseChannel *BKE_pose_channel_ensure(bPose *pose, const char *name)
BLI_strncpy(chan->name, name, sizeof(chan->name));
chan->custom_scale = 1.0f;
copy_v3_fl(chan->custom_scale_xyz, 1.0f);
zero_v3(chan->custom_translation);
zero_v3(chan->custom_rotation_euler);
/* init vars to prevent math errors */
unit_qt(chan->quat);
@ -1235,8 +1237,10 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
if (pchan->custom) {
id_us_plus(&pchan->custom->id);
}
copy_v3_v3(pchan->custom_scale_xyz, pchan_from->custom_scale_xyz);
copy_v3_v3(pchan->custom_translation, pchan_from->custom_translation);
copy_v3_v3(pchan->custom_rotation_euler, pchan_from->custom_rotation_euler);
pchan->custom_scale = pchan_from->custom_scale;
pchan->drawflag = pchan_from->drawflag;
}

View File

@ -1040,6 +1040,7 @@ static NlaEvalChannelSnapshot *nlaevalchan_snapshot_new(NlaEvalChannel *nec)
nec_snapshot->channel = nec;
nec_snapshot->length = length;
nlavalidmask_init(&nec_snapshot->blend_domain, length);
nlavalidmask_init(&nec_snapshot->remap_domain, length);
return nec_snapshot;
}
@ -1050,6 +1051,7 @@ static void nlaevalchan_snapshot_free(NlaEvalChannelSnapshot *nec_snapshot)
BLI_assert(!nec_snapshot->is_base);
nlavalidmask_free(&nec_snapshot->blend_domain);
nlavalidmask_free(&nec_snapshot->remap_domain);
MEM_freeN(nec_snapshot);
}
@ -1649,6 +1651,363 @@ static bool nla_combine_quaternion_get_inverted_strip_values(const float lower_v
return true;
}
/* ---------------------- */
/* Assert necs and necs->channel is nonNull. */
static void nlaevalchan_assert_nonNull(NlaEvalChannelSnapshot *necs)
{
UNUSED_VARS_NDEBUG(necs);
BLI_assert(necs != NULL && necs->channel != NULL);
}
/* Assert that the channels given can be blended or combined together. */
static void nlaevalchan_assert_blendOrcombine_compatible(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
NlaEvalChannelSnapshot *blended_necs)
{
UNUSED_VARS_NDEBUG(lower_necs, upper_necs, blended_necs);
BLI_assert(!ELEM(NULL, lower_necs, blended_necs));
BLI_assert(upper_necs == NULL || lower_necs->length == upper_necs->length);
BLI_assert(lower_necs->length == blended_necs->length);
}
/* Assert that the channels given can be blended or combined together as a quaternion. */
static void nlaevalchan_assert_blendOrcombine_compatible_quaternion(
NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
NlaEvalChannelSnapshot *blended_necs)
{
nlaevalchan_assert_blendOrcombine_compatible(lower_necs, upper_necs, blended_necs);
BLI_assert(lower_necs->length == 4);
}
static void nlaevalchan_copy_values(NlaEvalChannelSnapshot *dst, NlaEvalChannelSnapshot *src)
{
memcpy(dst->values, src->values, src->length * sizeof(float));
}
/**
* Copies lower necs to blended necs if upper necs is NULL or has zero influence.
* \return true if copied.
*/
static bool nlaevalchan_blendOrcombine_try_copy_lower(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
const float upper_influence,
NlaEvalChannelSnapshot *r_blended_necs)
{
const bool has_influence = !IS_EQF(upper_influence, 0.0f);
if (upper_necs != NULL && has_influence) {
return false;
}
nlaevalchan_copy_values(r_blended_necs, lower_necs);
return true;
}
/**
* Based on blend-mode, blend lower necs with upper necs into blended necs.
*
* Each upper value's blend domain determines whether to blend or to copy directly from lower.
*/
static void nlaevalchan_blend_value(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
const int upper_blendmode,
const float upper_influence,
NlaEvalChannelSnapshot *r_blended_necs)
{
nlaevalchan_assert_blendOrcombine_compatible(lower_necs, upper_necs, r_blended_necs);
if (nlaevalchan_blendOrcombine_try_copy_lower(
lower_necs, upper_necs, upper_influence, r_blended_necs)) {
return;
}
const int length = lower_necs->length;
for (int j = 0; j < length; j++) {
if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) {
r_blended_necs->values[j] = lower_necs->values[j];
continue;
}
r_blended_necs->values[j] = nla_blend_value(
upper_blendmode, lower_necs->values[j], upper_necs->values[j], upper_influence);
}
}
/**
* Based on mix-mode, provided by one the necs,
* combines lower necs with upper necs into blended necs.
*
* Each upper value's blend domain determines whether to blend or to copy directly from lower.
*/
static void nlaevalchan_combine_value(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
const float upper_influence,
NlaEvalChannelSnapshot *r_blended_necs)
{
nlaevalchan_assert_blendOrcombine_compatible(lower_necs, upper_necs, r_blended_necs);
if (nlaevalchan_blendOrcombine_try_copy_lower(
lower_necs, upper_necs, upper_influence, r_blended_necs)) {
return;
}
/* Assumes every base is the same. */
float *base_values = lower_necs->channel->base_snapshot.values;
const int length = lower_necs->length;
const char mix_mode = lower_necs->channel->mix_mode;
for (int j = 0; j < length; j++) {
if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) {
r_blended_necs->values[j] = lower_necs->values[j];
continue;
}
r_blended_necs->values[j] = nla_combine_value(
mix_mode, base_values[j], lower_necs->values[j], upper_necs->values[j], upper_influence);
}
}
/**
* Quaternion combines lower necs with upper necs into blended necs.
*
* Each upper value's blend domain determines whether to blend or to copy directly
* from lower.
*/
static void nlaevalchan_combine_quaternion(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
const float upper_influence,
NlaEvalChannelSnapshot *r_blended_necs)
{
nlaevalchan_assert_blendOrcombine_compatible_quaternion(lower_necs, upper_necs, r_blended_necs);
if (nlaevalchan_blendOrcombine_try_copy_lower(
lower_necs, upper_necs, upper_influence, r_blended_necs)) {
return;
}
/** No need to check per index. We limit to all or nothing combining for quaternions. */
if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, 0)) {
nlaevalchan_copy_values(r_blended_necs, lower_necs);
return;
}
nla_combine_quaternion(
lower_necs->values, upper_necs->values, upper_influence, r_blended_necs->values);
}
/**
* Based on blendmode and mixmode, blend lower necs with upper necs into blended necs.
*
* Each upper value's blend domain determines whether to blend or to copy directly
* from lower.
*
* \param lower_necs: Never NULL.
* \param upper_necs: Can be NULL.
* \param upper_blendmode: Enum value in eNlaStrip_Blend_Mode.
* \param upper_influence: Value in range [0, 1].
* \param upper_necs: Never NULL.
*
*/
static void nlaevalchan_blendOrcombine(NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *upper_necs,
const int upper_blendmode,
const float upper_influence,
NlaEvalChannelSnapshot *r_blended_necs)
{
nlaevalchan_assert_nonNull(r_blended_necs);
switch (upper_blendmode) {
case NLASTRIP_MODE_COMBINE: {
switch (r_blended_necs->channel->mix_mode) {
case NEC_MIX_QUATERNION: {
nlaevalchan_combine_quaternion(lower_necs, upper_necs, upper_influence, r_blended_necs);
return;
}
case NEC_MIX_ADD:
case NEC_MIX_AXIS_ANGLE:
case NEC_MIX_MULTIPLY: {
nlaevalchan_combine_value(lower_necs, upper_necs, upper_influence, r_blended_necs);
return;
}
default:
BLI_assert("Mix mode should've been handled");
}
return;
}
case NLASTRIP_MODE_ADD:
case NLASTRIP_MODE_SUBTRACT:
case NLASTRIP_MODE_MULTIPLY:
case NLASTRIP_MODE_REPLACE: {
nlaevalchan_blend_value(
lower_necs, upper_necs, upper_blendmode, upper_influence, r_blended_necs);
return;
}
default:
BLI_assert("Blend mode should've been handled");
}
}
/**
* Based on blend-mode, solve for the upper values such that when lower blended with upper then we
* get blended values as a result.
*
* Only processes blended values in the remap domain. Successfully remapped upper values are placed
* in the remap domain so caller knows which values are usable.
*/
static void nlaevalchan_blend_value_get_inverted_upper_evalchan(
NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *blended_necs,
const int upper_blendmode,
const float upper_influence,
NlaEvalChannelSnapshot *r_upper_necs)
{
nlaevalchan_assert_nonNull(r_upper_necs);
nlaevalchan_assert_blendOrcombine_compatible(lower_necs, r_upper_necs, blended_necs);
const int length = lower_necs->length;
for (int j = 0; j < length; j++) {
if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j)) {
BLI_BITMAP_DISABLE(r_upper_necs->remap_domain.ptr, j);
continue;
}
const bool success = nla_blend_get_inverted_strip_value(upper_blendmode,
lower_necs->values[j],
blended_necs->values[j],
upper_influence,
&r_upper_necs->values[j]);
BLI_BITMAP_SET(r_upper_necs->remap_domain.ptr, j, success);
}
}
/**
* Based on mixmode, solve for the upper values such that when lower combined with upper then we
* get blended values as a result.
*
* Only processes blended values in the remap domain. Successfully remapped upper values are placed
* in the remap domain so caller knows which values are usable.
*/
static void nlaevalchan_combine_value_get_inverted_upper_evalchan(
NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *blended_necs,
const float upper_influence,
NlaEvalChannelSnapshot *r_upper_necs)
{
nlaevalchan_assert_nonNull(r_upper_necs);
nlaevalchan_assert_blendOrcombine_compatible(lower_necs, r_upper_necs, blended_necs);
/* Assumes every channel's base is the same. */
float *base_values = lower_necs->channel->base_snapshot.values;
const int length = lower_necs->length;
const char mix_mode = lower_necs->channel->mix_mode;
for (int j = 0; j < length; j++) {
if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j)) {
BLI_BITMAP_DISABLE(r_upper_necs->remap_domain.ptr, j);
continue;
}
const bool success = nla_combine_get_inverted_strip_value(mix_mode,
base_values[j],
lower_necs->values[j],
blended_necs->values[j],
upper_influence,
&r_upper_necs->values[j]);
BLI_BITMAP_SET(r_upper_necs->remap_domain.ptr, j, success);
}
}
/**
* Solve for the upper values such that when lower quaternion combined with upper then we get
* blended values as a result.
*
* All blended values must be in the remap domain. If successfully remapped, then all upper values
* are placed in the remap domain so caller knows the result is usable.
*/
static void nlaevalchan_combine_quaternion_get_inverted_upper_evalchan(
NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *blended_necs,
const float upper_influence,
NlaEvalChannelSnapshot *r_upper_necs)
{
nlaevalchan_assert_nonNull(r_upper_necs);
nlaevalchan_assert_blendOrcombine_compatible_quaternion(lower_necs, r_upper_necs, blended_necs);
/* Must check each domain index individually in case animator had a non-combine NLA strip with a
* subset of quaternion channels and remapping through any of them failed and thus potentially
* has undefined values. */
for (int j = 0; j < 4; j++) {
if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, j)) {
BLI_bitmap_set_all(r_upper_necs->remap_domain.ptr, false, 4);
return;
}
}
const bool success = nla_combine_quaternion_get_inverted_strip_values(
lower_necs->values, blended_necs->values, upper_influence, r_upper_necs->values);
BLI_bitmap_set_all(r_upper_necs->remap_domain.ptr, success, 4);
}
/**
* Based on blend-mode and mix mode, solve for the upper values such that when lower blended or
* combined with upper then we get blended values as a result.
*
* Only processes blended values in the remap domain. Successfully remapped upper values are placed
* in the remap domain so caller knows which values are usable.
*
* \param lower_necs: Never NULL.
* \param blended_necs: Never NULL.
* \param upper_blendmode: Enum value in eNlaStrip_Blend_Mode.
* \param upper_influence: Value in range [0, 1].
* \param r_upper_necs: Never NULL.
*/
static void nlaevalchan_blendOrcombine_get_inverted_upper_evalchan(
NlaEvalChannelSnapshot *lower_necs,
NlaEvalChannelSnapshot *blended_necs,
const int upper_blendmode,
const float upper_influence,
NlaEvalChannelSnapshot *r_upper_necs)
{
nlaevalchan_assert_nonNull(r_upper_necs);
if (IS_EQF(upper_influence, 0.0f)) {
BLI_bitmap_set_all(r_upper_necs->remap_domain.ptr, false, r_upper_necs->length);
return;
}
switch (upper_blendmode) {
case NLASTRIP_MODE_COMBINE: {
switch (r_upper_necs->channel->mix_mode) {
case NEC_MIX_QUATERNION: {
nlaevalchan_combine_quaternion_get_inverted_upper_evalchan(
lower_necs, blended_necs, upper_influence, r_upper_necs);
return;
}
case NEC_MIX_ADD:
case NEC_MIX_AXIS_ANGLE:
case NEC_MIX_MULTIPLY: {
nlaevalchan_combine_value_get_inverted_upper_evalchan(
lower_necs, blended_necs, upper_influence, r_upper_necs);
return;
}
default:
BLI_assert("Mix mode should've been handled");
}
return;
}
case NLASTRIP_MODE_ADD:
case NLASTRIP_MODE_SUBTRACT:
case NLASTRIP_MODE_MULTIPLY:
case NLASTRIP_MODE_REPLACE: {
nlaevalchan_blend_value_get_inverted_upper_evalchan(
lower_necs, blended_necs, upper_blendmode, upper_influence, r_upper_necs);
return;
}
default:
BLI_assert("Blend mode should've been handled");
}
}
/* ---------------------- */
/* F-Modifier stack joining/separation utilities -
* should we generalize these for BLI_listbase.h interface? */
@ -2513,11 +2872,7 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
{
nlaeval_snapshot_ensure_size(r_blended_snapshot, eval_data->num_channels);
const bool zero_upper_influence = IS_EQF(upper_influence, 0.0f);
LISTBASE_FOREACH (NlaEvalChannel *, nec, &eval_data->channels) {
const int length = nec->base_snapshot.length;
NlaEvalChannelSnapshot *upper_necs = nlaeval_snapshot_get(upper_snapshot, nec->index);
NlaEvalChannelSnapshot *lower_necs = nlaeval_snapshot_get(lower_snapshot, nec->index);
if (upper_necs == NULL && lower_necs == NULL) {
@ -2530,49 +2885,44 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
}
NlaEvalChannelSnapshot *result_necs = nlaeval_snapshot_ensure_channel(r_blended_snapshot, nec);
nlaevalchan_blendOrcombine(
lower_necs, upper_necs, upper_blendmode, upper_influence, result_necs);
}
}
/** Always copy \a lower_snapshot to result, irrelevant of whether \a upper_snapshot has a
* corresponding channel. This only matters when \a lower_snapshot not the same as
* \a r_blended_snapshot. */
memcpy(result_necs->values, lower_necs->values, length * sizeof(float));
if (upper_necs == NULL || zero_upper_influence) {
/**
* Using \a blended_snapshot and \a lower_snapshot, we can solve for the \a r_upper_snapshot.
*
* Only channels that exist within \a blended_snapshot are inverted.
*
* For \a r_upper_snapshot, disables \a NlaEvalChannelSnapshot->remap_domain for failed inversions.
* Only values within the \a remap_domain are processed.
*/
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
const short upper_blendmode,
const float upper_influence,
NlaEvalSnapshot *r_upper_snapshot)
{
nlaeval_snapshot_ensure_size(r_upper_snapshot, eval_data->num_channels);
LISTBASE_FOREACH (NlaEvalChannel *, nec, &eval_data->channels) {
NlaEvalChannelSnapshot *blended_necs = nlaeval_snapshot_get(blended_snapshot, nec->index);
if (blended_necs == NULL) {
/** We assume the caller only wants a subset of channels to be inverted, those that exist
* within \a blended_snapshot. */
continue;
}
if (upper_blendmode == NLASTRIP_MODE_COMBINE) {
const int mix_mode = nec->mix_mode;
if (mix_mode == NEC_MIX_QUATERNION) {
if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, 0)) {
continue;
}
nla_combine_quaternion(
lower_necs->values, upper_necs->values, upper_influence, result_necs->values);
}
else {
for (int j = 0; j < length; j++) {
if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) {
continue;
}
result_necs->values[j] = nla_combine_value(mix_mode,
nec->base_snapshot.values[j],
lower_necs->values[j],
upper_necs->values[j],
upper_influence);
}
}
NlaEvalChannelSnapshot *lower_necs = nlaeval_snapshot_get(lower_snapshot, nec->index);
if (lower_necs == NULL) {
lower_necs = nlaeval_snapshot_find_channel(lower_snapshot->base, nec);
}
else {
for (int j = 0; j < length; j++) {
if (!BLI_BITMAP_TEST_BOOL(upper_necs->blend_domain.ptr, j)) {
continue;
}
result_necs->values[j] = nla_blend_value(
upper_blendmode, lower_necs->values[j], upper_necs->values[j], upper_influence);
}
}
NlaEvalChannelSnapshot *result_necs = nlaeval_snapshot_ensure_channel(r_upper_snapshot, nec);
nlaevalchan_blendOrcombine_get_inverted_upper_evalchan(
lower_necs, blended_necs, upper_blendmode, upper_influence, result_necs);
}
}
@ -2670,74 +3020,64 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
return false;
}
/* Find the evaluation channel for the NLA stack below current strip. */
/** Create \a blended_snapshot and fill with input \a values. */
NlaEvalData *eval_data = &context->lower_eval_data;
NlaEvalSnapshot blended_snapshot;
nlaeval_snapshot_init(&blended_snapshot, eval_data, NULL);
NlaEvalChannelKey key = {
.ptr = *prop_ptr,
.prop = prop,
};
/**
* Remove lower NLA stack effects.
*
* Using the tweak strip's blended result and the lower snapshot value, we can solve for the
* tweak strip value it must evaluate to.
*/
NlaEvalData *const lower_eval_data = &context->lower_eval_data;
NlaEvalChannel *const lower_nec = nlaevalchan_verify_key(lower_eval_data, NULL, &key);
if ((lower_nec->base_snapshot.length != count)) {
NlaEvalChannel *nec = nlaevalchan_verify_key(eval_data, NULL, &key);
BLI_assert(nec);
if (nec->base_snapshot.length != count) {
BLI_assert(!"invalid value count");
nlaeval_snapshot_free_data(&blended_snapshot);
return false;
}
/* Invert the blending operation to compute the desired strip values. */
NlaEvalChannelSnapshot *const lower_nec_snapshot = nlaeval_snapshot_find_channel(
&lower_eval_data->eval_snapshot, lower_nec);
NlaEvalChannelSnapshot *blended_necs = nlaeval_snapshot_ensure_channel(&blended_snapshot, nec);
memcpy(blended_necs->values, values, sizeof(float) * count);
BLI_bitmap_set_all(blended_necs->remap_domain.ptr, true, count);
float *lower_values = lower_nec_snapshot->values;
/** Remove lower NLA stack effects. */
nlasnapshot_blend_get_inverted_upper_snapshot(eval_data,
&context->lower_eval_data.eval_snapshot,
&blended_snapshot,
blend_mode,
influence,
&blended_snapshot);
if (blend_mode == NLASTRIP_MODE_COMBINE) {
/* Quaternion combine handles all sub-channels as a unit. */
if (lower_nec->mix_mode == NEC_MIX_QUATERNION) {
if (r_force_all == NULL) {
return false;
}
/** Write results into \a values. */
bool successful_remap = true;
if (blended_necs->channel->mix_mode == NEC_MIX_QUATERNION &&
blend_mode == NLASTRIP_MODE_COMBINE) {
if (r_force_all != NULL) {
*r_force_all = true;
if (!nla_combine_quaternion_get_inverted_strip_values(
lower_values, values, influence, values)) {
return false;
}
index = -1;
}
else {
float *base_values = lower_nec->base_snapshot.values;
for (int i = 0; i < count; i++) {
if (ELEM(index, i, -1)) {
if (!nla_combine_get_inverted_strip_value(lower_nec->mix_mode,
base_values[i],
lower_values[i],
values[i],
influence,
&values[i])) {
return false;
}
}
}
}
}
else {
for (int i = 0; i < count; i++) {
if (ELEM(index, i, -1)) {
if (!nla_blend_get_inverted_strip_value(
blend_mode, lower_values[i], values[i], influence, &values[i])) {
return false;
}
}
successful_remap = false;
}
}
return true;
for (int i = 0; i < count; i++) {
if (!ELEM(index, i, -1)) {
continue;
}
if (!BLI_BITMAP_TEST_BOOL(blended_necs->remap_domain.ptr, i)) {
successful_remap = false;
}
values[i] = blended_necs->values[i];
}
nlaeval_snapshot_free_data(&blended_snapshot);
return successful_remap;
}
/**

View File

@ -2881,7 +2881,8 @@ bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden
NULL;
if (bb_custom) {
float mat[4][4], smat[4][4];
scale_m4_fl(smat, PCHAN_CUSTOM_DRAW_SIZE(pchan));
scale_m4_fl(smat, PCHAN_CUSTOM_BONE_LENGTH(pchan));
mul_m4_v3(smat, pchan->custom_scale_xyz);
mul_m4_series(mat, ob->obmat, pchan_tx->pose_mat, smat);
BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
}

View File

@ -27,12 +27,34 @@ using blender::float3;
using blender::float4x4;
using blender::Span;
blender::Span<SplinePtr> CurveEval::splines() const
{
return splines_;
}
blender::MutableSpan<SplinePtr> CurveEval::splines()
{
return splines_;
}
void CurveEval::add_spline(SplinePtr spline)
{
splines_.append(std::move(spline));
}
void CurveEval::remove_splines(blender::IndexMask mask)
{
for (int i = mask.size() - 1; i >= 0; i--) {
splines_.remove_and_reorder(mask.indices()[i]);
}
}
CurveEval *CurveEval::copy()
{
CurveEval *new_curve = new CurveEval();
for (SplinePtr &spline : this->splines) {
new_curve->splines.append(spline->copy());
for (SplinePtr &spline : this->splines()) {
new_curve->add_spline(spline->copy());
}
return new_curve;
@ -40,7 +62,7 @@ CurveEval *CurveEval::copy()
void CurveEval::translate(const float3 &translation)
{
for (SplinePtr &spline : this->splines) {
for (SplinePtr &spline : this->splines()) {
spline->translate(translation);
spline->mark_cache_invalid();
}
@ -48,14 +70,14 @@ void CurveEval::translate(const float3 &translation)
void CurveEval::transform(const float4x4 &matrix)
{
for (SplinePtr &spline : this->splines) {
for (SplinePtr &spline : this->splines()) {
spline->transform(matrix);
}
}
void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
{
for (const SplinePtr &spline : this->splines) {
for (const SplinePtr &spline : this->splines()) {
spline->bounds_min_max(min, max, use_evaluated);
}
}
@ -115,8 +137,6 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
const ListBase *nurbs = BKE_curve_nurbs_get(&const_cast<Curve &>(dna_curve));
curve->splines.reserve(BLI_listbase_count(nurbs));
/* TODO: Optimize by reserving the correct points size. */
LISTBASE_FOREACH (const Nurb *, nurb, nurbs) {
switch (nurb->type) {
@ -135,7 +155,7 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
bezt.tilt);
}
curve->splines.append(std::move(spline));
curve->add_spline(std::move(spline));
break;
}
case CU_NURBS: {
@ -149,7 +169,7 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
spline->add_point(bp.vec, bp.radius, bp.tilt, bp.vec[3]);
}
curve->splines.append(std::move(spline));
curve->add_spline(std::move(spline));
break;
}
case CU_POLY: {
@ -160,7 +180,7 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
spline->add_point(bp.vec, bp.radius, bp.tilt);
}
curve->splines.append(std::move(spline));
curve->add_spline(std::move(spline));
break;
}
default: {
@ -174,7 +194,7 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
* from multiple curve objects, where the value may be different. */
const Spline::NormalCalculationMode normal_mode = normal_mode_from_dna_curve(
dna_curve.twist_mode);
for (SplinePtr &spline : curve->splines) {
for (SplinePtr &spline : curve->splines()) {
spline->normal_mode = normal_mode;
}

View File

@ -115,7 +115,7 @@ void CurveComponent::ensure_owns_direct_data()
/** \} */
/* -------------------------------------------------------------------- */
/** \name Attribute Access
/** \name Attribute Access Helper Functions
* \{ */
int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
@ -125,23 +125,44 @@ int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
}
if (domain == ATTR_DOMAIN_POINT) {
int total = 0;
for (const SplinePtr &spline : curve_->splines) {
for (const SplinePtr &spline : curve_->splines()) {
total += spline->size();
}
return total;
}
if (domain == ATTR_DOMAIN_CURVE) {
return curve_->splines.size();
return curve_->splines().size();
}
return 0;
}
static CurveEval *get_curve_from_component_for_write(GeometryComponent &component)
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
CurveComponent &curve_component = static_cast<CurveComponent &>(component);
return curve_component.get_for_write();
}
static const CurveEval *get_curve_from_component_for_read(const GeometryComponent &component)
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
return curve_component.get_for_read();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Builtin Spline Attributes
*
* Attributes with a value for every spline, stored contiguously or in every spline separately.
* \{ */
namespace blender::bke {
class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
using AsReadAttribute = GVArrayPtr (*)(const CurveEval &data);
using AsWriteAttribute = GVMutableArrayPtr (*)(CurveEval &data);
using UpdateOnWrite = void (*)(Spline &spline);
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
@ -164,12 +185,10 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
{
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
const CurveEval *curve = curve_component.get_for_read();
const CurveEval *curve = get_curve_from_component_for_read(component);
if (curve == nullptr) {
return {};
}
return as_read_attribute_(*curve);
}
@ -178,12 +197,10 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
if (writable_ != Writable) {
return {};
}
CurveComponent &curve_component = static_cast<CurveComponent &>(component);
CurveEval *curve = curve_component.get_for_write();
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
return {};
}
return as_write_attribute_(*curve);
}
@ -228,7 +245,7 @@ static void set_spline_resolution(SplinePtr &spline, const int resolution)
static GVArrayPtr make_resolution_read_attribute(const CurveEval &curve)
{
return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, int, get_spline_resolution>>(
curve.splines.as_span());
curve.splines());
}
static GVMutableArrayPtr make_resolution_write_attribute(CurveEval &curve)
@ -237,7 +254,7 @@ static GVMutableArrayPtr make_resolution_write_attribute(CurveEval &curve)
int,
get_spline_resolution,
set_spline_resolution>>(
curve.splines.as_mutable_span());
curve.splines());
}
static bool get_cyclic_value(const SplinePtr &spline)
@ -256,16 +273,434 @@ static void set_cyclic_value(SplinePtr &spline, const bool value)
static GVArrayPtr make_cyclic_read_attribute(const CurveEval &curve)
{
return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value>>(
curve.splines.as_span());
curve.splines());
}
static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve)
{
return std::make_unique<
fn::GVMutableArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value, set_cyclic_value>>(
curve.splines.as_mutable_span());
curve.splines());
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Builtin Control Point Attributes
*
* Attributes with a value for every control point. Most of the complexity here is due to the fact
* that we must provide access to the attribute data as if it was a contiguous array when it is
* really stored separately on each spline. That will be inherently rather slow, but these virtual
* array implementations try to make it workable in common situations.
* \{ */
static Array<int> control_point_offsets(const CurveEval &curve)
{
Span<SplinePtr> splines = curve.splines();
Array<int> offsets(splines.size() + 1);
int size = 0;
for (const int spline_index : splines.index_range()) {
offsets[spline_index] = size;
size += splines[spline_index]->size();
}
offsets.last() = size;
return offsets;
}
namespace {
struct PointIndices {
int spline_index;
int point_index;
};
} // namespace
static PointIndices lookup_point_indices(Span<int> offsets, const int index)
{
const int spline_index = std::upper_bound(offsets.begin(), offsets.end(), index) -
offsets.begin() - 1;
const int index_in_spline = index - offsets[spline_index];
return {spline_index, index_in_spline};
}
template<typename T>
static void point_attribute_materialize(Span<Span<T>> data,
Span<int> offsets,
const IndexMask mask,
MutableSpan<T> r_span)
{
const int total_size = offsets.last();
if (mask.is_range() && mask.as_range() == IndexRange(total_size)) {
for (const int spline_index : data.index_range()) {
const int offset = offsets[spline_index];
const int next_offset = offsets[spline_index + 1];
initialized_copy_n(data[spline_index].data(), next_offset - offset, r_span.data() + offset);
}
}
else {
int spline_index = 0;
for (const int i : r_span.index_range()) {
const int dst_index = mask[i];
while (offsets[spline_index] < dst_index) {
spline_index++;
}
const int index_in_spline = dst_index - offsets[spline_index];
r_span[dst_index] = data[spline_index][index_in_spline];
}
}
}
template<typename T>
static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data,
Span<int> offsets,
const IndexMask mask,
MutableSpan<T> r_span)
{
T *dst = r_span.data();
const int total_size = offsets.last();
if (mask.is_range() && mask.as_range() == IndexRange(total_size)) {
for (const int spline_index : data.index_range()) {
const int offset = offsets[spline_index];
const int next_offset = offsets[spline_index + 1];
uninitialized_copy_n(data[spline_index].data(), next_offset - offset, dst + offset);
}
}
else {
int spline_index = 0;
for (const int i : r_span.index_range()) {
const int dst_index = mask[i];
while (offsets[spline_index] < dst_index) {
spline_index++;
}
const int index_in_spline = dst_index - offsets[spline_index];
new (dst + dst_index) T(data[spline_index][index_in_spline]);
}
}
}
/**
* Virtual array for any control point data accessed with spans and an offset array.
*/
template<typename T> class VArray_For_SplinePoints : public VArray<T> {
private:
const Array<Span<T>> data_;
Array<int> offsets_;
public:
VArray_For_SplinePoints(Array<Span<T>> data, Array<int> offsets)
: VArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
{
}
T get_impl(const int64_t index) const final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
return data_[indices.spline_index][indices.point_index];
}
void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final
{
point_attribute_materialize(data_.as_span(), offsets_, mask, r_span);
}
void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final
{
point_attribute_materialize_to_uninitialized(data_.as_span(), offsets_, mask, r_span);
}
};
/**
* Mutable virtual array for any control point data accessed with spans and an offset array.
*/
template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArray<T> {
private:
Array<MutableSpan<T>> data_;
Array<int> offsets_;
public:
VMutableArray_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
: VMutableArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
{
}
T get_impl(const int64_t index) const final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
return data_[indices.spline_index][indices.point_index];
}
void set_impl(const int64_t index, T value) final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
data_[indices.spline_index][indices.point_index] = value;
}
void set_all_impl(Span<T> src) final
{
for (const int spline_index : data_.index_range()) {
const int offset = offsets_[spline_index];
const int next_offsets = offsets_[spline_index + 1];
data_[spline_index].copy_from(src.slice(offset, next_offsets - offset));
}
}
void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final
{
point_attribute_materialize({(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
}
void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final
{
point_attribute_materialize_to_uninitialized(
{(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
}
};
/**
* Virtual array implementation specifically for control point positions. This is only needed for
* Bezier splines, where adjusting the position also needs to adjust handle positions depending on
* the handle types. We pay a small price for this when other spline types are mixed with Bezier.
*
* \note There is no need to check the handle type to avoid changing auto handles, since
* retrieving write access to the position data will mark them for recomputation anyway.
*/
class VMutableArray_For_SplinePosition final : public VMutableArray<float3> {
private:
MutableSpan<SplinePtr> splines_;
Array<int> offsets_;
public:
VMutableArray_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
: VMutableArray<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets))
{
}
float3 get_impl(const int64_t index) const final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
return splines_[indices.spline_index]->positions()[indices.point_index];
}
void set_impl(const int64_t index, float3 value) final
{
const PointIndices indices = lookup_point_indices(offsets_, index);
Spline &spline = *splines_[indices.spline_index];
if (BezierSpline *bezier_spline = dynamic_cast<BezierSpline *>(&spline)) {
const float3 delta = value - bezier_spline->positions()[indices.point_index];
bezier_spline->handle_positions_left()[indices.point_index] += delta;
bezier_spline->handle_positions_right()[indices.point_index] += delta;
bezier_spline->positions()[indices.point_index] = value;
}
else {
spline.positions()[indices.point_index] = value;
}
}
void set_all_impl(Span<float3> src) final
{
for (const int spline_index : splines_.index_range()) {
Spline &spline = *splines_[spline_index];
const int offset = offsets_[spline_index];
const int next_offset = offsets_[spline_index + 1];
if (BezierSpline *bezier_spline = dynamic_cast<BezierSpline *>(&spline)) {
MutableSpan<float3> positions = bezier_spline->positions();
MutableSpan<float3> handle_positions_left = bezier_spline->handle_positions_left();
MutableSpan<float3> handle_positions_right = bezier_spline->handle_positions_right();
for (const int i : IndexRange(next_offset - offset)) {
const float3 delta = src[offset + i] - positions[i];
handle_positions_left[i] += delta;
handle_positions_right[i] += delta;
positions[i] = src[offset + i];
}
}
else {
spline.positions().copy_from(src.slice(offset, next_offset - offset));
}
}
}
/** Utility so we can pass positions to the materialize functions above. */
Array<Span<float3>> get_position_spans() const
{
Array<Span<float3>> spans(splines_.size());
for (const int i : spans.index_range()) {
spans[i] = splines_[i]->positions();
}
return spans;
}
void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final
{
Array<Span<float3>> spans = this->get_position_spans();
point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
}
void materialize_to_uninitialized_impl(const IndexMask mask,
MutableSpan<float3> r_span) const final
{
Array<Span<float3>> spans = this->get_position_spans();
point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
}
};
/**
* Provider for any builtin control point attribute that doesn't need
* special handling such as access to other arrays in the spline.
*/
template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttributeProvider {
protected:
using GetSpan = Span<T> (*)(const Spline &spline);
using GetMutableSpan = MutableSpan<T> (*)(Spline &spline);
using UpdateOnWrite = void (*)(Spline &spline);
const GetSpan get_span_;
const GetMutableSpan get_mutable_span_;
const UpdateOnWrite update_on_write_;
public:
BuiltinPointAttributeProvider(std::string attribute_name,
const WritableEnum writable,
const GetSpan get_span,
const GetMutableSpan get_mutable_span,
const UpdateOnWrite update_on_write)
: BuiltinAttributeProvider(std::move(attribute_name),
ATTR_DOMAIN_POINT,
bke::cpp_type_to_custom_data_type(CPPType::get<T>()),
BuiltinAttributeProvider::NonCreatable,
writable,
BuiltinAttributeProvider::NonDeletable),
get_span_(get_span),
get_mutable_span_(get_mutable_span),
update_on_write_(update_on_write)
{
}
GVArrayPtr try_get_for_read(const GeometryComponent &component) const override
{
const CurveEval *curve = get_curve_from_component_for_read(component);
if (curve == nullptr) {
return {};
}
Span<SplinePtr> splines = curve->splines();
if (splines.size() == 1) {
return std::make_unique<fn::GVArray_For_GSpan>(get_span_(*splines.first()));
}
Array<int> offsets = control_point_offsets(*curve);
Array<Span<T>> spans(splines.size());
for (const int i : splines.index_range()) {
spans[i] = get_span_(*splines[i]);
}
return std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplinePoints<T>>>(
offsets.last(), std::move(spans), std::move(offsets));
}
GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const override
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
return {};
}
MutableSpan<SplinePtr> splines = curve->splines();
if (splines.size() == 1) {
return std::make_unique<fn::GVMutableArray_For_GMutableSpan>(
get_mutable_span_(*splines.first()));
}
Array<int> offsets = control_point_offsets(*curve);
Array<MutableSpan<T>> spans(splines.size());
for (const int i : splines.index_range()) {
spans[i] = get_mutable_span_(*splines[i]);
if (update_on_write_) {
update_on_write_(*splines[i]);
}
}
return std::make_unique<
fn::GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_SplinePoints<T>>>(
offsets.last(), std::move(spans), std::move(offsets));
}
bool try_delete(GeometryComponent &UNUSED(component)) const final
{
return false;
}
bool try_create(GeometryComponent &UNUSED(component),
const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
bool exists(const GeometryComponent &component) const final
{
return component.attribute_domain_size(ATTR_DOMAIN_POINT) != 0;
}
};
/**
* Special attribute provider for the position attribute. Having this separate means we don't
* need to make #BuiltinPointAttributeProvider overly generic, and the special handling for the
* positions is more clear.
*/
class PositionAttributeProvider final : public BuiltinPointAttributeProvider<float3> {
public:
PositionAttributeProvider()
: BuiltinPointAttributeProvider(
"position",
BuiltinAttributeProvider::Writable,
[](const Spline &spline) { return spline.positions(); },
[](Spline &spline) { return spline.positions(); },
[](Spline &spline) { spline.mark_cache_invalid(); })
{
}
GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final
{
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
return {};
}
/* Changing the positions requires recalculation of cached evaluated data in many cases.
* This could set more specific flags in the future to avoid unnecessary recomputation. */
bool curve_has_bezier_spline = false;
for (SplinePtr &spline : curve->splines()) {
if (spline->type() == Spline::Type::Bezier) {
curve_has_bezier_spline = true;
break;
}
}
/* Use the regular position virtual array there are any bezier splines to potentially avoid
* using the special position virtual array when there are no Bezier splines anyway. */
if (!curve_has_bezier_spline) {
return BuiltinPointAttributeProvider<float3>::try_get_for_write(component);
}
for (SplinePtr &spline : curve->splines()) {
spline->mark_cache_invalid();
}
Array<int> offsets = control_point_offsets(*curve);
return std::make_unique<
fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_SplinePosition>>(
offsets.last(), curve->splines(), std::move(offsets));
}
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name Attribute Provider Declaration
* \{ */
/**
* In this function all the attribute providers for a curve component are created. Most data
* in this function is statically allocated, because it does not change over time.
@ -284,7 +719,23 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
make_cyclic_read_attribute,
make_cyclic_write_attribute);
return ComponentAttributeProviders({&resolution, &cyclic}, {});
static PositionAttributeProvider position;
static BuiltinPointAttributeProvider<float> radius(
"radius",
BuiltinAttributeProvider::Writable,
[](const Spline &spline) { return spline.radii(); },
[](Spline &spline) { return spline.radii(); },
nullptr);
static BuiltinPointAttributeProvider<float> tilt(
"tilt",
BuiltinAttributeProvider::Writable,
[](const Spline &spline) { return spline.tilts(); },
[](Spline &spline) { return spline.tilts(); },
[](Spline &spline) { spline.mark_cache_invalid(); });
return ComponentAttributeProviders({&position, &radius, &tilt, &resolution, &cyclic}, {});
}
} // namespace blender::bke

View File

@ -528,11 +528,11 @@ static void join_curve_splines(Span<GeometryInstanceGroup> set_groups, CurveComp
}
const CurveEval &source_curve = *set.get_curve_for_read();
for (const SplinePtr &source_spline : source_curve.splines) {
for (const SplinePtr &source_spline : source_curve.splines()) {
for (const float4x4 &transform : set_group.transforms) {
SplinePtr new_spline = source_spline->copy();
new_spline->transform(transform);
new_curve->splines.append(std::move(new_spline));
new_curve->add_spline(std::move(new_spline));
}
}
}

View File

@ -735,6 +735,37 @@ int BKE_image_get_tile_from_pos(struct Image *ima,
return tile_number;
}
/**
* Return the tile_number for the closest UDIM tile.
*/
int BKE_image_find_nearest_tile(const Image *image, const float co[2])
{
const float co_floor[2] = {floorf(co[0]), floorf(co[1])};
/* Distance to the closest UDIM tile. */
float dist_best_sq = FLT_MAX;
int tile_number_best = -1;
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
const int tile_index = tile->tile_number - 1001;
/* Coordinates of the current tile. */
const float tile_index_co[2] = {tile_index % 10, tile_index / 10};
if (equals_v2v2(co_floor, tile_index_co)) {
return tile->tile_number;
}
/* Distance between co[2] and UDIM tile. */
const float dist_sq = len_squared_v2v2(tile_index_co, co);
if (dist_sq < dist_best_sq) {
dist_best_sq = dist_sq;
tile_number_best = tile->tile_number;
}
}
return tile_number_best;
}
static void image_init_color_management(Image *ima)
{
ImBuf *ibuf;

View File

@ -1669,7 +1669,7 @@ bool BKE_lib_override_library_property_operation_operands_validate(
return true;
}
/** Check against potential \a bmain. */
/** Check against potential \a bmain. */
void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports)
{
if (id->override_library == NULL) {
@ -1703,7 +1703,7 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
}
}
/** Check against potential \a bmain. */
/** Check against potential \a bmain. */
void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
{
ID *id;

View File

@ -303,6 +303,16 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket
BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value;
BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value;
BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@ -434,6 +444,12 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
case SOCK_COLLECTION:
BLO_write_struct(writer, bNodeSocketValueCollection, sock->default_value);
break;
case SOCK_TEXTURE:
BLO_write_struct(writer, bNodeSocketValueTexture, sock->default_value);
break;
case SOCK_MATERIAL:
BLO_write_struct(writer, bNodeSocketValueMaterial, sock->default_value);
break;
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
@ -820,6 +836,16 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock
BLO_read_id_address(reader, lib, &default_value->value);
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value;
BLO_read_id_address(reader, lib, &default_value->value);
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value;
BLO_read_id_address(reader, lib, &default_value->value);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@ -905,6 +931,16 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock)
BLO_expand(expander, default_value->value);
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value;
BLO_expand(expander, default_value->value);
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value;
BLO_expand(expander, default_value->value);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@ -1472,6 +1508,16 @@ static void socket_id_user_increment(bNodeSocket *sock)
id_us_plus((ID *)default_value->value);
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value;
id_us_plus((ID *)default_value->value);
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value;
id_us_plus((ID *)default_value->value);
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@ -1511,6 +1557,20 @@ static void socket_id_user_decrement(bNodeSocket *sock)
}
break;
}
case SOCK_TEXTURE: {
bNodeSocketValueTexture *default_value = (bNodeSocketValueTexture *)sock->default_value;
if (default_value->value != nullptr) {
id_us_min(&default_value->value->id);
}
break;
}
case SOCK_MATERIAL: {
bNodeSocketValueMaterial *default_value = (bNodeSocketValueMaterial *)sock->default_value;
if (default_value->value != nullptr) {
id_us_min(&default_value->value->id);
}
break;
}
case SOCK_FLOAT:
case SOCK_VECTOR:
case SOCK_RGBA:
@ -1654,6 +1714,10 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketGeometry";
case SOCK_COLLECTION:
return "NodeSocketCollection";
case SOCK_TEXTURE:
return "NodeSocketTexture";
case SOCK_MATERIAL:
return "NodeSocketMaterial";
}
return nullptr;
}
@ -1725,6 +1789,10 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceGeometry";
case SOCK_COLLECTION:
return "NodeSocketInterfaceCollection";
case SOCK_TEXTURE:
return "NodeSocketInterfaceTexture";
case SOCK_MATERIAL:
return "NodeSocketInterfaceMaterial";
}
return nullptr;
}
@ -4962,6 +5030,7 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_separate_xyz();
register_node_type_geo_attribute_transfer();
register_node_type_geo_attribute_vector_math();
register_node_type_geo_attribute_vector_rotate();
register_node_type_geo_attribute_remove();
register_node_type_geo_boolean();
register_node_type_geo_bounding_box();

View File

@ -152,6 +152,7 @@ void BKE_nodetree_error_message_add(bNodeTree &ntree,
node_error_message_log(ntree, node, message, type);
NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ntree, context, node);
std::lock_guard lock{node_ui_storage.mutex};
node_ui_storage.warnings.append({type, std::move(message)});
}
@ -163,6 +164,7 @@ void BKE_nodetree_attribute_hint_add(bNodeTree &ntree,
const CustomDataType data_type)
{
NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ntree, context, node);
std::lock_guard lock{node_ui_storage.mutex};
node_ui_storage.attribute_hints.add_as(
AvailableAttributeInfo{attribute_name, domain, data_type});
}

View File

@ -829,13 +829,13 @@ static void calculate_collision_balls(Object *ob)
}
/* creates new softbody if didn't exist yet, makes new points and springs arrays */
static void renew_softbody(Scene *scene, Object *ob, int totpoint, int totspring)
static void renew_softbody(Object *ob, int totpoint, int totspring)
{
SoftBody *sb;
int i;
short softflag;
if (ob->soft == NULL) {
ob->soft = sbNew(scene);
ob->soft = sbNew();
}
else {
free_softbody_intern(ob->soft);
@ -2679,7 +2679,7 @@ static void springs_from_mesh(Object *ob)
}
/* makes totally fresh start situation */
static void mesh_to_softbody(Scene *scene, Object *ob)
static void mesh_to_softbody(Object *ob)
{
SoftBody *sb;
Mesh *me = ob->data;
@ -2697,7 +2697,7 @@ static void mesh_to_softbody(Scene *scene, Object *ob)
}
/* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
renew_softbody(scene, ob, me->totvert, totedge);
renew_softbody(ob, me->totvert, totedge);
/* we always make body points */
sb = ob->soft;
@ -2909,7 +2909,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object
}
/* makes totally fresh start situation */
static void lattice_to_softbody(Scene *scene, Object *ob)
static void lattice_to_softbody(Object *ob)
{
Lattice *lt = ob->data;
SoftBody *sb;
@ -2929,7 +2929,7 @@ static void lattice_to_softbody(Scene *scene, Object *ob)
}
/* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
renew_softbody(scene, ob, totvert, totspring);
renew_softbody(ob, totvert, totspring);
sb = ob->soft; /* can be created in renew_softbody() */
bp = sb->bpoint;
@ -2972,7 +2972,7 @@ static void lattice_to_softbody(Scene *scene, Object *ob)
}
/* makes totally fresh start situation */
static void curve_surf_to_softbody(Scene *scene, Object *ob)
static void curve_surf_to_softbody(Object *ob)
{
Curve *cu = ob->data;
SoftBody *sb;
@ -2993,7 +2993,7 @@ static void curve_surf_to_softbody(Scene *scene, Object *ob)
}
/* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
renew_softbody(scene, ob, totvert, totspring);
renew_softbody(ob, totvert, totspring);
sb = ob->soft; /* can be created in renew_softbody() */
/* set vars now */
@ -3117,7 +3117,7 @@ static void sb_new_scratch(SoftBody *sb)
/* ************ Object level, exported functions *************** */
/* allocates and initializes general main data */
SoftBody *sbNew(Scene *scene)
SoftBody *sbNew(void)
{
SoftBody *sb;
@ -3140,12 +3140,6 @@ SoftBody *sbNew(Scene *scene)
/*todo backward file compat should copy inspring to inpush while reading old files*/
sb->inpush = 0.5f;
sb->interval = 10;
if (scene != NULL) {
sb->sfra = scene->r.sfra;
sb->efra = scene->r.efra;
}
sb->colball = 0.49f;
sb->balldamp = 0.50f;
sb->ballstiff = 1.0f;
@ -3577,17 +3571,17 @@ void sbObjectStep(struct Depsgraph *depsgraph,
switch (ob->type) {
case OB_MESH:
mesh_to_softbody(scene, ob);
mesh_to_softbody(ob);
break;
case OB_LATTICE:
lattice_to_softbody(scene, ob);
lattice_to_softbody(ob);
break;
case OB_CURVE:
case OB_SURF:
curve_surf_to_softbody(scene, ob);
curve_surf_to_softbody(ob);
break;
default:
renew_softbody(scene, ob, numVerts, 0);
renew_softbody(ob, numVerts, 0);
break;
}

View File

@ -119,10 +119,12 @@ MutableSpan<BezierSpline::HandleType> BezierSpline::handle_types_left()
}
Span<float3> BezierSpline::handle_positions_left() const
{
this->ensure_auto_handles();
return handle_positions_left_;
}
MutableSpan<float3> BezierSpline::handle_positions_left()
{
this->ensure_auto_handles();
return handle_positions_left_;
}
Span<BezierSpline::HandleType> BezierSpline::handle_types_right() const
@ -135,13 +137,90 @@ MutableSpan<BezierSpline::HandleType> BezierSpline::handle_types_right()
}
Span<float3> BezierSpline::handle_positions_right() const
{
this->ensure_auto_handles();
return handle_positions_right_;
}
MutableSpan<float3> BezierSpline::handle_positions_right()
{
this->ensure_auto_handles();
return handle_positions_right_;
}
static float3 previous_position(Span<float3> positions, const bool cyclic, const int i)
{
if (i == 0) {
if (cyclic) {
return positions[positions.size() - 1];
}
return 2.0f * positions[i] - positions[i + 1];
}
return positions[i - 1];
}
static float3 next_position(Span<float3> positions, const bool cyclic, const int i)
{
if (i == positions.size() - 1) {
if (cyclic) {
return positions[0];
}
return 2.0f * positions[i] - positions[i - 1];
}
return positions[i + 1];
}
void BezierSpline::ensure_auto_handles() const
{
if (!auto_handles_dirty_) {
return;
}
std::lock_guard lock{auto_handle_mutex_};
if (!auto_handles_dirty_) {
return;
}
for (const int i : IndexRange(this->size())) {
if (ELEM(HandleType::Auto, handle_types_left_[i], handle_types_right_[i])) {
const float3 prev_diff = positions_[i] - previous_position(positions_, is_cyclic_, i);
const float3 next_diff = next_position(positions_, is_cyclic_, i) - positions_[i];
float prev_len = prev_diff.length();
float next_len = next_diff.length();
if (prev_len == 0.0f) {
prev_len = 1.0f;
}
if (next_len == 0.0f) {
next_len = 1.0f;
}
const float3 dir = next_diff / next_len + prev_diff / prev_len;
/* This magic number is unfortunate, but comes from elsewhere in Blender. */
const float len = dir.length() * 2.5614f;
if (len != 0.0f) {
if (handle_types_left_[i] == HandleType::Auto) {
const float prev_len_clamped = std::min(prev_len, next_len * 5.0f);
handle_positions_left_[i] = positions_[i] + dir * -(prev_len_clamped / len);
}
if (handle_types_right_[i] == HandleType::Auto) {
const float next_len_clamped = std::min(next_len, prev_len * 5.0f);
handle_positions_right_[i] = positions_[i] + dir * (next_len_clamped / len);
}
}
}
if (handle_types_left_[i] == HandleType::Vector) {
const float3 prev = previous_position(positions_, is_cyclic_, i);
handle_positions_left_[i] = float3::interpolate(positions_[i], prev, 1.0f / 3.0f);
}
if (handle_types_right_[i] == HandleType::Vector) {
const float3 next = next_position(positions_, is_cyclic_, i);
handle_positions_right_[i] = float3::interpolate(positions_[i], next, 1.0f / 3.0f);
}
}
auto_handles_dirty_ = false;
}
void BezierSpline::translate(const blender::float3 &translation)
{
for (float3 &position : this->positions()) {
@ -195,6 +274,7 @@ void BezierSpline::mark_cache_invalid()
tangent_cache_dirty_ = true;
normal_cache_dirty_ = true;
length_cache_dirty_ = true;
auto_handles_dirty_ = true;
}
int BezierSpline::evaluated_points_size() const
@ -389,6 +469,8 @@ Span<float3> BezierSpline::evaluated_positions() const
return evaluated_position_cache_;
}
this->ensure_auto_handles();
const int eval_size = this->evaluated_points_size();
evaluated_position_cache_.resize(eval_size);

View File

@ -82,6 +82,10 @@ typedef struct NlaEvalChannelSnapshot {
/** For an upper snapshot channel, marks values that should be blended. */
NlaValidMask blend_domain;
/** Only used for keyframe remapping. Any values not in the \a remap_domain will not be used
* for keyframe remapping. */
NlaValidMask remap_domain;
int length; /* Number of values in the property. */
bool is_base; /* Base snapshot of the channel. */
@ -196,6 +200,13 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
const float upper_influence,
NlaEvalSnapshot *r_blended_snapshot);
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
const short upper_blendmode,
const float upper_influence,
NlaEvalSnapshot *r_upper_snapshot);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,73 @@
/*
* 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.
*/
#pragma once
#ifdef WITH_TBB
# include <tbb/enumerable_thread_specific.h>
#endif
#include <atomic>
#include <mutex>
#include "BLI_map.hh"
#include "BLI_utility_mixins.hh"
namespace blender {
namespace enumerable_thread_specific_utils {
inline std::atomic<int> next_id = 0;
inline thread_local int thread_id = next_id.fetch_add(1, std::memory_order_relaxed);
} // namespace enumerable_thread_specific_utils
/**
* This is mainly a wrapper for `tbb::enumerable_thread_specific`. The wrapper is needed because we
* want to be able to build without tbb.
*
* More features of the tbb version can be wrapped when they are used.
*/
template<typename T> class EnumerableThreadSpecific : NonCopyable, NonMovable {
#ifdef WITH_TBB
private:
tbb::enumerable_thread_specific<T> values_;
public:
T &local()
{
return values_.local();
}
#else /* WITH_TBB */
private:
std::mutex mutex_;
/* Maps thread ids to their corresponding values. The values are not embedded in the map, so that
* their addresses do not change when the map grows. */
Map<int, std::unique_ptr<T>> values_;
public:
T &local()
{
const int thread_id = enumerable_thread_specific_utils::thread_id;
std::lock_guard lock{mutex_};
return *values_.lookup_or_add_cb(thread_id, []() { return std::make_unique<T>(); });
}
#endif /* WITH_TBB */
};
} // namespace blender

View File

@ -85,9 +85,12 @@
namespace blender {
/**
* If there is no other specialization of #DefaultHash for a given type, try to call `hash()` on
* the value. If there is no such method, this will result in a compiler error. Usually that means
* that you have to implement a hash function using one of three strategies listed above.
* If there is no other specialization of #DefaultHash for a given type, look for a hash function
* on the type itself. Implementing a `hash()` method on a type is often significantly easier than
* specializing #DefaultHash.
*
* To support heterogeneous lookup, a type can also implement a static `hash_as(const OtherType &)`
* function.
*
* In the case of an enum type, the default hash is just to cast the enum value to an integer.
*/
@ -95,12 +98,25 @@ template<typename T> struct DefaultHash {
uint64_t operator()(const T &value) const
{
if constexpr (std::is_enum_v<T>) {
/* For enums use the value as hash directly. */
return (uint64_t)value;
}
else {
/* Try to call the `hash()` function on the value. */
/* If this results in a compiler error, no hash function for the type has been found. */
return value.hash();
}
}
template<typename U> uint64_t operator()(const U &value) const
{
/* Try calling the static `T::hash_as(value)` function with the given value. The returned hash
* should be "compatible" with `T::hash()`. Usually that means that if `value` is converted to
* `T` its hash does not change. */
/* If this results in a compiler error, no hash function for the heterogeneous lookup has been
* found. */
return T::hash_as(value);
}
};
/**

View File

@ -128,6 +128,21 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya
return destruct_ptr<T>(value);
}
/**
* Construct multiple instances of a type in an array. The constructor of is called with the
* given arguments. The caller is responsible for calling the destructor (and not `delete`) on
* the constructed elements.
*/
template<typename T, typename... Args>
MutableSpan<T> construct_array(int64_t size, Args &&... args)
{
MutableSpan<T> array = this->allocate_array<T>(size);
for (const int64_t i : IndexRange(size)) {
new (&array[i]) T(std::forward<Args>(args)...);
}
return array;
}
/**
* Copy the given array into a memory buffer provided by this allocator.
*/

View File

@ -604,6 +604,37 @@ class Map {
return this->lookup_or_add_cb_as(std::forward<ForwardKey>(key), []() { return Value(); });
}
/**
* Returns the key that is stored in the set that compares equal to the given key. This invokes
* undefined behavior when the key is not in the map.
*/
const Key &lookup_key(const Key &key) const
{
return this->lookup_key_as(key);
}
template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
{
const Slot &slot = this->lookup_slot(key, hash_(key));
return *slot.key();
}
/**
* Returns a pointer to the key that is stored in the map that compares equal to the given key.
* If the key is not in the map, null is returned.
*/
const Key *lookup_key_ptr(const Key &key) const
{
return this->lookup_key_ptr_as(key);
}
template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
{
const Slot *slot = this->lookup_slot_ptr(key, hash_(key));
if (slot == nullptr) {
return nullptr;
}
return slot->key();
}
/**
* Calls the provided callback for every key-value-pair in the map. The callback is expected
* to take a `const Key &` as first and a `const Value &` as second parameter.

View File

@ -414,6 +414,38 @@ class VectorSet {
return this->index_of_or_add__impl(std::forward<ForwardKey>(key), hash_(key));
}
/**
* Returns the key that is stored in the vector set that compares equal to the given key. This
* invokes undefined behavior when the key is not in the set.
*/
const Key &lookup_key(const Key &key) const
{
return this->lookup_key_as(key);
}
template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
{
const Key *key_ptr = this->lookup_key_ptr_as(key);
BLI_assert(key_ptr != nullptr);
return *key_ptr;
}
/**
* Returns a pointer to the key that is stored in the vector set that compares equal to the given
* key. If the key is not in the set, null is returned.
*/
const Key *lookup_key_ptr(const Key &key) const
{
return this->lookup_key_ptr_as(key);
}
template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
{
const int64_t index = this->index_of_try__impl(key, hash_(key));
if (index >= 0) {
return keys_ + index;
}
return nullptr;
}
/**
* Get a pointer to the beginning of the array containing all keys.
*/

View File

@ -185,6 +185,7 @@ set(SRC
BLI_edgehash.h
BLI_endian_switch.h
BLI_endian_switch_inline.h
BLI_enumerable_thread_specific.hh
BLI_expr_pylike_eval.h
BLI_fileops.h
BLI_fileops_types.h

View File

@ -136,4 +136,17 @@ TEST(linear_allocator, ManyAllocations)
}
}
TEST(linear_allocator, ConstructArray)
{
LinearAllocator<> allocator;
MutableSpan<std::string> strings = allocator.construct_array<std::string>(4, "hello");
EXPECT_EQ(strings[0], "hello");
EXPECT_EQ(strings[1], "hello");
EXPECT_EQ(strings[2], "hello");
EXPECT_EQ(strings[3], "hello");
for (std::string &string : strings) {
string.~basic_string();
}
}
} // namespace blender::tests

View File

@ -640,6 +640,19 @@ TEST(map, RemoveDuringIteration)
EXPECT_EQ(map.lookup(3), 3);
}
TEST(map, LookupKey)
{
Map<std::string, int> map;
map.add("a", 0);
map.add("b", 1);
map.add("c", 2);
EXPECT_EQ(map.lookup_key("a"), "a");
EXPECT_EQ(map.lookup_key_as("c"), "c");
EXPECT_EQ(map.lookup_key_ptr_as("d"), nullptr);
EXPECT_EQ(map.lookup_key_ptr_as("b")->size(), 1);
EXPECT_EQ(map.lookup_key_ptr("a"), map.lookup_key_ptr_as("a"));
}
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/

View File

@ -258,4 +258,17 @@ TEST(vector_set, Clear)
EXPECT_EQ(set.size(), 0);
}
TEST(vector_set, LookupKey)
{
VectorSet<std::string> set;
set.add("a");
set.add("b");
set.add("c");
EXPECT_EQ(set.lookup_key("a"), "a");
EXPECT_EQ(set.lookup_key_as("c"), "c");
EXPECT_EQ(set.lookup_key_ptr_as("d"), nullptr);
EXPECT_EQ(set.lookup_key_ptr_as("b")->size(), 1);
EXPECT_EQ(set.lookup_key_ptr("a"), set.lookup_key_ptr_as("a"));
}
} // namespace blender::tests

View File

@ -21,6 +21,7 @@
#define DNA_DEPRECATED_ALLOW
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
@ -95,5 +96,15 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale_xyz[3]")) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->pose == NULL) {
continue;
}
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
copy_v3_fl(pchan->custom_scale_xyz, pchan->custom_scale);
}
}
}
}
}

View File

@ -1278,12 +1278,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (ob->soft->physics_speed == 0.0f) {
ob->soft->physics_speed = 1.0f;
}
if (ob->soft->interval == 0) {
ob->soft->interval = 2;
ob->soft->sfra = 1;
ob->soft->efra = 100;
}
}
if (ob->soft && ob->soft->vertgroup == 0) {
bDeformGroup *locGroup = BKE_object_defgroup_find_name(ob, "SOFTGOAL");

View File

@ -1557,6 +1557,12 @@ void DepsgraphNodeBuilder::build_nodetree_socket(bNodeSocket *socket)
else if (socket->type == SOCK_COLLECTION) {
build_id((ID *)((bNodeSocketValueCollection *)socket->default_value)->value);
}
else if (socket->type == SOCK_TEXTURE) {
build_id((ID *)((bNodeSocketValueTexture *)socket->default_value)->value);
}
else if (socket->type == SOCK_MATERIAL) {
build_id((ID *)((bNodeSocketValueMaterial *)socket->default_value)->value);
}
}
void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)

View File

@ -2401,6 +2401,18 @@ void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket)
build_collection(nullptr, nullptr, collection);
}
}
else if (socket->type == SOCK_TEXTURE) {
Tex *texture = ((bNodeSocketValueTexture *)socket->default_value)->value;
if (texture != nullptr) {
build_texture(texture);
}
}
else if (socket->type == SOCK_MATERIAL) {
Material *material = ((bNodeSocketValueMaterial *)socket->default_value)->value;
if (material != nullptr) {
build_material(material);
}
}
}
void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)

View File

@ -158,9 +158,9 @@ void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
const ViewLayer *view_layer = draw_ctx->view_layer;
const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer);
eGPUTextureFormat format = (num_cryptomatte_layers == 1) ? GPU_R32F :
(num_cryptomatte_layers == 2) ? GPU_RG32F :
GPU_RGBA32F;
eGPUTextureFormat format = (num_cryptomatte_layers == 1) ?
GPU_R32F :
(num_cryptomatte_layers == 2) ? GPU_RG32F : GPU_RGBA32F;
const float *viewport_size = DRW_viewport_size_get();
const int buffer_size = viewport_size[0] * viewport_size[1];

View File

@ -51,53 +51,72 @@
closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, sub_data, out_##t2##_2); \
closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, sub_data, out_##t3##_3);
#ifndef DEPTH_SHADER
/* Inputs are inout so that callers can get the final inputs used for evaluation. */
#define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
void closure_##name##_eval(ClosureInputCommon in_common, \
inout ClosureInput##t0 in_##t0##_0, \
inout ClosureInput##t1 in_##t1##_1, \
inout ClosureInput##t2 in_##t2##_2, \
inout ClosureInput##t3 in_##t3##_3, \
out ClosureOutput##t0 out_##t0##_0, \
out ClosureOutput##t1 out_##t1##_1, \
out ClosureOutput##t2 out_##t2##_2, \
out ClosureOutput##t3 out_##t3##_3) \
{ \
CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
# define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
void closure_##name##_eval(ClosureInputCommon in_common, \
inout ClosureInput##t0 in_##t0##_0, \
inout ClosureInput##t1 in_##t1##_1, \
inout ClosureInput##t2 in_##t2##_2, \
inout ClosureInput##t3 in_##t3##_3, \
out ClosureOutput##t0 out_##t0##_0, \
out ClosureOutput##t1 out_##t1##_1, \
out ClosureOutput##t2 out_##t2##_2, \
out ClosureOutput##t3 out_##t3##_3) \
{ \
CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
\
/* Starts at 1 because 0 is world cubemap. */ \
for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \
i++) { \
ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \
if (cube.attenuation > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \
/* Starts at 1 because 0 is world cubemap. */ \
for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \
i++) { \
ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \
if (cube.attenuation > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \
} \
} \
} \
\
/* Starts at 1 because 0 is world irradiance. */ \
for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; i++) { \
ClosureGridData grid = closure_grid_eval_init(i, cl_common); \
if (grid.attenuation > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \
/* Starts at 1 because 0 is world irradiance. */ \
for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; \
i++) { \
ClosureGridData grid = closure_grid_eval_init(i, cl_common); \
if (grid.attenuation > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \
} \
} \
} \
\
CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \
CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \
\
ClosurePlanarData planar = closure_planar_eval_init(cl_common); \
if (planar.attenuation > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \
} \
\
for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \
ClosureLightData light = closure_light_eval_init(cl_common, i); \
if (light.vis > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \
ClosurePlanarData planar = closure_planar_eval_init(cl_common); \
if (planar.attenuation > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \
} \
} \
\
CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \
}
for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \
ClosureLightData light = closure_light_eval_init(cl_common, i); \
if (light.vis > 1e-8) { \
CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \
} \
} \
\
CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \
}
#else
/* Inputs are inout so that callers can get the final inputs used for evaluation. */
# define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
void closure_##name##_eval(ClosureInputCommon in_common, \
inout ClosureInput##t0 in_##t0##_0, \
inout ClosureInput##t1 in_##t1##_1, \
inout ClosureInput##t2 in_##t2##_2, \
inout ClosureInput##t3 in_##t3##_3, \
out ClosureOutput##t0 out_##t0##_0, \
out ClosureOutput##t1 out_##t1##_1, \
out ClosureOutput##t2 out_##t2##_2, \
out ClosureOutput##t3 out_##t3##_3) \
{ \
CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
}
#endif
#define CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) \
closure_##name##_eval(in_common, \

View File

@ -1031,7 +1031,7 @@ static void pchan_draw_data_init(bPoseChannel *pchan)
static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *pchan)
{
float ebmat[4][4];
float length;
float bone_scale[3];
float(*bone_mat)[4];
float(*disp_mat)[4];
float(*disp_tail_mat)[4];
@ -1040,23 +1040,23 @@ static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *
* and not be tight to the draw pass creation.
* This would refresh armature without invalidating the draw cache */
if (pchan) {
length = pchan->bone->length;
bone_mat = pchan->pose_mat;
disp_mat = pchan->disp_mat;
disp_tail_mat = pchan->disp_tail_mat;
copy_v3_fl(bone_scale, pchan->bone->length);
}
else {
eBone->length = len_v3v3(eBone->tail, eBone->head);
ED_armature_ebone_to_mat4(eBone, ebmat);
length = eBone->length;
copy_v3_fl(bone_scale, eBone->length);
bone_mat = ebmat;
disp_mat = eBone->disp_mat;
disp_tail_mat = eBone->disp_tail_mat;
}
copy_m4_m4(disp_mat, bone_mat);
rescale_m4(disp_mat, (float[3]){length, length, length});
rescale_m4(disp_mat, bone_scale);
copy_m4_m4(disp_tail_mat, disp_mat);
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
}
@ -1255,19 +1255,27 @@ static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pc
static void draw_bone_update_disp_matrix_custom(bPoseChannel *pchan)
{
float length;
float bone_scale[3];
float(*bone_mat)[4];
float(*disp_mat)[4];
float(*disp_tail_mat)[4];
float rot_mat[3][3];
/* See TODO above */
length = PCHAN_CUSTOM_DRAW_SIZE(pchan);
mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(pchan));
bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
disp_mat = pchan->disp_mat;
disp_tail_mat = pchan->disp_tail_mat;
eulO_to_mat3(rot_mat, pchan->custom_rotation_euler, ROT_MODE_XYZ);
copy_m4_m4(disp_mat, bone_mat);
rescale_m4(disp_mat, (float[3]){length, length, length});
translate_m4(disp_mat,
pchan->custom_translation[0],
pchan->custom_translation[1],
pchan->custom_translation[2]);
mul_m4_m4m3(disp_mat, disp_mat, rot_mat);
rescale_m4(disp_mat, bone_scale);
copy_m4_m4(disp_tail_mat, disp_mat);
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
}

View File

@ -285,10 +285,6 @@ static bool overlay_should_fade_object(Object *ob, Object *active_object)
return false;
}
if (ob->base_flag & BASE_FROM_DUPLI) {
return false;
}
return true;
}

View File

@ -210,7 +210,7 @@ ModifierData *ED_object_modifier_add(
/* special cases */
if (type == eModifierType_Softbody) {
if (!ob->soft) {
ob->soft = sbNew(scene);
ob->soft = sbNew();
ob->softflag |= OB_SB_GOAL | OB_SB_EDGES;
}
}

View File

@ -104,8 +104,12 @@ static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
MEM_freeN(area);
}
ScrArea *area_split(
const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge)
ScrArea *area_split(const wmWindow *win,
bScreen *screen,
ScrArea *area,
char dir,
const float fac,
const bool merge)
{
ScrArea *newa = NULL;
@ -484,7 +488,7 @@ static ScrArea *screen_area_trim(
float fac = abs(size) / (float)(vertical ? ((*area)->v3->vec.x - (*area)->v1->vec.x) :
((*area)->v3->vec.y - (*area)->v1->vec.y));
fac = (reverse == vertical) ? 1.0f - fac : fac;
ScrArea *newsa = area_split(CTX_wm_window(C), screen, *area, vertical ? 'v' : 'h', fac, 1);
ScrArea *newsa = area_split(CTX_wm_window(C), screen, *area, vertical ? 'v' : 'h', fac, true);
/* area_split always returns smallest of the two areas, so might have to swap. */
if (((fac > 0.5f) == vertical) != reverse) {
@ -534,7 +538,7 @@ int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
return screen_area_join_ex(C, screen, sa1, sa2, false);
}
/* Close a screen area, allowing any neighbor to take its place. */
/* Close a screen area, allowing most-aligned neighbor to take its place. */
bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
{
if (area == NULL) {
@ -542,32 +546,27 @@ bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area)
}
ScrArea *sa2 = NULL;
float best_alignment = 0.0f;
/* Find the most-aligned joinable area. Larger size breaks ties. */
int min_alignment = INT_MAX;
int max_size = 0;
LISTBASE_FOREACH (ScrArea *, ar, &screen->areabase) {
int dir = area_getorientation(area, ar);
if (dir != -1) {
int offset1;
int offset2;
area_getoffsets(area, ar, dir, &offset1, &offset2);
int area_alignment = abs(offset1) + abs(offset2);
if (area_alignment < min_alignment) {
min_alignment = area_alignment;
max_size = ar->winx * ar->winy;
sa2 = ar;
}
else if (area_alignment == min_alignment) {
int area_size = ar->winx * ar->winy;
if (area_size > max_size) {
max_size = area_size;
sa2 = ar;
}
LISTBASE_FOREACH (ScrArea *, neighbor, &screen->areabase) {
int dir = area_getorientation(area, neighbor);
/* Must at least partially share an edge and not be a global area. */
if (dir != -1 && !neighbor->global) {
/* Winx/Winy might not be updated yet, so get lengths from verts. */
int area_length = ELEM(dir, 1, 3) ? area->v3->vec.x - area->v1->vec.x :
area->v3->vec.y - area->v1->vec.y;
int ar_length = ELEM(dir, 1, 3) ? neighbor->v3->vec.x - neighbor->v1->vec.x :
neighbor->v3->vec.y - neighbor->v1->vec.y;
/* Calculate the ratio of the lengths of the shared edges. */
float alignment = MIN2(area_length, ar_length) / (float)MAX2(area_length, ar_length);
if (alignment > best_alignment) {
best_alignment = alignment;
sa2 = neighbor;
}
}
}
/* Join from neighbor into this area to close it. */
return screen_area_join_ex(C, screen, sa2, area, true);
}

View File

@ -56,8 +56,12 @@ void screen_change_prepare(bScreen *screen_old,
struct Main *bmain,
struct bContext *C,
wmWindow *win);
ScrArea *area_split(
const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge);
ScrArea *area_split(const wmWindow *win,
bScreen *screen,
ScrArea *area,
char dir,
const float fac,
const bool merge);
int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
int area_getorientation(ScrArea *sa_a, ScrArea *sa_b);
void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const int dir, int *r_offset1, int *r_offset2);

View File

@ -2092,7 +2092,7 @@ static bool area_split_apply(bContext *C, wmOperator *op)
float fac = RNA_float_get(op->ptr, "factor");
int dir = RNA_enum_get(op->ptr, "direction");
sd->narea = area_split(win, screen, sd->sarea, dir, fac, 0); /* 0 = no merge */
sd->narea = area_split(win, screen, sd->sarea, dir, fac, false); /* false = no merge */
if (sd->narea == NULL) {
return false;

View File

@ -1962,13 +1962,22 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
* The faces that were using the `delete_id` Face Set are filled
* using the content from their neighbors.
*/
static void sculpt_expand_delete_face_set_id(
int *r_face_sets, Mesh *mesh, MeshElemMap *pmap, const int totface, const int delete_id)
static void sculpt_expand_delete_face_set_id(int *r_face_sets,
SculptSession *ss,
ExpandCache *expand_cache,
Mesh *mesh,
const int delete_id)
{
const int totface = ss->totfaces;
MeshElemMap *pmap = ss->pmap;
/* Check that all the face sets IDs in the mesh are not equal to `delete_id`
* before attempting to delete it. */
bool all_same_id = true;
for (int i = 0; i < totface; i++) {
if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, i)) {
continue;
}
if (r_face_sets[i] != delete_id) {
all_same_id = false;
break;
@ -2140,9 +2149,9 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
if (ss->expand_cache->modify_active_face_set) {
sculpt_expand_delete_face_set_id(ss->expand_cache->initial_face_sets,
ss,
ss->expand_cache,
ob->data,
ss->pmap,
ss->totfaces,
ss->expand_cache->next_face_set);
}

View File

@ -3334,12 +3334,14 @@ static const float std_node_socket_colors[][4] = {
{0.39, 0.78, 0.39, 1.0}, /* SOCK_SHADER */
{0.80, 0.65, 0.84, 1.0}, /* SOCK_BOOLEAN */
{0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */
{0.25, 0.75, 0.26, 1.0}, /* SOCK_INT */
{0.35, 0.55, 0.36, 1.0}, /* SOCK_INT */
{0.44, 0.70, 1.00, 1.0}, /* SOCK_STRING */
{0.93, 0.62, 0.36, 1.0}, /* SOCK_OBJECT */
{0.89, 0.76, 0.43, 1.0}, /* SOCK_IMAGE */
{0.39, 0.22, 0.39, 1.0}, /* SOCK_IMAGE */
{0.00, 0.84, 0.64, 1.0}, /* SOCK_GEOMETRY */
{0.96, 0.96, 0.96, 1.0}, /* SOCK_COLLECTION */
{0.62, 0.31, 0.64, 1.0}, /* SOCK_TEXTURE */
{0.92, 0.46, 0.51, 1.0}, /* SOCK_MATERIAL */
};
/* common color callbacks for standard types */
@ -3480,6 +3482,14 @@ static void std_node_socket_draw(
uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
}
case SOCK_TEXTURE: {
uiTemplateID(layout, C, ptr, "default_value", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
break;
}
case SOCK_MATERIAL: {
uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
}
default:
node_socket_button_label(C, layout, ptr, node_ptr, text);
break;

View File

@ -885,10 +885,12 @@ static void draw_seq_background(Scene *scene,
immUniformColor4ubv(col);
if (seq->startstill) {
immRectf(pos, seq->startdisp, y1, (float)(seq->start), y2);
const float content_start = min_ff(seq->enddisp, seq->start);
immRectf(pos, seq->startdisp, y1, content_start, y2);
}
if (seq->endstill) {
immRectf(pos, (float)(seq->start + seq->len), y1, seq->enddisp, y2);
const float content_end = max_ff(seq->startdisp, seq->start + seq->len);
immRectf(pos, content_end, y1, seq->enddisp, y2);
}
}
@ -1105,6 +1107,10 @@ static void draw_seq_strip(const bContext *C,
x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
/* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */
x1 = min_ff(x1, seq->enddisp);
x2 = max_ff(x2, seq->startdisp);
float text_margin_y;
bool y_threshold;
if ((sseq->flag & SEQ_SHOW_STRIP_NAME) || (sseq->flag & SEQ_SHOW_STRIP_SOURCE) ||

View File

@ -1595,7 +1595,6 @@ static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(area))
}
const char *view3d_context_dir[] = {
"active_base",
"active_object",
NULL,
};
@ -1608,20 +1607,6 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, view3d_context_dir);
}
else if (CTX_data_equals(member, "active_base")) {
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
if (view_layer->basact) {
Object *ob = view_layer->basact->object;
/* if hidden but in edit mode, we still display, can happen with animation */
if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 ||
(ob->mode != OB_MODE_OBJECT)) {
CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact);
}
}
return 1;
}
else if (CTX_data_equals(member, "active_object")) {
/* In most cases the active object is the `view_layer->basact->object`.
* For the 3D view however it can be NULL when hidden.

View File

@ -782,7 +782,7 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type)
}
else {
short orient_index = 1;
if (t->orient_curr == 0 || ELEM(constraint_curr, -1, constraint_new)) {
if (t->orient_curr == O_DEFAULT || ELEM(constraint_curr, -1, constraint_new)) {
/* Successive presses on existing axis, cycle orientation modes. */
orient_index = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient));
}
@ -1412,25 +1412,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ToolSettings *ts = CTX_data_tool_settings(C);
PropertyRNA *prop;
if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) &&
ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) {
/* When redoing these modes the first time, it's more convenient to save
* in the Global orientation. */
if (t->mode == TFM_TRANSLATION) {
mul_m3_v3(t->spacemtx, t->values_final);
}
else {
float tmat[3][3], sizemat[3][3];
size_to_mat3(sizemat, t->values_final);
mul_m3_m3m3(tmat, t->spacemtx, sizemat);
mat3_to_size(t->values_final, tmat);
}
BLI_assert(t->orient_curr == 0);
unit_m3(t->spacemtx);
t->orient[0].type = V3D_ORIENT_GLOBAL;
}
/* Save back mode in case we're in the generic operator */
if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
RNA_property_enum_set(op->ptr, prop, t->mode);
@ -1638,7 +1619,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2])
/**
* \note caller needs to free 't' on a 0 return
* \warning \a event might be NULL (when tweaking from redo panel)
* \warning \a event might be NULL (when tweaking from redo panel)
* \see #saveTransform which writes these values back.
*/
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)

View File

@ -596,11 +596,18 @@ typedef struct TransInfo {
* mouse button then.) */
bool is_launch_event_tweak;
bool is_orient_set;
struct {
short type;
float matrix[3][3];
} orient[3];
short orient_curr;
enum {
O_DEFAULT = 0,
O_SCENE,
O_SET,
} orient_curr;
/** backup from view3d, to restore on end. */
short gizmo_flag;

View File

@ -953,9 +953,8 @@ void startConstraint(TransInfo *t)
void stopConstraint(TransInfo *t)
{
if (t->orient_curr != 0) {
t->orient_curr = 0;
transform_orientations_current_set(t, t->orient_curr);
if (t->orient_curr != O_DEFAULT) {
transform_orientations_current_set(t, O_DEFAULT);
}
t->con.mode &= ~(CON_APPLY | CON_SELECT);
@ -971,8 +970,8 @@ void stopConstraint(TransInfo *t)
void initSelectConstraint(TransInfo *t)
{
if (t->orient_curr == 0) {
transform_orientations_current_set(t, 1);
if (t->orient_curr == O_DEFAULT) {
transform_orientations_current_set(t, O_SCENE);
}
setUserConstraint(t, CON_APPLY | CON_SELECT, "%s");

View File

@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@ -505,9 +506,27 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
bool clipx = true, clipy = true;
float min[2], max[2];
min[0] = min[1] = 0.0f;
max[0] = t->aspect[0];
max[1] = t->aspect[1];
/* Check if the current image in UV editor is a tiled image or not. */
const SpaceImage *sima = t->area->spacedata.first;
const Image *image = sima->image;
const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
/* Stores the coordinates of the closest UDIM tile.
* Also acts as an offset to the tile from the origin of UV space. */
float base_offset[2] = {0.0f, 0.0f};
/* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */
if (is_tiled_image) {
int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global);
if (nearest_tile_index != -1) {
nearest_tile_index -= 1001;
/* Getting coordinates of nearest tile from the tile index. */
base_offset[0] = nearest_tile_index % 10;
base_offset[1] = nearest_tile_index / 10;
}
}
min[0] = min[1] = FLT_MAX;
max[0] = max[1] = FLT_MIN;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@ -520,42 +539,48 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
}
if (resize) {
if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) {
vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
if (min[0] < base_offset[0] && t->center_global[0] > base_offset[0] &&
t->center_global[0] < base_offset[0] + (t->aspect[0] * 0.5f)) {
vec[0] *= (t->center_global[0] - base_offset[0]) / (t->center_global[0] - min[0]);
}
else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) {
vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
else if (max[0] > (base_offset[0] + t->aspect[0]) &&
t->center_global[0] < (base_offset[0] + t->aspect[0])) {
vec[0] *= (t->center_global[0] - (base_offset[0] + t->aspect[0])) /
(t->center_global[0] - max[0]);
}
else {
clipx = 0;
}
if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) {
vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
if (min[1] < base_offset[1] && t->center_global[1] > base_offset[1] &&
t->center_global[1] < base_offset[1] + (t->aspect[1] * 0.5f)) {
vec[1] *= (t->center_global[1] - base_offset[1]) / (t->center_global[1] - min[1]);
}
else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) {
vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
else if (max[1] > (base_offset[1] + t->aspect[1]) &&
t->center_global[1] < (base_offset[1] + t->aspect[1])) {
vec[1] *= (t->center_global[1] - (base_offset[1] + t->aspect[1])) /
(t->center_global[1] - max[1]);
}
else {
clipy = 0;
}
}
else {
if (min[0] < 0.0f) {
vec[0] -= min[0];
if (min[0] < base_offset[0]) {
vec[0] += base_offset[0] - min[0];
}
else if (max[0] > t->aspect[0]) {
vec[0] -= max[0] - t->aspect[0];
else if (max[0] > base_offset[0] + t->aspect[0]) {
vec[0] -= max[0] - base_offset[0] - t->aspect[0];
}
else {
clipx = 0;
}
if (min[1] < 0.0f) {
vec[1] -= min[1];
if (min[1] < base_offset[1]) {
vec[1] += base_offset[1] - min[1];
}
else if (max[1] > t->aspect[1]) {
vec[1] -= max[1] - t->aspect[1];
else if (max[1] > base_offset[1] + t->aspect[1]) {
vec[1] -= max[1] - base_offset[1] - t->aspect[1];
}
else {
clipy = 0;

View File

@ -414,8 +414,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
int orient_type_set = -1;
int orient_type_matrix_set = -1;
bool use_orient_axis = false;
if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
orient_type_scene = orient_slot->type;
@ -435,7 +433,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
t->orient_axis = RNA_property_enum_get(op->ptr, prop);
use_orient_axis = true;
}
if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
@ -457,28 +454,23 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if (orient_type_set != -1) {
orient_type_default = orient_type_set;
t->is_orient_set = true;
}
else if (orient_type_matrix_set != -1) {
orient_type_default = orient_type_set = orient_type_matrix_set;
t->is_orient_set = true;
}
else if (t->con.mode & CON_APPLY) {
orient_type_default = orient_type_set = orient_type_scene;
}
else {
orient_type_default = orient_type_scene;
if (orient_type_scene == V3D_ORIENT_GLOBAL) {
orient_type_set = V3D_ORIENT_LOCAL;
}
else {
orient_type_set = V3D_ORIENT_GLOBAL;
}
if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) &&
(t->mode != TFM_ALIGN)) {
orient_type_default = V3D_ORIENT_VIEW;
}
else {
orient_type_default = orient_type_scene;
}
}
BLI_assert(!ELEM(-1, orient_type_default, orient_type_set));
@ -487,9 +479,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
orient_type_set = V3D_ORIENT_CUSTOM_MATRIX;
}
orient_types[0] = (short)orient_type_default;
orient_types[1] = (short)orient_type_scene;
orient_types[2] = (short)orient_type_set;
orient_types[O_DEFAULT] = (short)orient_type_default;
orient_types[O_SCENE] = (short)orient_type_scene;
orient_types[O_SET] = (short)orient_type_set;
for (int i = 0; i < 3; i++) {
/* For efficiency, avoid calculating the same orientation twice. */
@ -506,9 +498,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
/* Set orient_curr to -1 in order to force the update in
* `transform_orientations_current_set`. */
t->orient_curr = -1;
transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0);
}

View File

@ -45,6 +45,7 @@
#include "transform.h"
#include "transform_convert.h"
#include "transform_orientations.h"
#include "transform_snap.h"
/* Own include. */
@ -1271,4 +1272,38 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
* BLI_assert(t->mode == mode); */
}
/**
* When in modal nad not set, initializes a default orientation for the mode.
*/
void transform_mode_default_modal_orientation_set(TransInfo *t, int type)
{
/* Currently only these types are supported. */
BLI_assert(ELEM(type, V3D_ORIENT_GLOBAL, V3D_ORIENT_VIEW));
if (t->is_orient_set) {
return;
}
if (!(t->flag & T_MODAL)) {
return;
}
if (t->orient[O_DEFAULT].type == type) {
return;
}
RegionView3D *rv3d = NULL;
if ((type == V3D_ORIENT_VIEW) && (t->spacetype == SPACE_VIEW3D) && t->region &&
(t->region->regiontype == RGN_TYPE_WINDOW)) {
rv3d = t->region->regiondata;
}
t->orient[O_DEFAULT].type = ED_transform_calc_orientation_from_type_ex(
NULL, t->orient[O_DEFAULT].matrix, NULL, rv3d, NULL, NULL, type, 0);
if (t->orient_curr == O_DEFAULT) {
/* Update Orientation. */
transform_orientations_current_set(t, O_DEFAULT);
}
}
/** \} */

View File

@ -61,6 +61,7 @@ short getAnimEdit_SnapMode(TransInfo *t);
void doAnimEdit_SnapFrame(
TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap);
void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode);
void transform_mode_default_modal_orientation_set(TransInfo *t, int type);
/* transform_mode_align.c */
void initAlign(TransInfo *t);

View File

@ -148,5 +148,7 @@ void initNormalRotation(TransInfo *t)
storeCustomLNorValue(tc, bm);
}
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
/** \} */

View File

@ -193,5 +193,7 @@ void initResize(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL);
}
/** \} */

View File

@ -249,5 +249,7 @@ void initRotation(TransInfo *t)
if (t->flag & T_2D_EDIT) {
t->flag |= T_NO_CONSTRAINT;
}
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
/** \} */

View File

@ -232,5 +232,7 @@ void initShear(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */
t->flag |= T_NO_CONSTRAINT;
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
}
/** \} */

View File

@ -470,5 +470,7 @@ void initTranslation(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
t->num.unit_type[2] = B_UNIT_NONE;
}
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL);
}
/** \} */

View File

@ -671,10 +671,6 @@ const char *transform_orientations_spacename_get(TransInfo *t, const short orien
void transform_orientations_current_set(TransInfo *t, const short orient_index)
{
if (t->orient_curr == orient_index) {
return;
}
const short orientation = t->orient[orient_index].type;
const char *spacename = transform_orientations_spacename_get(t, orientation);

View File

@ -554,6 +554,16 @@ template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableAr
varray_->set(index, std::move(value_));
}
void materialize_impl(const IndexMask mask, void *dst) const override
{
varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
{
varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
const void *try_get_internal_varray_impl() const override
{
return (const VArray<T> *)varray_;

View File

@ -27,6 +27,7 @@
#include "BLI_resource_scope.hh"
#include "FN_generic_pointer.hh"
#include "FN_generic_vector_array.hh"
#include "FN_generic_virtual_vector_array.hh"
#include "FN_multi_function_signature.hh"
@ -64,6 +65,12 @@ class MFParamsBuilder {
this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(__func__, span),
expected_name);
}
void add_readonly_single_input(GPointer value, StringRef expected_name = "")
{
this->add_readonly_single_input(scope_.construct<GVArray_For_SingleValueRef>(
__func__, *value.type(), min_array_size_, value.get()),
expected_name);
}
void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "")
{
this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name);

View File

@ -322,9 +322,11 @@ typedef enum eLineartTriangleFlags {
LRT_TRIANGLE_NO_INTERSECTION = (1 << 4),
} eLineartTriangleFlags;
/** Controls how many edges a worker thread is processing at one request.
/**
* Controls how many edges a worker thread is processing at one request.
* There's no significant performance impact on choosing different values.
* Don't make it too small so that the worker thread won't request too many times. */
* Don't make it too small so that the worker thread won't request too many times.
*/
#define LRT_THREAD_EDGE_COUNT 1000
typedef struct LineartRenderTaskInfo {

View File

@ -286,9 +286,10 @@ static void detect_workarounds()
strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") ||
strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") ||
strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") ||
strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") ||
strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") ||
strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) {
strstr(renderer, " RX 580X ") || strstr(renderer, " RX 590 ") ||
strstr(renderer, " RX550/550 ") || strstr(renderer, " (TM) 520 ") ||
strstr(renderer, " (TM) 530 ") || strstr(renderer, " R5 ") || strstr(renderer, " R7 ") ||
strstr(renderer, " R9 ")) {
GCaps.use_hq_normals_workaround = true;
}
}

View File

@ -265,9 +265,10 @@ typedef struct bPoseChannel {
* since the alternative is highly complicated - campbell
*/
struct bPoseChannel *custom_tx;
float custom_scale;
char _pad1[4];
float custom_scale; /* Deprecated */
float custom_scale_xyz[3];
float custom_translation[3];
float custom_rotation_euler[3];
/** Transforms - written in by actions or transform. */
float loc[3];
@ -417,9 +418,9 @@ typedef enum ePchan_DrawFlag {
PCHAN_DRAW_NO_CUSTOM_BONE_SIZE = (1 << 0),
} ePchan_DrawFlag;
#define PCHAN_CUSTOM_DRAW_SIZE(pchan) \
(pchan)->custom_scale *( \
((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length)
/* Note: It doesn't take custom_scale_xyz into account */
#define PCHAN_CUSTOM_BONE_LENGTH(pchan) \
(((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length)
#ifdef DNA_DEPRECATED_ALLOW
/* PoseChannel->bboneflag */

View File

@ -97,7 +97,8 @@ typedef struct BoidRuleFollowLeader {
} BoidRuleFollowLeader;
typedef struct BoidRuleAverageSpeed {
BoidRule rule;
float wander, level, speed, rt;
float wander, level, speed;
char _pad0[4];
} BoidRuleAverageSpeed;
typedef struct BoidRuleFight {
BoidRule rule;
@ -178,7 +179,7 @@ typedef struct BoidState {
//} BoidSignal;
// typedef struct BoidSignalDefine {
// struct BoidSignalDefine *next, *prev;
// int id, rt;
// int id, _pad[4];
// char name[32];
//} BoidSignalDefine;

View File

@ -71,13 +71,15 @@ extern "C" {
typedef struct Effect {
struct Effect *next, *prev;
short type, flag, buttype, rt;
short type, flag, buttype;
char _pad0[2];
} Effect;
typedef struct BuildEff {
struct BuildEff *next, *prev;
short type, flag, buttype, rt;
short type, flag, buttype;
char _pad0[2];
float len, sfra;
@ -88,7 +90,8 @@ typedef struct BuildEff {
typedef struct Particle {
float co[3], no[3];
float time, lifetime;
short mat_nr, rt;
short mat_nr;
char _pad0[2];
} Particle;
struct Collection;

View File

@ -77,8 +77,9 @@ typedef struct IpoCurve {
short totvert;
/** Interpolation and extrapolation modes . */
short ipo, extrap;
/** Flag= settings; rt= ???. */
short flag, rt;
/** Flag= settings. */
short flag;
char _pad0[2];
/** Minimum/maximum y-extents for curve. */
float ymin, ymax;
/** ???. */

View File

@ -45,6 +45,8 @@ struct bNodePreview;
struct bNodeTreeExec;
struct bNodeType;
struct uiBlock;
struct Tex;
struct Material;
#define NODE_MAXSTR 64
@ -165,6 +167,8 @@ typedef enum eNodeSocketDatatype {
SOCK_IMAGE = 9,
SOCK_GEOMETRY = 10,
SOCK_COLLECTION = 11,
SOCK_TEXTURE = 12,
SOCK_MATERIAL = 13,
} eNodeSocketDatatype;
/* socket shape */
@ -593,6 +597,14 @@ typedef struct bNodeSocketValueCollection {
struct Collection *value;
} bNodeSocketValueCollection;
typedef struct bNodeSocketValueTexture {
struct Tex *value;
} bNodeSocketValueTexture;
typedef struct bNodeSocketValueMaterial {
struct Material *value;
} bNodeSocketValueMaterial;
/* data structs, for node->storage */
enum {
CMP_NODE_MASKTYPE_ADD = 0,
@ -1184,6 +1196,19 @@ typedef struct NodeAttributeVectorMath {
uint8_t input_type_c;
} NodeAttributeVectorMath;
typedef struct NodeAttributeVectorRotate {
/* GeometryNodeAttributeVectorRotateMode */
uint8_t mode;
/* GeometryNodeAttributeInputMode */
uint8_t input_type_vector;
uint8_t input_type_center;
uint8_t input_type_axis;
uint8_t input_type_angle;
uint8_t input_type_rotation;
char _pad[2];
} NodeAttributeVectorRotate;
typedef struct NodeAttributeColorRamp {
ColorBand color_ramp;
} NodeAttributeColorRamp;
@ -1775,6 +1800,14 @@ typedef enum GeometryNodeRotatePointsType {
GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE = 1,
} GeometryNodeRotatePointsType;
typedef enum GeometryNodeAttributeVectorRotateMode {
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y = 2,
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z = 3,
GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ = 4,
} GeometryNodeAttributeVectorRotateMode;
typedef enum GeometryNodeAttributeRandomizeMode {
GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE = 0,
GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD = 1,

View File

@ -182,8 +182,8 @@ typedef struct EffectorWeights {
/** Effector type specific weights. */
float weight[14];
float global_gravity;
short flag, rt[3];
char _pad[4];
short flag;
char _pad[2];
} EffectorWeights;
/* EffectorWeights->flag */
@ -267,10 +267,9 @@ typedef struct SoftBody {
char namedVG_Spring_K[64];
/* baking */
int sfra, efra;
int interval;
char _pad1[6];
/** Local==1: use local coords for baking. */
short local, solverflags;
char local, solverflags;
/* -- these must be kept for backwards compatibility -- */
/** Array of size totpointkey. */

View File

@ -64,7 +64,7 @@ typedef struct BoidParticle {
struct BoidData data;
float gravity[3];
float wander[3];
float rt;
char _pad0[4];
} BoidParticle;
typedef struct ParticleSpring {
@ -82,7 +82,7 @@ typedef struct ChildParticle {
float w[4];
/** Face vertex weights and offset. */
float fuv[4], foffset;
float rt;
char _pad0[4];
} ChildParticle;
typedef struct ParticleTarget {
@ -99,7 +99,8 @@ typedef struct ParticleDupliWeight {
short count;
short flag;
/** Only updated on file save and used on file load. */
short index, rt;
short index;
char _pad0[2];
} ParticleDupliWeight;
typedef struct ParticleData {
@ -191,7 +192,8 @@ typedef struct ParticleSettings {
struct EffectorWeights *effector_weights;
struct Collection *collision_group;
int flag, rt;
int flag;
char _pad1[4];
short type, from, distr, texact;
/* physics modes */
short phystype, rotmode, avemode, reactevent;

View File

@ -107,7 +107,8 @@ typedef struct PointCache {
int totpoint;
/** Modifier stack index. */
int index;
short compression, rt;
short compression;
char _pad0[2];
char name[64];
char prev_name[64];

View File

@ -952,7 +952,8 @@ typedef struct ParticleEditSettings {
/** Runtime. */
void *paintcursor;
float emitterdist, rt;
float emitterdist;
char _pad0[4];
int selectmode;
int edittype;
@ -1558,7 +1559,8 @@ typedef struct UnitSettings {
typedef struct PhysicsSettings {
float gravity[3];
int flag, quick_cache_step, rt;
int flag, quick_cache_step;
char _pad0[4];
} PhysicsSettings;
/* ------------------------------------------- */

View File

@ -57,7 +57,8 @@ typedef struct MTex {
short colormodel, pmapto, pmaptoneg;
short normapspace, which_output;
float r, g, b, k;
float def_var, rt;
float def_var;
char _pad1[4];
/* common */
float colfac, varfac;

View File

@ -76,6 +76,8 @@ static const EnumPropertyItem node_socket_data_type_items[] = {
{SOCK_IMAGE, "IMAGE", 0, "Image", ""},
{SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
{SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""},
{SOCK_TEXTURE, "TEXTURE", 0, "Texture", ""},
{SOCK_MATERIAL, "MATERIAL", 0, "Material", ""},
{0, NULL, 0, NULL, NULL},
};
@ -102,6 +104,8 @@ static const EnumPropertyItem node_socket_type_items[] = {
{SOCK_IMAGE, "IMAGE", 0, "Image", ""},
{SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
{SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""},
{SOCK_TEXTURE, "TEXTURE", 0, "Texture", ""},
{SOCK_MATERIAL, "MATERIAL", 0, "Material", ""},
{0, NULL, 0, NULL, NULL},
};
@ -9297,6 +9301,61 @@ static void def_geo_attribute_curve_map(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_attribute_vector_rotate(StructRNA *srna)
{
static const EnumPropertyItem rotate_mode_items[] = {
{GEO_NODE_VECTOR_ROTATE_TYPE_AXIS,
"AXIS_ANGLE",
0,
"Axis Angle",
"Rotate a point using axis angle"},
{GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X, "X_AXIS", 0, "X Axis", "Rotate a point using X axis"},
{GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y, "Y_AXIS", 0, "Y Axis", "Rotate a point using Y axis"},
{GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z, "Z_AXIS", 0, "Z Axis", "Rotate a point using Z axis"},
{GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ,
"EULER_XYZ",
0,
"Euler",
"Rotate a point using XYZ order"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeAttributeVectorRotate", "storage");
prop = RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, rotate_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Type of rotation");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "input_type_vector", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type Vector", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_center", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type Center", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type Axis", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_angle", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Input Type Angle", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_rotation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
RNA_def_property_ui_text(prop, "Input Type Rotation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_point_rotate(StructRNA *srna)
{
static const EnumPropertyItem type_items[] = {
@ -10577,6 +10636,76 @@ static void rna_def_node_socket_collection(BlenderRNA *brna,
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
}
static void rna_def_node_socket_texture(BlenderRNA *brna,
const char *identifier,
const char *interface_idname)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
RNA_def_struct_ui_text(srna, "Texture Node Socket", "Texture socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueTexture", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Texture");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(
prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
/* socket interface */
srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
RNA_def_struct_ui_text(srna, "Texture Node Socket Interface", "Texture socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueTexture", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Texture");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
}
static void rna_def_node_socket_material(BlenderRNA *brna,
const char *identifier,
const char *interface_idname)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
RNA_def_struct_ui_text(srna, "Material Node Socket", "Material socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueMaterial", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Material");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(
prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
/* socket interface */
srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
RNA_def_struct_ui_text(srna, "Material Node Socket Interface", "Material socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueMaterial", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "value");
RNA_def_property_struct_type(prop, "Material");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
}
static void rna_def_node_socket_standard_types(BlenderRNA *brna)
{
/* XXX Workaround: Registered functions are not exposed in python by bpy,
@ -10721,6 +10850,10 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
rna_def_node_socket_geometry(brna, "NodeSocketGeometry", "NodeSocketInterfaceGeometry");
rna_def_node_socket_collection(brna, "NodeSocketCollection", "NodeSocketInterfaceCollection");
rna_def_node_socket_texture(brna, "NodeSocketTexture", "NodeSocketInterfaceTexture");
rna_def_node_socket_material(brna, "NodeSocketMaterial", "NodeSocketInterfaceMaterial");
}
static void rna_def_internal_node(BlenderRNA *brna)

View File

@ -1359,12 +1359,27 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update");
prop = RNA_def_property(srna, "custom_shape_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "custom_scale");
RNA_def_property_range(prop, 0.0f, 1000.0f);
prop = RNA_def_property(srna, "custom_shape_scale_xyz", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "custom_scale_xyz");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_float_array_default(prop, rna_default_scale_3d);
RNA_def_property_ui_text(prop, "Custom Shape Scale", "Adjust the size of the custom shape");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
prop = RNA_def_property(srna, "custom_shape_translation", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "custom_translation");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_text(
prop, "Custom Shape Translation", "Adjust the location of the custom shape");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
prop = RNA_def_property(srna, "custom_shape_rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "custom_rotation_euler");
RNA_def_property_ui_text(
prop, "Custom Shape Rotation", "Adjust the rotation of the custom shape");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
prop = RNA_def_property(srna, "use_custom_shape_bone_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "drawflag", PCHAN_DRAW_NO_CUSTOM_BONE_SIZE);
RNA_def_property_ui_text(

View File

@ -193,6 +193,18 @@ if(WITH_GMP)
)
endif()
if(WITH_TBB)
add_definitions(-DWITH_TBB)
list(APPEND INC_SYS
${TBB_INCLUDE_DIRS}
)
list(APPEND LIB
${TBB_LIBRARIES}
)
endif()
if(WITH_OPENVDB)
list(APPEND INC
../../../intern/openvdb

View File

@ -157,6 +157,7 @@ set(SRC
geometry/nodes/node_geo_attribute_separate_xyz.cc
geometry/nodes/node_geo_attribute_transfer.cc
geometry/nodes/node_geo_attribute_vector_math.cc
geometry/nodes/node_geo_attribute_vector_rotate.cc
geometry/nodes/node_geo_boolean.cc
geometry/nodes/node_geo_bounding_box.cc
geometry/nodes/node_geo_collection_info.cc

View File

@ -92,6 +92,9 @@ class DNode {
operator bool() const;
uint64_t hash() const;
DInputSocket input(int index) const;
DOutputSocket output(int index) const;
};
/* A (nullable) reference to a socket and the context it is in. It is unique within an entire
@ -274,6 +277,16 @@ inline uint64_t DNode::hash() const
return get_default_hash_2(context_, node_ref_);
}
inline DInputSocket DNode::input(int index) const
{
return {context_, &node_ref_->input(index)};
}
inline DOutputSocket DNode::output(int index) const
{
return {context_, &node_ref_->output(index)};
}
/* --------------------------------------------------------------------
* DSocket inline methods.
*/

View File

@ -45,6 +45,7 @@ void register_node_type_geo_attribute_randomize(void);
void register_node_type_geo_attribute_separate_xyz(void);
void register_node_type_geo_attribute_transfer(void);
void register_node_type_geo_attribute_vector_math(void);
void register_node_type_geo_attribute_vector_rotate(void);
void register_node_type_geo_attribute_remove(void);
void register_node_type_geo_boolean(void);
void register_node_type_geo_bounding_box(void);

View File

@ -263,58 +263,59 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")
DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "")
DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", InputString, "String", "")
DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "")
DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "ALIGN_ROTATION_TO_VECTOR", AlignRotationToVector, "Align Rotation to Vector", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "ATTRIBUTE_CLAMP", AttributeClamp, "Attribute Clamp", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CONVERT, def_geo_attribute_convert, "ATTRIBUTE_CONVERT", AttributeConvert, "Attribute Convert", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CURVE_MAP, def_geo_attribute_curve_map, "ATTRIBUTE_CURVE_MAP", AttributeCurveMap, "Attribute Curve Map", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "ATTRIBUTE_MAP_RANGE", AttributeMapRange, "Attribute Map Range", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUTE_MATH", AttributeMath, "Attribute Math", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_MIX", AttributeMix, "Attribute Mix", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity, "ATTRIBUTE_PROXIMITY", AttributeProximity, "Attribute Proximity", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "ATTRIBUTE_RANDOMIZE", AttributeRandomize, "Attribute Randomize", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_TRANSFER, def_geo_attribute_transfer, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Attribute Transfer", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_math, "ATTRIBUTE_VECTOR_MATH", AttributeVectorMath, "Attribute Vector Math", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_ROTATE, def_geo_attribute_vector_rotate, "ATTRIBUTE_VECTOR_ROTATE", AttributeVectorRotate, "Attribute Vector Rotate", "")
DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, "MESH_PRIMITIVE_CYLINDER", MeshCylinder, "Cylinder", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", MeshGrid, "Grid", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, def_geo_point_distribute, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "")
DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "ATTRIBUTE_RANDOMIZE", AttributeRandomize, "Attribute Randomize", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUTE_MATH", AttributeMath, "Attribute Math", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_MIX", AttributeMix, "Attribute Mix", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "")
DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "")
DefNode(GeometryNode, GEO_NODE_POINT_ROTATE, def_geo_point_rotate, "POINT_ROTATE", RotatePoints, "Point Rotate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_math, "ATTRIBUTE_VECTOR_MATH", AttributeVectorMath, "Attribute Vector Math", "")
DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "ALIGN_ROTATION_TO_VECTOR", AlignRotationToVector, "Align Rotation to Vector", "")
DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE", PointScale, "Point Scale", "")
DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "")
DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "")
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity, "ATTRIBUTE_PROXIMITY", AttributeProximity, "Attribute Proximity", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CONVERT, def_geo_attribute_convert, "ATTRIBUTE_CONVERT", AttributeConvert, "Attribute Convert", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, "MESH_PRIMITIVE_CYLINDER", MeshCylinder, "Cylinder", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", MeshGrid, "Grid", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "ATTRIBUTE_MAP_RANGE", AttributeMapRange, "Attribute Map Range", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "ATTRIBUTE_CLAMP", AttributeClamp, "Attribute Clamp", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_TRANSFER, def_geo_attribute_transfer, "ATTRIBUTE_TRANSFER", AttributeTransfer, "Attribute Transfer", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CURVE_MAP, def_geo_attribute_curve_map, "ATTRIBUTE_CURVE_MAP", AttributeCurveMap, "Attribute Curve Map", "")
DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
/* undefine macros */
#undef DefNode

View File

@ -84,6 +84,16 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
}
static bool geometry_node_tree_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
{
/* Geometry, string, object and collection sockets can only be connected to themselves. */
if (ELEM(link->fromsock->type, SOCK_GEOMETRY, SOCK_STRING, SOCK_OBJECT, SOCK_COLLECTION) ||
ELEM(link->tosock->type, SOCK_GEOMETRY, SOCK_STRING, SOCK_OBJECT, SOCK_COLLECTION)) {
return (link->tosock->type == link->fromsock->type);
}
return true;
}
static bool geometry_node_tree_socket_type_valid(eNodeSocketDatatype socket_type,
bNodeTreeType *UNUSED(ntreetype))
{
@ -113,6 +123,7 @@ void register_node_tree_type_geo(void)
tt->get_from_context = geometry_node_tree_get_from_context;
tt->foreach_nodeclass = foreach_nodeclass;
tt->valid_socket_type = geometry_node_tree_socket_type_valid;
tt->validate_link = geometry_node_tree_validate_link;
ntreeTypeAdd(tt);
}

View File

@ -0,0 +1,352 @@
/*
* 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.
*/
#include "node_geometry_util.hh"
#include "BLI_task.hh"
#include "UI_interface.h"
#include "UI_resources.h"
static bNodeSocketTemplate geo_node_attribute_vector_rotate_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Vector")},
{SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
{SOCK_STRING, N_("Center")},
{SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
{SOCK_STRING, N_("Axis")},
{SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_XYZ, PROP_NONE},
{SOCK_STRING, N_("Angle")},
{SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE},
{SOCK_STRING, N_("Rotation")},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{SOCK_BOOLEAN, N_("Invert")},
{SOCK_STRING, N_("Result")},
{-1, ""},
};
static bNodeSocketTemplate geo_node_attribute_vector_rotate_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static void geo_node_attribute_vector_rotate_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage;
const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode)
node_storage.mode;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiLayout *column = uiLayoutColumn(layout, false);
uiItemR(column, ptr, "rotation_mode", 0, "", ICON_NONE);
uiItemR(column, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE);
uiItemR(column, ptr, "input_type_center", 0, IFACE_("Center"), ICON_NONE);
if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS) {
uiItemR(column, ptr, "input_type_axis", 0, IFACE_("Axis"), ICON_NONE);
}
if (mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
uiItemR(column, ptr, "input_type_angle", 0, IFACE_("Angle"), ICON_NONE);
}
if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
uiItemR(column, ptr, "input_type_rotation", 0, IFACE_("Rotation"), ICON_NONE);
}
}
namespace blender::nodes {
static void geo_node_attribute_vector_rotate_update(bNodeTree *UNUSED(ntree), bNode *node)
{
const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage;
const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode)
node_storage->mode;
update_attribute_input_socket_availabilities(
*node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
update_attribute_input_socket_availabilities(
*node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center);
update_attribute_input_socket_availabilities(
*node,
"Axis",
(GeometryNodeAttributeInputMode)node_storage->input_type_axis,
(mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS));
update_attribute_input_socket_availabilities(
*node,
"Angle",
(GeometryNodeAttributeInputMode)node_storage->input_type_angle,
(mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
update_attribute_input_socket_availabilities(
*node,
"Rotation",
(GeometryNodeAttributeInputMode)node_storage->input_type_rotation,
(mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
}
static float3 vector_rotate_around_axis(const float3 vector,
const float3 center,
const float3 axis,
const float angle)
{
float3 result = vector - center;
float mat[3][3];
axis_angle_to_mat3(mat, axis, angle);
mul_m3_v3(mat, result);
return result + center;
}
static void geo_node_attribute_vector_rotate_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN(
sizeof(NodeAttributeVectorRotate), __func__);
node_storage->mode = GEO_NODE_VECTOR_ROTATE_TYPE_AXIS;
node_storage->input_type_vector = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node_storage->input_type_center = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node_storage->input_type_axis = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node_storage->input_type_angle = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node_storage->input_type_rotation = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = node_storage;
}
static float3 vector_rotate_euler(const float3 vector,
const float3 center,
const float3 rotation,
const bool invert)
{
float mat[3][3];
float3 result = vector - center;
eul_to_mat3(mat, rotation);
if (invert) {
invert_m3(mat);
}
mul_m3_v3(mat, result);
return result + center;
}
static void do_vector_rotate_around_axis(const VArray<float3> &vector,
const VArray<float3> &center,
const VArray<float3> &axis,
const VArray<float> &angle,
MutableSpan<float3> results,
const bool invert)
{
VArray_Span<float3> span_vector{vector};
VArray_Span<float3> span_center{center};
VArray_Span<float3> span_axis{axis};
VArray_Span<float> span_angle{angle};
parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
float angle = (invert) ? -span_angle[i] : span_angle[i];
results[i] = vector_rotate_around_axis(span_vector[i], span_center[i], span_axis[i], angle);
}
});
}
static void do_vector_rotate_around_fixed_axis(const VArray<float3> &vector,
const VArray<float3> &center,
const float3 axis,
const VArray<float> &angle,
MutableSpan<float3> results,
const bool invert)
{
VArray_Span<float3> span_vector{vector};
VArray_Span<float3> span_center{center};
VArray_Span<float> span_angle{angle};
parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
float angle = (invert) ? -span_angle[i] : span_angle[i];
results[i] = vector_rotate_around_axis(span_vector[i], span_center[i], axis, angle);
}
});
}
static void do_vector_rotate_euler(const VArray<float3> &vector,
const VArray<float3> &center,
const VArray<float3> &rotation,
MutableSpan<float3> results,
const bool invert)
{
VArray_Span<float3> span_vector{vector};
VArray_Span<float3> span_center{center};
VArray_Span<float3> span_rotation{rotation};
parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
for (const int i : range) {
results[i] = vector_rotate_euler(span_vector[i], span_center[i], span_rotation[i], invert);
}
});
}
static AttributeDomain get_result_domain(const GeometryComponent &component,
const GeoNodeExecParams &params,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(result_name);
if (meta_data) {
return meta_data->domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
const AttributeDomain default_domain = ATTR_DOMAIN_POINT;
return params.get_highest_priority_input_domain({"Vector", "Center"}, component, default_domain);
}
static void execute_on_component(const GeoNodeExecParams &params, GeometryComponent &component)
{
const bNode &node = params.node();
const NodeAttributeVectorRotate *node_storage = (const NodeAttributeVectorRotate *)node.storage;
const GeometryNodeAttributeVectorRotateMode mode = (GeometryNodeAttributeVectorRotateMode)
node_storage->mode;
const std::string result_name = params.get_input<std::string>("Result");
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
const bool invert = params.get_input<bool>("Invert");
GVArrayPtr attribute_vector = params.get_input_attribute(
"Vector", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_vector) {
return;
}
GVArrayPtr attribute_center = params.get_input_attribute(
"Center", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_center) {
return;
}
OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, result_domain, CD_PROP_FLOAT3);
if (!attribute_result) {
return;
}
if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
GVArrayPtr attribute_rotation = params.get_input_attribute(
"Rotation", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_rotation) {
return;
}
do_vector_rotate_euler(attribute_vector->typed<float3>(),
attribute_center->typed<float3>(),
attribute_rotation->typed<float3>(),
attribute_result.as_span<float3>(),
invert);
attribute_result.save();
return;
}
GVArrayPtr attribute_angle = params.get_input_attribute(
"Angle", component, result_domain, CD_PROP_FLOAT, nullptr);
if (!attribute_angle) {
return;
}
switch (mode) {
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS: {
GVArrayPtr attribute_axis = params.get_input_attribute(
"Axis", component, result_domain, CD_PROP_FLOAT3, nullptr);
if (!attribute_axis) {
return;
}
do_vector_rotate_around_axis(attribute_vector->typed<float3>(),
attribute_center->typed<float3>(),
attribute_axis->typed<float3>(),
attribute_angle->typed<float>(),
attribute_result.as_span<float3>(),
invert);
} break;
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X:
do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(),
attribute_center->typed<float3>(),
float3(1.0f, 0.0f, 0.0f),
attribute_angle->typed<float>(),
attribute_result.as_span<float3>(),
invert);
break;
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(),
attribute_center->typed<float3>(),
float3(0.0f, 1.0f, 0.0f),
attribute_angle->typed<float>(),
attribute_result.as_span<float3>(),
invert);
break;
case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(),
attribute_center->typed<float3>(),
float3(0.0f, 0.0f, 1.0f),
attribute_angle->typed<float>(),
attribute_result.as_span<float3>(),
invert);
break;
case GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ:
/* Euler is handled before other modes to avoid processing the unavailable angle socket. */
BLI_assert_unreachable();
break;
}
attribute_result.save();
}
static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
geometry_set = geometry_set_realize_instances(geometry_set);
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
}
if (geometry_set.has<PointCloudComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
}
if (geometry_set.has<CurveComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<CurveComponent>());
}
params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes
void register_node_type_geo_attribute_vector_rotate()
{
static bNodeType ntype;
geo_node_type_base(&ntype,
GEO_NODE_ATTRIBUTE_VECTOR_ROTATE,
"Attribute Vector Rotate",
NODE_CLASS_ATTRIBUTE,
0);
node_type_socket_templates(
&ntype, geo_node_attribute_vector_rotate_in, geo_node_attribute_vector_rotate_out);
node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_rotate_update);
node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_rotate_init);
node_type_size(&ntype, 165, 100, 600);
node_type_storage(
&ntype, "NodeAttributeVectorRotate", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_rotate_exec;
ntype.draw_buttons = geo_node_attribute_vector_rotate_layout;
nodeRegisterType(&ntype);
}

View File

@ -139,16 +139,16 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
{
std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
for (const SplinePtr &spline : input_curve.splines) {
for (const SplinePtr &spline : input_curve.splines()) {
if (mode_param.mode == GEO_NODE_CURVE_SAMPLE_COUNT) {
BLI_assert(mode_param.count);
output_curve->splines.append(resample_spline(*spline, *mode_param.count));
output_curve->add_spline(resample_spline(*spline, *mode_param.count));
}
else if (mode_param.mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
BLI_assert(mode_param.length);
const float length = spline->length();
const int count = length / *mode_param.length;
output_curve->splines.append(resample_spline(*spline, count));
output_curve->add_spline(resample_spline(*spline, count));
}
}

View File

@ -211,7 +211,7 @@ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &pr
{
int profile_vert_total = 0;
int profile_edge_total = 0;
for (const SplinePtr &profile_spline : profile_curve.splines) {
for (const SplinePtr &profile_spline : profile_curve.splines()) {
profile_vert_total += profile_spline->evaluated_points_size();
profile_edge_total += profile_spline->evaluated_edges_size();
}
@ -219,7 +219,7 @@ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &pr
int vert_total = 0;
int edge_total = 0;
int poly_total = 0;
for (const SplinePtr &spline : curve.splines) {
for (const SplinePtr &spline : curve.splines()) {
const int spline_vert_len = spline->evaluated_points_size();
const int spline_edge_len = spline->evaluated_edges_size();
vert_total += spline_vert_len * profile_vert_total;
@ -247,8 +247,8 @@ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &pr
int edge_offset = 0;
int loop_offset = 0;
int poly_offset = 0;
for (const SplinePtr &spline : curve.splines) {
for (const SplinePtr &profile_spline : profile_curve.splines) {
for (const SplinePtr &spline : curve.splines()) {
for (const SplinePtr &profile_spline : profile_curve.splines()) {
spline_extrude_to_mesh_data(*spline,
*profile_spline,
verts,
@ -272,7 +272,7 @@ static CurveEval get_curve_single_vert()
CurveEval curve;
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
spline->add_point(float3(0), 0, 0.0f);
curve.splines.append(std::move(spline));
curve.add_spline(std::move(spline));
return curve;
}

Some files were not shown because too many files have changed in this diff Show More