Merge branch 'master' into sculpt-dev
This commit is contained in:
commit
72aad83780
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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'}),
|
||||
|
|
|
@ -590,7 +590,7 @@ class PREFERENCES_OT_addon_install(Operator):
|
|||
name="Target Path",
|
||||
items=(
|
||||
('DEFAULT', "Default", ""),
|
||||
('PREFS', "User Prefs", ""),
|
||||
('PREFS', "Preferences", ""),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -494,6 +494,7 @@ geometry_node_categories = [
|
|||
NodeItem("GeometryNodeAttributeProximity"),
|
||||
NodeItem("GeometryNodeAttributeColorRamp"),
|
||||
NodeItem("GeometryNodeAttributeVectorMath"),
|
||||
NodeItem("GeometryNodeAttributeVectorRotate"),
|
||||
NodeItem("GeometryNodeAttributeSampleTexture"),
|
||||
NodeItem("GeometryNodeAttributeCombineXYZ"),
|
||||
NodeItem("GeometryNodeAttributeSeparateXYZ"),
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -148,5 +148,7 @@ void initNormalRotation(TransInfo *t)
|
|||
|
||||
storeCustomLNorValue(tc, bm);
|
||||
}
|
||||
|
||||
transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW);
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
/** ???. */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
||||
/* ------------------------------------------- */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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> ¢er,
|
||||
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> ¢er,
|
||||
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> ¢er,
|
||||
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 ¶ms,
|
||||
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 ¶ms, 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);
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue