Versioning function to replace legacy instancing panel by geometry node modifier #105494
|
@ -1589,6 +1589,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|||
add_check_c_compiler_flag(C_REMOVE_STRICT_FLAGS C_WARN_NO_DEPRECATED_DECLARATIONS -Wno-deprecated-declarations)
|
||||
add_check_c_compiler_flag(C_REMOVE_STRICT_FLAGS C_WARN_NO_STRICT_PROTOTYPES -Wno-strict-prototypes)
|
||||
add_check_c_compiler_flag(C_REMOVE_STRICT_FLAGS C_WARN_NO_BITWISE_INSTEAD_OF_LOGICAL -Wno-bitwise-instead-of-logical)
|
||||
add_check_c_compiler_flag(C_REMOVE_STRICT_FLAGS C_WARN_NO_IMPLICIT_CONST_INT_FLOAT_CONVERSION -Wno-implicit-const-int-float-conversion)
|
||||
|
||||
add_check_cxx_compiler_flag(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_UNUSED_PARAMETER -Wno-unused-parameter)
|
||||
add_check_cxx_compiler_flag(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_UNUSED_PRIVATE_FIELD -Wno-unused-private-field)
|
||||
|
@ -1603,6 +1604,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|||
add_check_cxx_compiler_flag(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_INSTANTIATION_AFTER_SPECIALIZATION -Wno-instantiation-after-specialization)
|
||||
add_check_cxx_compiler_flag(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_MISLEADING_INDENTATION -Wno-misleading-indentation)
|
||||
add_check_cxx_compiler_flag(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_BITWISE_INSTEAD_OF_LOGICAL -Wno-bitwise-instead-of-logical)
|
||||
add_check_cxx_compiler_flag(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_IMPLICIT_CONST_INT_FLOAT_CONVERSION -Wno-implicit-const-int-float-conversion)
|
||||
|
||||
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ ccl_device_forceinline float intersection_t_offset(const float t)
|
|||
* The check relies on the fact that comparison of de-normal values with zero
|
||||
* returns true. */
|
||||
if (t == 0.0f) {
|
||||
/* The value of std::numeric_limits<float>::min() and __FLT_MIN__, inlined
|
||||
* to ensure matched behavior on all platforms and compilers. */
|
||||
return 0x1p-126;
|
||||
/* The exact bit value of this should be 0x1p-126, but hex floating point values notation is
|
||||
* not available in CUDA/OptiX. */
|
||||
return FLT_MIN;
|
||||
}
|
||||
|
||||
const uint32_t bits = __float_as_uint(t) + 1;
|
||||
|
|
|
@ -5782,8 +5782,14 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
|
|||
}
|
||||
const GWL_ModifierInfo &mod_info = g_modifier_info_table[i];
|
||||
const bool val = (state & (1 << seat->xkb_keymap_mod_index[i])) != 0;
|
||||
bool val_l = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_l)] > 0;
|
||||
bool val_r = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_r)] > 0;
|
||||
/* NOTE(@ideasman42): it's important to write the XKB state back to #GWL_KeyboardDepressedState
|
||||
* otherwise changes to modifiers in the future wont generate events.
|
||||
* This can cause modifiers to be stuck when switching between windows in GNOME because
|
||||
* window activation is handled before the keyboard enter callback runs, see: #107314. */
|
||||
int16_t &depressed_l = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_l)];
|
||||
int16_t &depressed_r = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_r)];
|
||||
bool val_l = depressed_l > 0;
|
||||
bool val_r = depressed_r > 0;
|
||||
|
||||
/* This shouldn't be needed, but guard against any possibility of modifiers being stuck.
|
||||
* Warn so if this happens it can be investigated. */
|
||||
|
@ -5796,6 +5802,7 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
|
|||
}
|
||||
/* Picking the left is arbitrary. */
|
||||
val_l = true;
|
||||
depressed_l = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -5807,6 +5814,8 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
|
|||
}
|
||||
val_l = false;
|
||||
val_r = false;
|
||||
depressed_l = 0;
|
||||
depressed_r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,9 +43,10 @@ def get_context_modifier(context):
|
|||
if context.area.type == 'PROPERTIES':
|
||||
modifier = context.modifier
|
||||
else:
|
||||
if context.object is None:
|
||||
ob = context.object
|
||||
if ob is None:
|
||||
return False
|
||||
modifier = context.object.modifiers.active
|
||||
modifier = ob.modifiers.active
|
||||
if modifier is None or modifier.type != 'NODES':
|
||||
return None
|
||||
return modifier
|
||||
|
@ -207,7 +208,8 @@ class NewGeometryNodesModifier(Operator):
|
|||
return geometry_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
modifier = context.object.modifiers.new(data_("GeometryNodes"), "NODES")
|
||||
ob = context.object
|
||||
modifier = ob.modifiers.new(data_("GeometryNodes"), 'NODES')
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
|
|
@ -1345,6 +1345,7 @@ rna_custom_property_name = StringProperty(
|
|||
maxlen=63,
|
||||
)
|
||||
|
||||
# Most useful entries of rna_enum_property_subtype_items:
|
||||
rna_custom_property_type_items = (
|
||||
('FLOAT', "Float", "A single floating-point value"),
|
||||
('FLOAT_ARRAY', "Float Array", "An array of floating-point values"),
|
||||
|
@ -1356,9 +1357,22 @@ rna_custom_property_type_items = (
|
|||
('PYTHON', "Python", "Edit a python value directly, for unsupported property types"),
|
||||
)
|
||||
|
||||
# Most useful entries of rna_enum_property_subtype_items for number arrays:
|
||||
rna_vector_subtype_items = (
|
||||
('NONE', "Plain Data", "Data values without special behavior"),
|
||||
rna_custom_property_subtype_none_item = ('NONE', "Plain Data", "Data values without special behavior")
|
||||
|
||||
rna_custom_property_subtype_number_items = (
|
||||
rna_custom_property_subtype_none_item,
|
||||
('PIXEL', "Pixel", ""),
|
||||
('PERCENTAGE', "Percentage", ""),
|
||||
('FACTOR', "Factor", ""),
|
||||
('ANGLE', "Angle", ""),
|
||||
('TIME_ABSOLUTE', "Time", "Time specified in seconds"),
|
||||
('DISTANCE', "Distance", ""),
|
||||
('POWER', "Power", ""),
|
||||
('TEMPERATURE', "Temperature", ""),
|
||||
)
|
||||
|
||||
rna_custom_property_subtype_vector_items = (
|
||||
rna_custom_property_subtype_none_item,
|
||||
('COLOR', "Linear Color", "Color in the linear space"),
|
||||
('COLOR_GAMMA', "Gamma-Corrected Color", "Color in the gamma corrected space"),
|
||||
('EULER', "Euler Angles", "Euler rotation angles in radians"),
|
||||
|
@ -1373,6 +1387,17 @@ class WM_OT_properties_edit(Operator):
|
|||
# register only because invoke_props_popup requires.
|
||||
bl_options = {'REGISTER', 'INTERNAL'}
|
||||
|
||||
def subtype_items_cb(self, context):
|
||||
match self.property_type:
|
||||
case 'FLOAT':
|
||||
return rna_custom_property_subtype_number_items
|
||||
case 'FLOAT_ARRAY':
|
||||
return rna_custom_property_subtype_vector_items
|
||||
return ()
|
||||
|
||||
def property_type_update_cb(self, context):
|
||||
self.subtype = 'NONE'
|
||||
|
||||
# Common settings used for all property types. Generally, separate properties are used for each
|
||||
# type to improve the experience when choosing UI data values.
|
||||
|
||||
|
@ -1381,6 +1406,7 @@ class WM_OT_properties_edit(Operator):
|
|||
property_type: EnumProperty(
|
||||
name="Type",
|
||||
items=rna_custom_property_type_items,
|
||||
update=property_type_update_cb
|
||||
)
|
||||
is_overridable_library: BoolProperty(
|
||||
name="Library Overridable",
|
||||
|
@ -1481,7 +1507,7 @@ class WM_OT_properties_edit(Operator):
|
|||
)
|
||||
subtype: EnumProperty(
|
||||
name="Subtype",
|
||||
items=WM_OT_properties_edit.subtype_items,
|
||||
items=subtype_items_cb,
|
||||
)
|
||||
|
||||
# String properties.
|
||||
|
@ -1497,9 +1523,6 @@ class WM_OT_properties_edit(Operator):
|
|||
description="Python value for unsupported custom property types",
|
||||
)
|
||||
|
||||
type_items = rna_custom_property_type_items
|
||||
subtype_items = rna_vector_subtype_items
|
||||
|
||||
# Helper method to avoid repetitive code to retrieve a single value from sequences and non-sequences.
|
||||
@staticmethod
|
||||
def _convert_new_value_single(old_value, new_type):
|
||||
|
@ -1567,15 +1590,7 @@ class WM_OT_properties_edit(Operator):
|
|||
return 'PYTHON'
|
||||
|
||||
def _init_subtype(self, subtype):
|
||||
subtype = subtype or 'NONE'
|
||||
subtype_items = rna_vector_subtype_items
|
||||
|
||||
# Add a temporary enum entry to preserve unknown subtypes
|
||||
if not any(subtype == item[0] for item in subtype_items):
|
||||
subtype_items += ((subtype, subtype, ""),)
|
||||
|
||||
WM_OT_properties_edit.subtype_items = subtype_items
|
||||
self.subtype = subtype
|
||||
self.subtype = subtype or 'NONE'
|
||||
|
||||
# Fill the operator's properties with the UI data properties from the existing custom property.
|
||||
# Note that if the UI data doesn't exist yet, the access will create it and use those default values.
|
||||
|
@ -1904,9 +1919,7 @@ class WM_OT_properties_edit(Operator):
|
|||
layout.prop(self, "step_float")
|
||||
layout.prop(self, "precision")
|
||||
|
||||
# Subtype is only supported for float properties currently.
|
||||
if self.property_type != 'FLOAT':
|
||||
layout.prop(self, "subtype")
|
||||
layout.prop(self, "subtype")
|
||||
elif self.property_type in {'INT', 'INT_ARRAY'}:
|
||||
if self.property_type == 'INT_ARRAY':
|
||||
layout.prop(self, "array_length")
|
||||
|
|
|
@ -110,7 +110,8 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.object and context.object.type == 'ARMATURE' and context.object.pose)
|
||||
ob = context.object
|
||||
return (ob and ob.type == 'ARMATURE' and ob.pose)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
|
|
@ -276,7 +276,7 @@ class OBJECT_PT_instancing_size(ObjectButtonsPanel, Panel):
|
|||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.object
|
||||
return ob.instance_type == 'FACES'
|
||||
return (ob is not None) and (ob.instance_type == 'FACES')
|
||||
|
||||
def draw_header(self, context):
|
||||
|
||||
|
@ -304,7 +304,8 @@ class OBJECT_PT_lineart(ObjectButtonsPanel, Panel):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
lineart = context.object.lineart
|
||||
ob = context.object
|
||||
lineart = ob.lineart
|
||||
|
||||
layout.use_property_split = True
|
||||
|
||||
|
@ -385,7 +386,7 @@ class OBJECT_PT_visibility(ObjectButtonsPanel, Panel):
|
|||
col.prop(ob, "hide_viewport", text="Viewports", toggle=False, invert_checkbox=True)
|
||||
col.prop(ob, "hide_render", text="Renders", toggle=False, invert_checkbox=True)
|
||||
|
||||
if context.object.type == 'GPENCIL':
|
||||
if ob.type == 'GPENCIL':
|
||||
col = layout.column(heading="Grease Pencil")
|
||||
col.prop(ob, "use_grease_pencil_lights", toggle=False)
|
||||
|
||||
|
|
|
@ -653,6 +653,11 @@ class MutableAttributeAccessor : public AttributeAccessor {
|
|||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the existing attribute with a new one with a different name.
|
||||
*/
|
||||
bool rename(const AttributeIDRef &old_attribute_id, const AttributeIDRef &new_attribute_id);
|
||||
|
||||
/**
|
||||
* Create a new attribute.
|
||||
* \return True, when a new attribute has been created. False, when it's not possible to create
|
||||
|
|
|
@ -38,6 +38,9 @@ class CurvesEditHints;
|
|||
class Instances;
|
||||
} // namespace blender::bke
|
||||
|
||||
class GeometryComponent;
|
||||
using GeometryComponentPtr = blender::ImplicitSharingPtr<GeometryComponent>;
|
||||
|
||||
/**
|
||||
* This is the base class for specialized geometry component types. A geometry component uses
|
||||
* implicit sharing to avoid read-only copies. It also integrates with attribute API, which
|
||||
|
@ -50,7 +53,7 @@ class GeometryComponent : public blender::ImplicitSharingMixin {
|
|||
public:
|
||||
GeometryComponent(GeometryComponentType type);
|
||||
virtual ~GeometryComponent() = default;
|
||||
static GeometryComponent *create(GeometryComponentType component_type);
|
||||
static GeometryComponentPtr create(GeometryComponentType component_type);
|
||||
|
||||
int attribute_domain_size(eAttrDomain domain) const;
|
||||
|
||||
|
@ -64,6 +67,9 @@ class GeometryComponent : public blender::ImplicitSharingMixin {
|
|||
/* The returned component should be of the same type as the type this is called on. */
|
||||
virtual GeometryComponent *copy() const = 0;
|
||||
|
||||
/** Remove referenced data from the geometry component. */
|
||||
virtual void clear() = 0;
|
||||
|
||||
/* Direct data is everything except for instances of objects/collections.
|
||||
* If this returns true, the geometry set can be cached and is still valid after e.g. modifier
|
||||
* evaluation ends. Instances can only be valid as long as the data they instance is valid. */
|
||||
|
@ -76,6 +82,7 @@ class GeometryComponent : public blender::ImplicitSharingMixin {
|
|||
|
||||
private:
|
||||
void delete_self() override;
|
||||
void delete_data_only() override;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -101,7 +108,6 @@ inline constexpr bool is_geometry_component_v = std::is_base_of_v<GeometryCompon
|
|||
*/
|
||||
struct GeometrySet {
|
||||
private:
|
||||
using GeometryComponentPtr = blender::ImplicitSharingPtr<class GeometryComponent>;
|
||||
/* Indexed by #GeometryComponentType. */
|
||||
std::array<GeometryComponentPtr, GEO_COMPONENT_TYPE_ENUM_SIZE> components_;
|
||||
|
||||
|
@ -377,7 +383,7 @@ class MeshComponent : public GeometryComponent {
|
|||
~MeshComponent();
|
||||
GeometryComponent *copy() const override;
|
||||
|
||||
void clear();
|
||||
void clear() override;
|
||||
bool has_mesh() const;
|
||||
/**
|
||||
* Clear the component and replace it with the new mesh.
|
||||
|
@ -431,7 +437,7 @@ class PointCloudComponent : public GeometryComponent {
|
|||
~PointCloudComponent();
|
||||
GeometryComponent *copy() const override;
|
||||
|
||||
void clear();
|
||||
void clear() override;
|
||||
bool has_pointcloud() const;
|
||||
/**
|
||||
* Clear the component and replace it with the new point cloud.
|
||||
|
@ -493,7 +499,7 @@ class CurveComponent : public GeometryComponent {
|
|||
~CurveComponent();
|
||||
GeometryComponent *copy() const override;
|
||||
|
||||
void clear();
|
||||
void clear() override;
|
||||
bool has_curves() const;
|
||||
/**
|
||||
* Clear the component and replace it with the new curve.
|
||||
|
@ -534,7 +540,7 @@ class InstancesComponent : public GeometryComponent {
|
|||
~InstancesComponent();
|
||||
GeometryComponent *copy() const override;
|
||||
|
||||
void clear();
|
||||
void clear() override;
|
||||
|
||||
const blender::bke::Instances *get_for_read() const;
|
||||
blender::bke::Instances *get_for_write();
|
||||
|
@ -568,7 +574,7 @@ class VolumeComponent : public GeometryComponent {
|
|||
~VolumeComponent();
|
||||
GeometryComponent *copy() const override;
|
||||
|
||||
void clear();
|
||||
void clear() override;
|
||||
bool has_volume() const;
|
||||
/**
|
||||
* Clear the component and replace it with the new volume.
|
||||
|
@ -621,6 +627,8 @@ class GeometryComponentEditData final : public GeometryComponent {
|
|||
bool owns_direct_data() const final;
|
||||
void ensure_owns_direct_data() final;
|
||||
|
||||
void clear() override;
|
||||
|
||||
/**
|
||||
* The first node that does topology changing operations on curves should store the curve point
|
||||
* positions it retrieved as input. Without this, information about the deformed positions is
|
||||
|
|
|
@ -383,7 +383,8 @@ bool BKE_image_is_filename_tokenized(char *filepath);
|
|||
* Ensures that `filename` contains a UDIM token if we find a supported format pattern.
|
||||
* \note This must only be the name component (without slashes).
|
||||
*/
|
||||
void BKE_image_ensure_tile_token(char *filename);
|
||||
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy);
|
||||
void BKE_image_ensure_tile_token_filename_only(char *filename, size_t filename_maxncpy);
|
||||
|
||||
/**
|
||||
* When provided with an absolute virtual `filepath`, check to see if at least
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "BKE_customdata.h"
|
||||
#include "BKE_mesh_types.h"
|
||||
|
||||
struct BLI_Stack;
|
||||
struct BMesh;
|
||||
struct BMeshCreateParams;
|
||||
struct BMeshFromMeshParams;
|
||||
|
@ -44,13 +43,6 @@ struct Scene;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* setting zero so we can catch bugs in OpenMP/BMesh */
|
||||
#ifdef DEBUG
|
||||
# define BKE_MESH_OMP_LIMIT 0
|
||||
#else
|
||||
# define BKE_MESH_OMP_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* mesh_runtime.cc */
|
||||
|
||||
/**
|
||||
|
@ -397,9 +389,6 @@ typedef struct MLoopNorSpace {
|
|||
* - BMLoop pointers. */
|
||||
struct LinkNode *loops;
|
||||
char flags;
|
||||
|
||||
/** To be used for extended processing related to loop normal spaces (aka smooth fans). */
|
||||
void *user_data;
|
||||
} MLoopNorSpace;
|
||||
/**
|
||||
* MLoopNorSpace.flags
|
||||
|
@ -449,6 +438,9 @@ void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr,
|
|||
MLoopNorSpaceArray *lnors_spacearr_tls);
|
||||
|
||||
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/**
|
||||
* Should only be called once.
|
||||
* Beware, this modifies ref_vec and other_vec in place!
|
||||
|
@ -459,7 +451,10 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
|
|||
const float lnor[3],
|
||||
float vec_ref[3],
|
||||
float vec_other[3],
|
||||
struct BLI_Stack *edge_vectors);
|
||||
blender::Span<blender::float3> edge_vectors);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Add a new given loop to given lnor_space.
|
||||
* Depending on \a lnor_space->data_type, we expect \a bm_loop to be a pointer to BMLoop struct
|
||||
|
|
|
@ -911,6 +911,41 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span
|
|||
return {};
|
||||
}
|
||||
|
||||
bool MutableAttributeAccessor::rename(const AttributeIDRef &old_attribute_id,
|
||||
const AttributeIDRef &new_attribute_id)
|
||||
{
|
||||
if (old_attribute_id == new_attribute_id) {
|
||||
return true;
|
||||
}
|
||||
if (this->contains(new_attribute_id)) {
|
||||
return false;
|
||||
}
|
||||
const GAttributeReader old_attribute = this->lookup(old_attribute_id);
|
||||
if (!old_attribute) {
|
||||
return false;
|
||||
}
|
||||
const eCustomDataType type = cpp_type_to_custom_data_type(old_attribute.varray.type());
|
||||
if (old_attribute.sharing_info != nullptr && old_attribute.varray.is_span()) {
|
||||
if (!this->add(new_attribute_id,
|
||||
old_attribute.domain,
|
||||
type,
|
||||
AttributeInitShared{old_attribute.varray.get_internal_span().data(),
|
||||
*old_attribute.sharing_info})) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this->add(new_attribute_id,
|
||||
old_attribute.domain,
|
||||
type,
|
||||
AttributeInitVArray{old_attribute.varray})) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this->remove(old_attribute_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn::GField AttributeValidator::validate_field_if_necessary(const fn::GField &field) const
|
||||
{
|
||||
if (function) {
|
||||
|
|
|
@ -531,7 +531,7 @@ static bool absolute_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
|
|||
return false; /* Already absolute. */
|
||||
}
|
||||
|
||||
BLI_strncpy(path_dst, path_src, FILENAME_MAX);
|
||||
BLI_strncpy(path_dst, path_src, FILE_MAX);
|
||||
BLI_path_abs(path_dst, data->basedir);
|
||||
if (BLI_path_is_rel(path_dst) == false) {
|
||||
data->count_changed++;
|
||||
|
|
|
@ -281,7 +281,7 @@ void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType
|
|||
}
|
||||
}
|
||||
/* A potential performance optimization is only counting the changed indices. */
|
||||
this->curve_types_for_write().fill_indices(selection, type);
|
||||
this->curve_types_for_write().fill_indices(selection.indices(), type);
|
||||
this->update_curve_types();
|
||||
this->tag_topology_changed();
|
||||
}
|
||||
|
|
|
@ -2358,21 +2358,30 @@ CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData
|
|||
class CustomDataLayerImplicitSharing : public ImplicitSharingInfo {
|
||||
private:
|
||||
const void *data_;
|
||||
const int totelem_;
|
||||
int totelem_;
|
||||
const eCustomDataType type_;
|
||||
|
||||
public:
|
||||
CustomDataLayerImplicitSharing(const void *data, const int totelem, const eCustomDataType type)
|
||||
: ImplicitSharingInfo(1), data_(data), totelem_(totelem), type_(type)
|
||||
: ImplicitSharingInfo(), data_(data), totelem_(totelem), type_(type)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void delete_self_with_data() override
|
||||
{
|
||||
free_layer_data(type_, data_, totelem_);
|
||||
if (data_ != nullptr) {
|
||||
free_layer_data(type_, data_, totelem_);
|
||||
}
|
||||
MEM_delete(this);
|
||||
}
|
||||
|
||||
void delete_data_only() override
|
||||
{
|
||||
free_layer_data(type_, data_, totelem_);
|
||||
data_ = nullptr;
|
||||
totelem_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/** Create a #ImplicitSharingInfo that takes ownership of the data. */
|
||||
|
@ -2395,7 +2404,10 @@ static void ensure_layer_data_is_mutable(CustomDataLayer &layer, const int totel
|
|||
/* Can not be shared without implicit-sharing data. */
|
||||
return;
|
||||
}
|
||||
if (layer.sharing_info->is_shared()) {
|
||||
if (layer.sharing_info->is_mutable()) {
|
||||
layer.sharing_info->tag_ensured_mutable();
|
||||
}
|
||||
else {
|
||||
const eCustomDataType type = eCustomDataType(layer.type);
|
||||
const void *old_data = layer.data;
|
||||
/* Copy the layer before removing the user because otherwise the data might be freed while
|
||||
|
|
|
@ -41,7 +41,7 @@ GeometryComponent *CurveComponent::copy() const
|
|||
|
||||
void CurveComponent::clear()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
BLI_assert(this->is_mutable() || this->is_expired());
|
||||
if (curves_ != nullptr) {
|
||||
if (ownership_ == GeometryOwnershipType::Owned) {
|
||||
BKE_id_free(nullptr, curves_);
|
||||
|
|
|
@ -29,6 +29,12 @@ void GeometryComponentEditData::ensure_owns_direct_data()
|
|||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
void GeometryComponentEditData::clear()
|
||||
{
|
||||
BLI_assert(this->is_mutable() || this->is_expired());
|
||||
curves_edit_hints_.reset();
|
||||
}
|
||||
|
||||
void GeometryComponentEditData::remember_deformed_curve_positions_if_necessary(
|
||||
GeometrySet &geometry)
|
||||
{
|
||||
|
|
|
@ -56,7 +56,7 @@ GeometryComponent *InstancesComponent::copy() const
|
|||
|
||||
void InstancesComponent::clear()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
BLI_assert(this->is_mutable() || this->is_expired());
|
||||
if (ownership_ == GeometryOwnershipType::Owned) {
|
||||
delete instances_;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ GeometryComponent *MeshComponent::copy() const
|
|||
|
||||
void MeshComponent::clear()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
BLI_assert(this->is_mutable() || this->is_expired());
|
||||
if (mesh_ != nullptr) {
|
||||
if (ownership_ == GeometryOwnershipType::Owned) {
|
||||
BKE_id_free(nullptr, mesh_);
|
||||
|
|
|
@ -31,7 +31,7 @@ GeometryComponent *PointCloudComponent::copy() const
|
|||
|
||||
void PointCloudComponent::clear()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
BLI_assert(this->is_mutable() || this->is_expired());
|
||||
if (pointcloud_ != nullptr) {
|
||||
if (ownership_ == GeometryOwnershipType::Owned) {
|
||||
BKE_id_free(nullptr, pointcloud_);
|
||||
|
|
|
@ -29,7 +29,7 @@ GeometryComponent *VolumeComponent::copy() const
|
|||
|
||||
void VolumeComponent::clear()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
BLI_assert(this->is_mutable() || this->is_expired());
|
||||
if (volume_ != nullptr) {
|
||||
if (ownership_ == GeometryOwnershipType::Owned) {
|
||||
BKE_id_free(nullptr, volume_);
|
||||
|
|
|
@ -41,7 +41,7 @@ using blender::bke::Instances;
|
|||
|
||||
GeometryComponent::GeometryComponent(GeometryComponentType type) : type_(type) {}
|
||||
|
||||
GeometryComponent *GeometryComponent::create(GeometryComponentType component_type)
|
||||
GeometryComponentPtr GeometryComponent::create(GeometryComponentType component_type)
|
||||
{
|
||||
switch (component_type) {
|
||||
case GEO_COMPONENT_TYPE_MESH:
|
||||
|
@ -58,7 +58,7 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
|
|||
return new GeometryComponentEditData();
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
int GeometryComponent::attribute_domain_size(const eAttrDomain domain) const
|
||||
|
@ -97,6 +97,11 @@ void GeometryComponent::delete_self()
|
|||
delete this;
|
||||
}
|
||||
|
||||
void GeometryComponent::delete_data_only()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -120,6 +125,7 @@ GeometryComponent &GeometrySet::get_component_for_write(GeometryComponentType co
|
|||
}
|
||||
if (component_ptr->is_mutable()) {
|
||||
/* If the referenced component is already mutable, return it directly. */
|
||||
component_ptr->tag_ensured_mutable();
|
||||
return *component_ptr;
|
||||
}
|
||||
/* If the referenced component is shared, make a copy. The copy is not shared and is
|
||||
|
@ -571,7 +577,7 @@ void GeometrySet::gather_attributes_for_propagation(
|
|||
using namespace blender::bke;
|
||||
/* Only needed right now to check if an attribute is built-in on this component type.
|
||||
* TODO: Get rid of the dummy component. */
|
||||
const GeometryComponent *dummy_component = GeometryComponent::create(dst_component_type);
|
||||
const GeometryComponentPtr dummy_component = GeometryComponent::create(dst_component_type);
|
||||
this->attribute_foreach(
|
||||
component_types,
|
||||
include_instances,
|
||||
|
@ -611,7 +617,6 @@ void GeometrySet::gather_attributes_for_propagation(
|
|||
};
|
||||
r_attributes.add_or_modify(attribute_id, add_info, modify_info);
|
||||
});
|
||||
delete dummy_component;
|
||||
}
|
||||
|
||||
static void gather_component_types_recursive(const GeometrySet &geometry_set,
|
||||
|
|
|
@ -3112,8 +3112,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
|
|||
}
|
||||
else {
|
||||
/* When changing to UDIM, attempt to tokenize the filepath. */
|
||||
char *filename = (char *)BLI_path_basename(ima->filepath);
|
||||
BKE_image_ensure_tile_token(filename);
|
||||
BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
|
||||
}
|
||||
|
||||
/* image buffers for non-sequence multilayer will share buffers with RenderResult,
|
||||
|
@ -3304,7 +3303,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
|
|||
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
|
||||
|
||||
if (!BKE_image_is_filename_tokenized(filename)) {
|
||||
BKE_image_ensure_tile_token(filename);
|
||||
BKE_image_ensure_tile_token_filename_only(filename, sizeof(filename));
|
||||
}
|
||||
|
||||
eUDIM_TILE_FORMAT tile_format;
|
||||
|
@ -3494,7 +3493,7 @@ bool BKE_image_is_filename_tokenized(char *filepath)
|
|||
return strstr(filename, "<UDIM>") != nullptr || strstr(filename, "<UVTILE>") != nullptr;
|
||||
}
|
||||
|
||||
void BKE_image_ensure_tile_token(char *filename)
|
||||
void BKE_image_ensure_tile_token_filename_only(char *filename, size_t filename_maxncpy)
|
||||
{
|
||||
BLI_assert_msg(BLI_path_slash_find(filename) == nullptr,
|
||||
"Only the file-name component should be used!");
|
||||
|
@ -3511,18 +3510,24 @@ void BKE_image_ensure_tile_token(char *filename)
|
|||
* 1000 through 2000 to provide better detection. */
|
||||
std::regex pattern(R"((.*[._-])([12]\d{3})([._-].*))");
|
||||
if (std::regex_search(path, match, pattern)) {
|
||||
BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), FILE_MAX);
|
||||
BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), filename_maxncpy);
|
||||
return;
|
||||
}
|
||||
|
||||
/* General `u##_v###` `uvtile` pattern. */
|
||||
pattern = std::regex(R"((.*)(u\d{1,2}_v\d{1,3})(\D.*))");
|
||||
if (std::regex_search(path, match, pattern)) {
|
||||
BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), FILE_MAX);
|
||||
BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), filename_maxncpy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
|
||||
{
|
||||
char *filename = (char *)BLI_path_basename(filepath);
|
||||
BKE_image_ensure_tile_token_filename_only(filename, filepath_maxncpy - (filename - filepath));
|
||||
}
|
||||
|
||||
bool BKE_image_tile_filepath_exists(const char *filepath)
|
||||
{
|
||||
BLI_assert(!BLI_path_is_rel(filepath));
|
||||
|
@ -5136,8 +5141,8 @@ void BKE_image_user_file_path_ex(const Main *bmain,
|
|||
int index;
|
||||
if (ima->source == IMA_SRC_SEQUENCE) {
|
||||
index = iuser ? iuser->framenr : ima->lastframe;
|
||||
BLI_path_sequence_decode(filepath, head, tail, &numlen);
|
||||
BLI_path_sequence_encode(filepath, head, tail, numlen, index);
|
||||
BLI_path_sequence_decode(filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
|
||||
BLI_path_sequence_encode(filepath, FILE_MAX, head, tail, numlen, index);
|
||||
}
|
||||
else if (resolve_udim) {
|
||||
index = image_get_tile_number_from_iuser(ima, iuser);
|
||||
|
@ -5277,7 +5282,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int
|
|||
|
||||
int BKE_image_sequence_guess_offset(Image *image)
|
||||
{
|
||||
return BLI_path_sequence_decode(image->filepath, nullptr, nullptr, nullptr);
|
||||
return BLI_path_sequence_decode(image->filepath, nullptr, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
bool BKE_image_has_anim(Image *ima)
|
||||
|
|
|
@ -18,7 +18,7 @@ TEST(udim, image_ensure_tile_token)
|
|||
char result[FILE_MAX];
|
||||
|
||||
BLI_strncpy(result, original, sizeof(result));
|
||||
BKE_image_ensure_tile_token(result);
|
||||
BKE_image_ensure_tile_token_filename_only(result, sizeof(result));
|
||||
EXPECT_STREQ(result, expected);
|
||||
};
|
||||
|
||||
|
|
|
@ -19,13 +19,10 @@
|
|||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_bit_vector.hh"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_linklist_stack.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_stack.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_timeit.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
@ -474,7 +471,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
|
|||
const float lnor[3],
|
||||
float vec_ref[3],
|
||||
float vec_other[3],
|
||||
BLI_Stack *edge_vectors)
|
||||
const blender::Span<blender::float3> edge_vectors)
|
||||
{
|
||||
const float pi2 = float(M_PI) * 2.0f;
|
||||
float tvec[3], dtp;
|
||||
|
@ -486,31 +483,24 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
|
|||
/* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
|
||||
* tag it as invalid and abort. */
|
||||
lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
|
||||
|
||||
if (edge_vectors) {
|
||||
BLI_stack_clear(edge_vectors);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
copy_v3_v3(lnor_space->vec_lnor, lnor);
|
||||
|
||||
/* Compute ref alpha, average angle of all available edge vectors to lnor. */
|
||||
if (edge_vectors) {
|
||||
if (!edge_vectors.is_empty()) {
|
||||
float alpha = 0.0f;
|
||||
int count = 0;
|
||||
while (!BLI_stack_is_empty(edge_vectors)) {
|
||||
const float *vec = (const float *)BLI_stack_peek(edge_vectors);
|
||||
for (const blender::float3 &vec : edge_vectors) {
|
||||
alpha += saacosf(dot_v3v3(vec, lnor));
|
||||
BLI_stack_discard(edge_vectors);
|
||||
count++;
|
||||
}
|
||||
/* This piece of code shall only be called for more than one loop. */
|
||||
/* NOTE: In theory, this could be `count > 2`,
|
||||
* but there is one case where we only have two edges for two loops:
|
||||
* a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.).
|
||||
*/
|
||||
BLI_assert(count >= 2); /* This piece of code shall only be called for more than one loop. */
|
||||
lnor_space->ref_alpha = alpha / float(count);
|
||||
BLI_assert(edge_vectors.size() >= 2);
|
||||
lnor_space->ref_alpha = alpha / float(edge_vectors.size());
|
||||
}
|
||||
else {
|
||||
lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) +
|
||||
|
@ -666,23 +656,6 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space,
|
|||
|
||||
namespace blender::bke::mesh {
|
||||
|
||||
#define LOOP_SPLIT_TASK_BLOCK_SIZE 1024
|
||||
|
||||
struct LoopSplitTaskData {
|
||||
enum class Type : int8_t {
|
||||
BlockEnd = 0, /* Set implicitly by calloc. */
|
||||
Fan = 1,
|
||||
Single = 2,
|
||||
};
|
||||
|
||||
/** We have to create those outside of tasks, since #MemArena is not thread-safe. */
|
||||
MLoopNorSpace *lnor_space;
|
||||
int ml_curr_index;
|
||||
int poly_index;
|
||||
|
||||
Type flag;
|
||||
};
|
||||
|
||||
struct LoopSplitTaskDataCommon {
|
||||
/* Read/write.
|
||||
* Note we do not need to protect it, though, since two different tasks will *always* affect
|
||||
|
@ -855,54 +828,39 @@ static void loop_manifold_fan_around_vert_next(const Span<int> corner_verts,
|
|||
}
|
||||
}
|
||||
|
||||
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
|
||||
static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data,
|
||||
const int ml_curr_index,
|
||||
MLoopNorSpace *lnor_space)
|
||||
{
|
||||
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
|
||||
const Span<short2> clnors_data = common_data->clnors_data;
|
||||
|
||||
const Span<float3> positions = common_data->positions;
|
||||
const Span<int2> edges = common_data->edges;
|
||||
const OffsetIndices polys = common_data->polys;
|
||||
const Span<int> corner_verts = common_data->corner_verts;
|
||||
const Span<int> corner_edges = common_data->corner_edges;
|
||||
const Span<int> loop_to_poly = common_data->loop_to_poly;
|
||||
const Span<float3> poly_normals = common_data->poly_normals;
|
||||
MutableSpan<float3> loop_normals = common_data->loop_normals;
|
||||
|
||||
MLoopNorSpace *lnor_space = data->lnor_space;
|
||||
const int ml_curr_index = data->ml_curr_index;
|
||||
const int poly_index = data->poly_index;
|
||||
loop_normals[ml_curr_index] = poly_normals[loop_to_poly[ml_curr_index]];
|
||||
|
||||
/* Simple case (both edges around that vertex are sharp in current polygon),
|
||||
* this loop just takes its poly normal.
|
||||
*/
|
||||
loop_normals[ml_curr_index] = poly_normals[poly_index];
|
||||
if (MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr) {
|
||||
const Span<float3> positions = common_data->positions;
|
||||
const Span<int2> edges = common_data->edges;
|
||||
const OffsetIndices polys = common_data->polys;
|
||||
const Span<int> corner_verts = common_data->corner_verts;
|
||||
const Span<int> corner_edges = common_data->corner_edges;
|
||||
const Span<short2> clnors_data = common_data->clnors_data;
|
||||
|
||||
#if 0
|
||||
printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n",
|
||||
ml_curr_index,
|
||||
loops[ml_curr_index].e,
|
||||
loops[ml_curr_index].v,
|
||||
poly_index);
|
||||
#endif
|
||||
|
||||
/* If needed, generate this (simple!) lnor space. */
|
||||
if (lnors_spacearr) {
|
||||
float vec_curr[3], vec_prev[3];
|
||||
const int poly_index = loop_to_poly[ml_curr_index];
|
||||
const int ml_prev_index = mesh::poly_corner_prev(polys[poly_index], ml_curr_index);
|
||||
|
||||
/* The vertex we are "fanning" around. */
|
||||
const int vert_pivot = corner_verts[ml_curr_index];
|
||||
const int2 &edge = edges[corner_edges[ml_curr_index]];
|
||||
const int vert_2 = edge_other_vert(edge, vert_pivot);
|
||||
const int2 &edge_prev = edges[corner_edges[ml_prev_index]];
|
||||
const int vert_3 = edge_other_vert(edge_prev, vert_pivot);
|
||||
const int vert_2 = edge_other_vert(edges[corner_edges[ml_curr_index]], vert_pivot);
|
||||
const int vert_3 = edge_other_vert(edges[corner_edges[ml_prev_index]], vert_pivot);
|
||||
|
||||
sub_v3_v3v3(vec_curr, positions[vert_2], positions[vert_pivot]);
|
||||
normalize_v3(vec_curr);
|
||||
sub_v3_v3v3(vec_prev, positions[vert_3], positions[vert_pivot]);
|
||||
normalize_v3(vec_prev);
|
||||
|
||||
BKE_lnor_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, nullptr);
|
||||
BKE_lnor_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {});
|
||||
/* We know there is only one loop in this space, no need to create a link-list in this case. */
|
||||
BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true);
|
||||
|
||||
|
@ -914,8 +872,9 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
|
|||
}
|
||||
|
||||
static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
||||
LoopSplitTaskData *data,
|
||||
BLI_Stack *edge_vectors)
|
||||
const int ml_curr_index,
|
||||
MLoopNorSpace *lnor_space,
|
||||
Vector<float3> *edge_vectors)
|
||||
{
|
||||
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
|
||||
MutableSpan<float3> loop_normals = common_data->loop_normals;
|
||||
|
@ -930,12 +889,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
|||
const Span<int> loop_to_poly = common_data->loop_to_poly;
|
||||
const Span<float3> poly_normals = common_data->poly_normals;
|
||||
|
||||
MLoopNorSpace *lnor_space = data->lnor_space;
|
||||
#if 0 /* Not needed for 'fan' loops. */
|
||||
float(*lnor)[3] = data->lnor;
|
||||
#endif
|
||||
const int ml_curr_index = data->ml_curr_index;
|
||||
const int poly_index = data->poly_index;
|
||||
const int poly_index = loop_to_poly[ml_curr_index];
|
||||
const int ml_prev_index = poly_corner_prev(polys[poly_index], ml_curr_index);
|
||||
|
||||
/* Sigh! we have to fan around current vertex, until we find the other non-smooth edge,
|
||||
|
@ -950,7 +904,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
|||
const int2 &edge_orig = edges[corner_edges[ml_curr_index]];
|
||||
|
||||
float vec_curr[3], vec_prev[3], vec_org[3];
|
||||
float lnor[3] = {0.0f, 0.0f, 0.0f};
|
||||
float3 lnor(0.0f);
|
||||
|
||||
/* We validate clnors data on the fly - cheapest way to do! */
|
||||
int clnors_avg[2] = {0, 0};
|
||||
|
@ -958,10 +912,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
|||
int clnors_count = 0;
|
||||
bool clnors_invalid = false;
|
||||
|
||||
/* Temp loop normal stack. */
|
||||
BLI_SMALLSTACK_DECLARE(normal, float *);
|
||||
/* Temp clnors stack. */
|
||||
BLI_SMALLSTACK_DECLARE(clnors, short *);
|
||||
Vector<int, 8> processed_corners;
|
||||
|
||||
/* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
|
||||
*/
|
||||
|
@ -981,7 +932,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
|||
copy_v3_v3(vec_prev, vec_org);
|
||||
|
||||
if (lnors_spacearr) {
|
||||
BLI_stack_push(edge_vectors, vec_org);
|
||||
edge_vectors->append(vec_org);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1021,20 +972,17 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
|||
clnors_avg[0] += (*clnor)[0];
|
||||
clnors_avg[1] += (*clnor)[1];
|
||||
clnors_count++;
|
||||
/* We store here a pointer to all custom loop_normals processed. */
|
||||
BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
|
||||
}
|
||||
}
|
||||
|
||||
/* We store here a pointer to all loop-normals processed. */
|
||||
BLI_SMALLSTACK_PUSH(normal, (float *)(loop_normals[mlfan_vert_index]));
|
||||
processed_corners.append(mlfan_vert_index);
|
||||
|
||||
if (lnors_spacearr) {
|
||||
/* Assign current lnor space to current 'vertex' loop. */
|
||||
BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, nullptr, false);
|
||||
if (edge != edge_orig) {
|
||||
/* We store here all edges-normalized vectors processed. */
|
||||
BLI_stack_push(edge_vectors, vec_curr);
|
||||
edge_vectors->append(vec_curr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1071,23 +1019,19 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
|||
lnor_len = 1.0f;
|
||||
}
|
||||
|
||||
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
|
||||
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors);
|
||||
edge_vectors->clear();
|
||||
|
||||
if (!clnors_data.is_empty()) {
|
||||
if (clnors_invalid) {
|
||||
short *clnor;
|
||||
|
||||
clnors_avg[0] /= clnors_count;
|
||||
clnors_avg[1] /= clnors_count;
|
||||
/* Fix/update all clnors of this fan with computed average value. */
|
||||
if (G.debug & G_DEBUG) {
|
||||
printf("Invalid clnors in this fan!\n");
|
||||
}
|
||||
while ((clnor = (short *)BLI_SMALLSTACK_POP(clnors))) {
|
||||
// print_v2("org clnor", clnor);
|
||||
clnor[0] = short(clnors_avg[0]);
|
||||
clnor[1] = short(clnors_avg[1]);
|
||||
}
|
||||
clnors_data.fill_indices(processed_corners.as_span(),
|
||||
short2(clnors_avg[0], clnors_avg[1]));
|
||||
// print_v2("new clnors", clnors_avg);
|
||||
}
|
||||
/* Extra bonus: since small-stack is local to this function,
|
||||
|
@ -1100,50 +1044,8 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
|
|||
/* In case we get a zero normal here, just use vertex normal already set! */
|
||||
if (LIKELY(lnor_len != 0.0f)) {
|
||||
/* Copy back the final computed normal into all related loop-normals. */
|
||||
float *nor;
|
||||
|
||||
while ((nor = (float *)BLI_SMALLSTACK_POP(normal))) {
|
||||
copy_v3_v3(nor, lnor);
|
||||
}
|
||||
loop_normals.fill_indices(processed_corners.as_span(), lnor);
|
||||
}
|
||||
/* Extra bonus: since small-stack is local to this function,
|
||||
* no more need to empty it at all cost! */
|
||||
}
|
||||
}
|
||||
|
||||
static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data,
|
||||
LoopSplitTaskData *data,
|
||||
BLI_Stack *edge_vectors)
|
||||
{
|
||||
if (data->flag == LoopSplitTaskData::Type::Fan) {
|
||||
BLI_assert((edge_vectors == nullptr) || BLI_stack_is_empty(edge_vectors));
|
||||
split_loop_nor_fan_do(common_data, data, edge_vectors);
|
||||
}
|
||||
else {
|
||||
/* No need for edge_vectors for 'single' case! */
|
||||
split_loop_nor_single_do(common_data, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
|
||||
{
|
||||
LoopSplitTaskDataCommon *common_data = (LoopSplitTaskDataCommon *)BLI_task_pool_user_data(pool);
|
||||
LoopSplitTaskData *data = (LoopSplitTaskData *)taskdata;
|
||||
|
||||
/* Temp edge vectors stack, only used when computing lnor spacearr. */
|
||||
BLI_Stack *edge_vectors = common_data->lnors_spacearr ?
|
||||
BLI_stack_new(sizeof(float[3]), __func__) :
|
||||
nullptr;
|
||||
|
||||
for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
|
||||
if (data->flag == LoopSplitTaskData::Type::BlockEnd) {
|
||||
break;
|
||||
}
|
||||
loop_split_worker_do(common_data, data, edge_vectors);
|
||||
}
|
||||
|
||||
if (edge_vectors) {
|
||||
BLI_stack_free(edge_vectors);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1218,10 +1120,10 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const Span<int> corner_
|
|||
}
|
||||
}
|
||||
|
||||
static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
|
||||
static void loop_split_generator(LoopSplitTaskDataCommon *common_data,
|
||||
Vector<int> &r_single_corners,
|
||||
Vector<int> &r_fan_corners)
|
||||
{
|
||||
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
|
||||
|
||||
const Span<int> corner_verts = common_data->corner_verts;
|
||||
const Span<int> corner_edges = common_data->corner_edges;
|
||||
const OffsetIndices polys = common_data->polys;
|
||||
|
@ -1230,23 +1132,10 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
|
|||
|
||||
BitVector<> skip_loops(corner_verts.size(), false);
|
||||
|
||||
LoopSplitTaskData *data_buff = nullptr;
|
||||
int data_idx = 0;
|
||||
|
||||
/* Temp edge vectors stack, only used when computing lnor spacearr
|
||||
* (and we are not multi-threading). */
|
||||
BLI_Stack *edge_vectors = nullptr;
|
||||
|
||||
#ifdef DEBUG_TIME
|
||||
SCOPED_TIMER_AVERAGED(__func__);
|
||||
#endif
|
||||
|
||||
if (!pool) {
|
||||
if (lnors_spacearr) {
|
||||
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/* We now know edges that can be smoothed (with their vector, and their two loops),
|
||||
* and edges that will be hard! Now, time to generate the normals.
|
||||
*/
|
||||
|
@ -1290,30 +1179,11 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
|
|||
// printf("SKIPPING!\n");
|
||||
}
|
||||
else {
|
||||
LoopSplitTaskData *data, data_local;
|
||||
|
||||
// printf("PROCESSING!\n");
|
||||
|
||||
if (pool) {
|
||||
if (data_idx == 0) {
|
||||
data_buff = (LoopSplitTaskData *)MEM_calloc_arrayN(
|
||||
LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__);
|
||||
}
|
||||
data = &data_buff[data_idx];
|
||||
}
|
||||
else {
|
||||
data = &data_local;
|
||||
memset(data, 0, sizeof(*data));
|
||||
}
|
||||
|
||||
if (IS_EDGE_SHARP(edge_to_loops[corner_edges[ml_curr_index]]) &&
|
||||
IS_EDGE_SHARP(edge_to_loops[corner_edges[ml_prev_index]])) {
|
||||
data->ml_curr_index = ml_curr_index;
|
||||
data->flag = LoopSplitTaskData::Type::Single;
|
||||
data->poly_index = poly_index;
|
||||
if (lnors_spacearr) {
|
||||
data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
|
||||
}
|
||||
/* Simple case (both edges around that vertex are sharp in current polygon),
|
||||
* this corner just takes its poly normal. */
|
||||
r_single_corners.append(ml_curr_index);
|
||||
}
|
||||
else {
|
||||
/* We do not need to check/tag loops as already computed. Due to the fact that a loop
|
||||
|
@ -1323,35 +1193,11 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
|
|||
* current edge, smooth previous edge), and not the alternative (smooth current edge,
|
||||
* sharp previous edge). All this due/thanks to the link between normals and loop
|
||||
* ordering (i.e. winding). */
|
||||
data->ml_curr_index = ml_curr_index;
|
||||
data->flag = LoopSplitTaskData::Type::Fan;
|
||||
data->poly_index = poly_index;
|
||||
if (lnors_spacearr) {
|
||||
data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
|
||||
}
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
data_idx++;
|
||||
if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
|
||||
BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr);
|
||||
data_idx = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
loop_split_worker_do(common_data, data, edge_vectors);
|
||||
r_fan_corners.append(ml_curr_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pool && data_idx) {
|
||||
BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr);
|
||||
}
|
||||
|
||||
if (edge_vectors) {
|
||||
BLI_stack_free(edge_vectors);
|
||||
}
|
||||
}
|
||||
|
||||
void normals_calc_loop(const Span<float3> vert_positions,
|
||||
|
@ -1472,19 +1318,34 @@ void normals_calc_loop(const Span<float3> vert_positions,
|
|||
edge_to_loops,
|
||||
{});
|
||||
|
||||
if (corner_verts.size() < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
|
||||
/* Not enough loops to be worth the whole threading overhead. */
|
||||
loop_split_generator(nullptr, &common_data);
|
||||
Vector<int> single_corners;
|
||||
Vector<int> fan_corners;
|
||||
loop_split_generator(&common_data, single_corners, fan_corners);
|
||||
|
||||
MLoopNorSpace *lnor_spaces = nullptr;
|
||||
if (r_lnors_spacearr) {
|
||||
r_lnors_spacearr->spaces_num = single_corners.size() + fan_corners.size();
|
||||
lnor_spaces = static_cast<MLoopNorSpace *>(BLI_memarena_calloc(
|
||||
r_lnors_spacearr->mem, sizeof(MLoopNorSpace) * r_lnors_spacearr->spaces_num));
|
||||
}
|
||||
else {
|
||||
TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH);
|
||||
|
||||
loop_split_generator(task_pool, &common_data);
|
||||
threading::parallel_for(single_corners.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
const int corner = single_corners[i];
|
||||
lnor_space_for_single_fan(&common_data, corner, lnor_spaces ? &lnor_spaces[i] : nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
BLI_task_pool_work_and_wait(task_pool);
|
||||
|
||||
BLI_task_pool_free(task_pool);
|
||||
}
|
||||
threading::parallel_for(fan_corners.index_range(), 1024, [&](const IndexRange range) {
|
||||
Vector<float3> edge_vectors;
|
||||
for (const int i : range) {
|
||||
const int corner = fan_corners[i];
|
||||
split_loop_nor_fan_do(&common_data,
|
||||
corner,
|
||||
lnor_spaces ? &lnor_spaces[single_corners.size() + i] : nullptr,
|
||||
&edge_vectors);
|
||||
}
|
||||
});
|
||||
|
||||
if (r_lnors_spacearr) {
|
||||
if (r_lnors_spacearr == &_lnors_spacearr) {
|
||||
|
@ -1534,7 +1395,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
|
|||
const bool use_split_normals = true;
|
||||
const float split_angle = float(M_PI);
|
||||
|
||||
BLI_SMALLSTACK_DECLARE(clnors_data, short *);
|
||||
Vector<short *> clnors_data;
|
||||
|
||||
/* Compute current lnor spacearr. */
|
||||
normals_calc_loop(positions,
|
||||
|
@ -1708,7 +1569,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
|
|||
else {
|
||||
int avg_nor_count = 0;
|
||||
float avg_nor[3];
|
||||
short clnor_data_tmp[2], *clnor_data;
|
||||
short clnor_data_tmp[2];
|
||||
|
||||
zero_v3(avg_nor);
|
||||
while (loop_link) {
|
||||
|
@ -1718,7 +1579,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
|
|||
|
||||
avg_nor_count++;
|
||||
add_v3_v3(avg_nor, nor);
|
||||
BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
|
||||
clnors_data.append(r_clnors_data[lidx]);
|
||||
|
||||
loop_link = loop_link->next;
|
||||
done_loops[lidx].reset();
|
||||
|
@ -1727,7 +1588,8 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
|
|||
mul_v3_fl(avg_nor, 1.0f / float(avg_nor_count));
|
||||
BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
|
||||
|
||||
while ((clnor_data = (short *)BLI_SMALLSTACK_POP(clnors_data))) {
|
||||
while (!clnors_data.is_empty()) {
|
||||
short *clnor_data = clnors_data.pop_last();
|
||||
clnor_data[0] = clnor_data_tmp[0];
|
||||
clnor_data[1] = clnor_data_tmp[1];
|
||||
}
|
||||
|
|
|
@ -481,15 +481,19 @@ static void get_sequence_filepath(const MovieClip *clip, const int framenr, char
|
|||
int offset;
|
||||
|
||||
BLI_strncpy(filepath, clip->filepath, sizeof(clip->filepath));
|
||||
BLI_path_sequence_decode(filepath, head, tail, &numlen);
|
||||
BLI_path_sequence_decode(filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
|
||||
|
||||
/* Movie-clips always points to first image from sequence, auto-guess offset for now.
|
||||
* Could be something smarter in the future. */
|
||||
offset = sequence_guess_offset(clip->filepath, strlen(head), numlen);
|
||||
|
||||
if (numlen) {
|
||||
BLI_path_sequence_encode(
|
||||
filepath, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
|
||||
BLI_path_sequence_encode(filepath,
|
||||
sizeof(filepath),
|
||||
head,
|
||||
tail,
|
||||
numlen,
|
||||
offset + framenr - clip->start_frame + clip->frame_offset);
|
||||
}
|
||||
else {
|
||||
BLI_strncpy(filepath, clip->filepath, sizeof(clip->filepath));
|
||||
|
@ -702,7 +706,7 @@ static void movieclip_calc_length(MovieClip *clip)
|
|||
ushort numlen;
|
||||
char filepath[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
|
||||
|
||||
BLI_path_sequence_decode(clip->filepath, head, tail, &numlen);
|
||||
BLI_path_sequence_decode(clip->filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
|
||||
|
||||
if (numlen == 0) {
|
||||
/* there's no number group in file name, assume it's single framed sequence */
|
||||
|
@ -790,7 +794,7 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr)
|
|||
ushort numlen;
|
||||
char head[FILE_MAX], tail[FILE_MAX];
|
||||
|
||||
BLI_path_sequence_decode(clip->filepath, head, tail, &numlen);
|
||||
BLI_path_sequence_decode(clip->filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
|
||||
|
||||
/* see comment in get_sequence_filepath */
|
||||
clip->cache->sequence_offset = sequence_guess_offset(clip->filepath, strlen(head), numlen);
|
||||
|
@ -933,7 +937,7 @@ static bool put_imbuf_cache(
|
|||
clip->cache->sequence_offset = -1;
|
||||
if (clip->source == MCLIP_SRC_SEQUENCE) {
|
||||
ushort numlen;
|
||||
BLI_path_sequence_decode(clip->filepath, NULL, NULL, &numlen);
|
||||
BLI_path_sequence_decode(clip->filepath, NULL, 0, NULL, 0, &numlen);
|
||||
clip->cache->is_still_sequence = (numlen == 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -654,8 +654,7 @@ int BKE_packedfile_unpack_image(Main *bmain,
|
|||
BLI_strncpy(ima->filepath, new_file_path, sizeof(imapf->filepath));
|
||||
if (ima->source == IMA_SRC_TILED) {
|
||||
/* Ensure that the Image filepath is kept in a tokenized format. */
|
||||
char *filename = (char *)BLI_path_basename(ima->filepath);
|
||||
BKE_image_ensure_tile_token(filename);
|
||||
BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
|
||||
}
|
||||
}
|
||||
MEM_freeN(new_file_path);
|
||||
|
|
|
@ -1301,7 +1301,7 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
|
|||
#define MAX_PTCACHE_PATH FILE_MAX
|
||||
#define MAX_PTCACHE_FILE (FILE_MAX * 2)
|
||||
|
||||
static int ptcache_path(PTCacheID *pid, char *dirname)
|
||||
static int ptcache_path(PTCacheID *pid, char dirname[MAX_PTCACHE_PATH])
|
||||
{
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
|
||||
|
@ -1311,13 +1311,13 @@ static int ptcache_path(PTCacheID *pid, char *dirname)
|
|||
size_t i;
|
||||
|
||||
if (pid->cache->flag & PTCACHE_EXTERNAL) {
|
||||
strcpy(dirname, pid->cache->path);
|
||||
BLI_strncpy(dirname, pid->cache->path, MAX_PTCACHE_PATH);
|
||||
|
||||
if (BLI_path_is_rel(dirname)) {
|
||||
BLI_path_abs(dirname, blendfilename);
|
||||
}
|
||||
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
|
||||
}
|
||||
if ((blendfile_path[0] != '\0') || lib) {
|
||||
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
|
||||
|
@ -1334,18 +1334,18 @@ static int ptcache_path(PTCacheID *pid, char *dirname)
|
|||
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
|
||||
|
||||
BLI_path_abs(dirname, blendfilename);
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
|
||||
}
|
||||
|
||||
/* use the temp path. this is weak but better than not using point cache at all */
|
||||
/* temporary directory is assumed to exist and ALWAYS has a trailing slash */
|
||||
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session());
|
||||
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
|
||||
}
|
||||
|
||||
static size_t ptcache_filepath_ext_append(PTCacheID *pid,
|
||||
char *filepath,
|
||||
char filepath[MAX_PTCACHE_FILE],
|
||||
const size_t filepath_len,
|
||||
const bool use_frame_number,
|
||||
const int cfra)
|
||||
|
@ -1396,8 +1396,11 @@ static size_t ptcache_filepath_ext_append(PTCacheID *pid,
|
|||
return len;
|
||||
}
|
||||
|
||||
static int ptcache_filepath(
|
||||
PTCacheID *pid, char *filepath, int cfra, const bool do_path, const bool do_ext)
|
||||
static int ptcache_filepath(PTCacheID *pid,
|
||||
char filepath[MAX_PTCACHE_FILE],
|
||||
int cfra,
|
||||
const bool do_path,
|
||||
const bool do_ext)
|
||||
{
|
||||
int len = 0;
|
||||
char *idname;
|
||||
|
@ -2591,7 +2594,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
|
|||
char path[MAX_PTCACHE_PATH];
|
||||
char filepath[MAX_PTCACHE_FILE];
|
||||
char path_full[MAX_PTCACHE_FILE];
|
||||
char ext[MAX_PTCACHE_PATH];
|
||||
char ext[MAX_PTCACHE_FILE];
|
||||
|
||||
if (!pid || !pid->cache || pid->cache->flag & PTCACHE_BAKED) {
|
||||
return;
|
||||
|
@ -2818,7 +2821,7 @@ void BKE_ptcache_id_time(
|
|||
struct dirent *de;
|
||||
char path[MAX_PTCACHE_PATH];
|
||||
char filepath[MAX_PTCACHE_FILE];
|
||||
char ext[MAX_PTCACHE_PATH];
|
||||
char ext[MAX_PTCACHE_FILE];
|
||||
uint len; /* store the length of the string */
|
||||
|
||||
ptcache_path(pid, path);
|
||||
|
@ -3490,7 +3493,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
|
|||
char old_filepath[MAX_PTCACHE_FILE];
|
||||
char new_path_full[MAX_PTCACHE_FILE];
|
||||
char old_path_full[MAX_PTCACHE_FILE];
|
||||
char ext[MAX_PTCACHE_PATH];
|
||||
char ext[MAX_PTCACHE_FILE];
|
||||
|
||||
/* If both names are the same, there is nothing to do. */
|
||||
if (STREQ(name_src, name_dst)) {
|
||||
|
|
|
@ -412,7 +412,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
|
|||
data.tree = calc->tree;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
|
||||
settings.use_threading = (calc->numVerts > 10000);
|
||||
settings.userdata_chunk = &nearest;
|
||||
settings.userdata_chunk_size = sizeof(nearest);
|
||||
BLI_task_parallel_range(
|
||||
|
@ -691,7 +691,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
|
|||
data.local2aux = &local2aux;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
|
||||
settings.use_threading = (calc->numVerts > 10000);
|
||||
settings.userdata_chunk = &hit;
|
||||
settings.userdata_chunk_size = sizeof(hit);
|
||||
BLI_task_parallel_range(
|
||||
|
@ -1363,7 +1363,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
|
|||
data.tree = calc->tree;
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
|
||||
settings.use_threading = (calc->numVerts > 10000);
|
||||
settings.userdata_chunk = &nearest;
|
||||
settings.userdata_chunk_size = sizeof(nearest);
|
||||
BLI_task_parallel_range(
|
||||
|
|
|
@ -1269,15 +1269,21 @@ int BKE_unit_base_of_type_get(int system, int type)
|
|||
|
||||
const char *BKE_unit_name_get(const void *usys_pt, int index)
|
||||
{
|
||||
return ((bUnitCollection *)usys_pt)->units[index].name;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return usys->units[index].name;
|
||||
}
|
||||
const char *BKE_unit_display_name_get(const void *usys_pt, int index)
|
||||
{
|
||||
return ((bUnitCollection *)usys_pt)->units[index].name_display;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return usys->units[index].name_display;
|
||||
}
|
||||
const char *BKE_unit_identifier_get(const void *usys_pt, int index)
|
||||
{
|
||||
const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
const bUnitDef *unit = &usys->units[index];
|
||||
if (unit->identifier == NULL) {
|
||||
BLI_assert_msg(0, "identifier for this unit is not specified yet");
|
||||
}
|
||||
|
@ -1286,10 +1292,14 @@ const char *BKE_unit_identifier_get(const void *usys_pt, int index)
|
|||
|
||||
double BKE_unit_scalar_get(const void *usys_pt, int index)
|
||||
{
|
||||
return ((bUnitCollection *)usys_pt)->units[index].scalar;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return usys->units[index].scalar;
|
||||
}
|
||||
|
||||
bool BKE_unit_is_suppressed(const void *usys_pt, int index)
|
||||
{
|
||||
return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
|
||||
const bUnitCollection *usys = usys_pt;
|
||||
BLI_assert((uint)index < (uint)usys->length);
|
||||
return (usys->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
|
||||
}
|
||||
|
|
|
@ -810,7 +810,7 @@ static bool vfont_to_curve(Object *ob,
|
|||
VChar *che;
|
||||
struct CharTrans *chartransdata = NULL, *ct;
|
||||
struct TempLineInfo *lineinfo;
|
||||
float *f, xof, yof, xtrax, linedist;
|
||||
float xof, yof, xtrax, linedist;
|
||||
float twidth = 0, maxlen = 0;
|
||||
int i, slen, j;
|
||||
int curbox;
|
||||
|
@ -820,6 +820,8 @@ static bool vfont_to_curve(Object *ob,
|
|||
char32_t ascii;
|
||||
bool ok = false;
|
||||
const float font_size = cu->fsize * iter_data->scale_to_fit;
|
||||
/* Shift down vertically to be 25% below & 75% above baseline (before font scale is applied). */
|
||||
const float font_select_y_offset = 0.25;
|
||||
const bool word_wrap = iter_data->word_wrap;
|
||||
const float xof_scale = safe_divide(cu->xof, font_size);
|
||||
const float yof_scale = safe_divide(cu->yof, font_size);
|
||||
|
@ -1122,7 +1124,7 @@ static bool vfont_to_curve(Object *ob,
|
|||
|
||||
if (selboxes && (i >= selstart) && (i <= selend)) {
|
||||
sb = &selboxes[i - selstart];
|
||||
sb->y = yof * font_size - linedist * font_size * 0.1f;
|
||||
sb->y = (yof - font_select_y_offset) * font_size - linedist * font_size * 0.1f;
|
||||
sb->h = linedist * font_size;
|
||||
sb->w = xof * font_size;
|
||||
}
|
||||
|
@ -1454,8 +1456,15 @@ static bool vfont_to_curve(Object *ob,
|
|||
ct = chartransdata;
|
||||
for (i = 0; i <= selend; i++, ct++) {
|
||||
if (i >= selstart) {
|
||||
selboxes[i - selstart].x = ct->xof * font_size;
|
||||
selboxes[i - selstart].y = (ct->yof - 0.25f) * font_size;
|
||||
EditFontSelBox *sb = &selboxes[i - selstart];
|
||||
sb->x = ct->xof;
|
||||
sb->y = ct->yof;
|
||||
if (ct->rot != 0.0f) {
|
||||
sb->x -= sinf(ct->rot) * font_select_y_offset;
|
||||
sb->y -= cosf(ct->rot) * font_select_y_offset;
|
||||
}
|
||||
sb->x *= font_size;
|
||||
sb->y *= font_size;
|
||||
selboxes[i - selstart].h = font_size;
|
||||
}
|
||||
}
|
||||
|
@ -1536,25 +1545,58 @@ static bool vfont_to_curve(Object *ob,
|
|||
|
||||
/* Cursor first. */
|
||||
if (ef) {
|
||||
float si, co;
|
||||
|
||||
ct = &chartransdata[ef->pos];
|
||||
si = sinf(ct->rot);
|
||||
co = cosf(ct->rot);
|
||||
const float cursor_width = 0.04f;
|
||||
const float cursor_half = 0.02f;
|
||||
const float xoffset = ct->xof;
|
||||
const float yoffset = ct->yof;
|
||||
|
||||
f = ef->textcurs[0];
|
||||
/* By default the cursor is exactly between the characters
|
||||
* and matches the rotation of the character to the right. */
|
||||
float cursor_left = 0.0f - cursor_half;
|
||||
float rotation = ct->rot;
|
||||
|
||||
f[0] = font_size * (-0.02f * co + ct->xof);
|
||||
f[1] = font_size * (0.1f * si - (0.25f * co) + ct->yof);
|
||||
if (ef->selboxes) {
|
||||
if (ef->selend >= ef->selstart) {
|
||||
/* Cursor at right edge of a text selection. Match rotation to the character at the
|
||||
* end of selection. Cursor is further right to show the selected characters better. */
|
||||
rotation = chartransdata[max_ii(0, ef->selend - 1)].rot;
|
||||
cursor_left = 0.0f;
|
||||
}
|
||||
else {
|
||||
/* Cursor at the left edge of a text selection. Cursor
|
||||
* is further left to show the selected characters better. */
|
||||
cursor_left = 0.0f - cursor_width;
|
||||
}
|
||||
}
|
||||
else if ((ef->pos == ef->len) && (ef->len > 0)) {
|
||||
/* Nothing selected, but at the end of the string. Match rotation to previous character. */
|
||||
rotation = chartransdata[ef->len - 1].rot;
|
||||
}
|
||||
|
||||
f[2] = font_size * (0.02f * co + ct->xof);
|
||||
f[3] = font_size * (-0.1f * si - (0.25f * co) + ct->yof);
|
||||
/* We need the rotation to be around the bottom-left corner. So we make
|
||||
* that the zero point before rotation, rotate, then apply offsets afterward. */
|
||||
|
||||
f[4] = font_size * (0.02f * co + 0.8f * si + ct->xof);
|
||||
f[5] = font_size * (-0.1f * si + 0.75f * co + ct->yof);
|
||||
/* Bottom left. */
|
||||
ef->textcurs[0][0] = cursor_left;
|
||||
ef->textcurs[0][1] = 0.0f - font_select_y_offset;
|
||||
/* Bottom right. */
|
||||
ef->textcurs[1][0] = cursor_left + cursor_width;
|
||||
ef->textcurs[1][1] = 0.0f - font_select_y_offset;
|
||||
/* Top left. */
|
||||
ef->textcurs[3][0] = cursor_left;
|
||||
ef->textcurs[3][1] = 1.0f - font_select_y_offset;
|
||||
/* Top right. */
|
||||
ef->textcurs[2][0] = cursor_left + cursor_width;
|
||||
ef->textcurs[2][1] = 1.0f - font_select_y_offset;
|
||||
|
||||
f[6] = font_size * (-0.02f * co + 0.8f * si + ct->xof);
|
||||
f[7] = font_size * (0.1f * si + 0.75f * co + ct->yof);
|
||||
for (int vert = 0; vert < 4; vert++) {
|
||||
float temp_fl[2];
|
||||
/* Rotate around the cursor's bottom-left corner. */
|
||||
rotate_v2_v2fl(temp_fl, &ef->textcurs[vert][0], -rotation);
|
||||
ef->textcurs[vert][0] = font_size * (xoffset + temp_fl[0]);
|
||||
ef->textcurs[vert][1] = font_size * (yoffset + temp_fl[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == FO_SELCHANGE) {
|
||||
|
|
|
@ -65,6 +65,11 @@ class GSpan {
|
|||
return size_;
|
||||
}
|
||||
|
||||
int64_t size_in_bytes() const
|
||||
{
|
||||
return type_->size() * size_;
|
||||
}
|
||||
|
||||
const void *data() const
|
||||
{
|
||||
return data_;
|
||||
|
@ -186,6 +191,11 @@ class GMutableSpan {
|
|||
return size_;
|
||||
}
|
||||
|
||||
int64_t size_in_bytes() const
|
||||
{
|
||||
return type_->size() * size_;
|
||||
}
|
||||
|
||||
void *data() const
|
||||
{
|
||||
return data_;
|
||||
|
|
|
@ -37,32 +37,91 @@ namespace blender {
|
|||
*/
|
||||
class ImplicitSharingInfo : NonCopyable, NonMovable {
|
||||
private:
|
||||
mutable std::atomic<int> users_;
|
||||
/**
|
||||
* Number of users that want to own the shared data. This can be in multiple states:
|
||||
* - 0: The data is expired and likely freed. It must not be accessed anymore. The
|
||||
* #ImplicitSharingInfo may still be alive when there are weak users.
|
||||
* - 1: The data is mutable by the single owner.
|
||||
* - >1: The data is shared and therefore immutable.
|
||||
*/
|
||||
mutable std::atomic<int> strong_users_ = 1;
|
||||
/**
|
||||
* Number of users that only keep a reference to the `ImplicitSharingInfo` but don't need to own
|
||||
* the shared data. One additional weak user is added as long as there is at least one strong
|
||||
* user. Together with the `version_` below this adds an efficient way to detect if data has been
|
||||
* changed.
|
||||
*/
|
||||
mutable std::atomic<int> weak_users_ = 1;
|
||||
/**
|
||||
* The data referenced by an #ImplicitSharingInfo can change over time. This version is
|
||||
* incremented whenever the referenced data is about to be changed. This allows checking if the
|
||||
* data has been changed between points in time.
|
||||
*/
|
||||
mutable std::atomic<int64_t> version_ = 0;
|
||||
|
||||
public:
|
||||
ImplicitSharingInfo(const int initial_users) : users_(initial_users) {}
|
||||
|
||||
virtual ~ImplicitSharingInfo()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
BLI_assert(strong_users_ == 0);
|
||||
BLI_assert(weak_users_ == 0);
|
||||
}
|
||||
|
||||
/** True if there are other const references to the resource, meaning it cannot be modified. */
|
||||
bool is_shared() const
|
||||
{
|
||||
return users_.load(std::memory_order_relaxed) >= 2;
|
||||
}
|
||||
|
||||
/** Whether the resource can be modified without a copy because there is only one owner. */
|
||||
/** Whether the resource can be modified inplace because there is only one owner. */
|
||||
bool is_mutable() const
|
||||
{
|
||||
return !this->is_shared();
|
||||
return strong_users_.load(std::memory_order_relaxed) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Weak users don't protect the referenced data from being freed. If the data is freed while
|
||||
* there is still a weak referenced, this returns true.
|
||||
*/
|
||||
bool is_expired() const
|
||||
{
|
||||
return strong_users_.load(std::memory_order_acquire) == 0;
|
||||
}
|
||||
|
||||
/** Call when a the data has a new additional owner. */
|
||||
void add_user() const
|
||||
{
|
||||
users_.fetch_add(1, std::memory_order_relaxed);
|
||||
BLI_assert(!this->is_expired());
|
||||
strong_users_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding a weak owner prevents the #ImplicitSharingInfo from being freed but not the referenced
|
||||
* data.
|
||||
*
|
||||
* \note Unlike std::shared_ptr a weak user cannot be turned into a strong user. This is
|
||||
* because some code might change the referenced data assuming that there is only one strong user
|
||||
* while a new strong user is added by another thread.
|
||||
*/
|
||||
void add_weak_user() const
|
||||
{
|
||||
weak_users_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this when making sure that the referenced data is mutable, which also implies that it is
|
||||
* about to be modified. This allows other code to detect whether data has not been changed very
|
||||
* efficiently.
|
||||
*/
|
||||
void tag_ensured_mutable() const
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
/* This might not need an atomic increment when the #version method below is only called when
|
||||
* the code calling it is a strong user of this sharing info. Better be safe and use an atomic
|
||||
* for now. */
|
||||
version_.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a version number that is increased when the data is modified. It can be used to detect if
|
||||
* data has been changed.
|
||||
*/
|
||||
int64_t version() const
|
||||
{
|
||||
return version_.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,17 +130,51 @@ class ImplicitSharingInfo : NonCopyable, NonMovable {
|
|||
*/
|
||||
void remove_user_and_delete_if_last() const
|
||||
{
|
||||
const int old_user_count = users_.fetch_sub(1, std::memory_order_acq_rel);
|
||||
const int old_user_count = strong_users_.fetch_sub(1, std::memory_order_acq_rel);
|
||||
BLI_assert(old_user_count >= 1);
|
||||
const bool was_last_user = old_user_count == 1;
|
||||
if (was_last_user) {
|
||||
const int old_weak_user_count = weak_users_.load(std::memory_order_acquire);
|
||||
BLI_assert(old_weak_user_count >= 1);
|
||||
if (old_weak_user_count == 1) {
|
||||
/* If the weak user count is 1 it means that there is no actual weak user. The 1 just
|
||||
* indicates that there was still at least one strong user. */
|
||||
weak_users_ = 0;
|
||||
const_cast<ImplicitSharingInfo *>(this)->delete_self_with_data();
|
||||
}
|
||||
else {
|
||||
/* There is still at least one actual weak user, so don't free the sharing info yet. The
|
||||
* data can be freed though. */
|
||||
const_cast<ImplicitSharingInfo *>(this)->delete_data_only();
|
||||
/* Also remove the "fake" weak user that indicated that there was at least one strong
|
||||
* user.*/
|
||||
this->remove_weak_user_and_delete_if_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This might just decrement the weak user count or might delete the data. Should be used in
|
||||
* conjunction with #add_weak_user.
|
||||
*/
|
||||
void remove_weak_user_and_delete_if_last() const
|
||||
{
|
||||
const int old_weak_user_count = weak_users_.fetch_sub(1, std::memory_order_acq_rel);
|
||||
BLI_assert(old_weak_user_count >= 1);
|
||||
const bool was_last_weak_user = old_weak_user_count == 1;
|
||||
if (was_last_weak_user) {
|
||||
/* It's possible that the data has been freed before already, but now it is definitely freed
|
||||
* together with the sharing info. */
|
||||
const_cast<ImplicitSharingInfo *>(this)->delete_self_with_data();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/** Has to free the #ImplicitSharingInfo and the referenced data. */
|
||||
/** Has to free the #ImplicitSharingInfo and the referenced data. The data might have been freed
|
||||
* before by #delete_data_only already. This case should be handled here. */
|
||||
virtual void delete_self_with_data() = 0;
|
||||
/** Can free the referenced data but the #ImplicitSharingInfo still has to be kept alive. */
|
||||
virtual void delete_data_only() {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -89,8 +182,6 @@ class ImplicitSharingInfo : NonCopyable, NonMovable {
|
|||
* class can be used with #ImplicitSharingPtr.
|
||||
*/
|
||||
class ImplicitSharingMixin : public ImplicitSharingInfo {
|
||||
public:
|
||||
ImplicitSharingMixin() : ImplicitSharingInfo(1) {}
|
||||
|
||||
private:
|
||||
void delete_self_with_data() override
|
||||
|
|
|
@ -311,22 +311,41 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
|
|||
*/
|
||||
int BLI_path_sequence_decode(const char *string,
|
||||
char *head,
|
||||
size_t head_maxncpy,
|
||||
char *tail,
|
||||
size_t tail_maxncpy,
|
||||
unsigned short *r_digits_len);
|
||||
/**
|
||||
* Returns in area pointed to by string a string of the form `<head><pic><tail>`,
|
||||
* where pic is formatted as `numlen` digits with leading zeroes.
|
||||
*/
|
||||
void BLI_path_sequence_encode(
|
||||
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
|
||||
void BLI_path_sequence_encode(char *string,
|
||||
size_t string_maxncpy,
|
||||
const char *head,
|
||||
const char *tail,
|
||||
unsigned short numlen,
|
||||
int pic);
|
||||
|
||||
/**
|
||||
* Remove redundant characters from \a path and optionally make absolute.
|
||||
* Remove redundant characters from \a path.
|
||||
*
|
||||
* \param path: Can be any input, and this function converts it to a regular full path.
|
||||
* Also removes garbage from directory paths, like `/../` or double slashes etc.
|
||||
* The following operations are performed:
|
||||
* - Redundant path components such as `//`, `/./` & `./` (prefix) are stripped.
|
||||
* (with the exception of `//` prefix used for blend-file relative paths).
|
||||
* - `..` are resolved so `<parent>/../<child>/` resolves to `<child>/`.
|
||||
* Note that the resulting path may begin with `..` if it's relative.
|
||||
*
|
||||
* \note \a path isn't protected for max string names.
|
||||
* Details:
|
||||
* - The slash direction is expected to be native (see #SEP).
|
||||
* When calculating a canonical paths you may need to run #BLI_path_slash_native first.
|
||||
* #BLI_path_cmp_normalized can be used for canonical path comparison.
|
||||
* - Trailing slashes are left intact (unlike Python which strips them).
|
||||
* - Handling paths beginning with `..` depends on them being absolute or relative.
|
||||
* For absolute paths they are removed (e.g. `/../path` becomes `/path`).
|
||||
* For relative paths they are kept as it's valid to reference paths above a relative location
|
||||
* such as `//../parent` or `../parent`.
|
||||
*
|
||||
* \param path: The path to a file or directory which can be absolute or relative.
|
||||
*/
|
||||
void BLI_path_normalize(char *path) ATTR_NONNULL(1);
|
||||
/**
|
||||
|
|
|
@ -87,12 +87,7 @@ template<typename T, eValueType V> class PrimitiveValue;
|
|||
using IntValue = PrimitiveValue<int64_t, eValueType::Int>;
|
||||
using DoubleValue = PrimitiveValue<double, eValueType::Double>;
|
||||
using BooleanValue = PrimitiveValue<bool, eValueType::Boolean>;
|
||||
|
||||
template<typename Container, eValueType V, typename ContainerItem = typename Container::value_type>
|
||||
class ContainerValue;
|
||||
/* ArrayValue stores its items as shared pointer as it shares data with a lookup table that can
|
||||
* be created by calling `create_lookup`. */
|
||||
using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Array>;
|
||||
class ArrayValue;
|
||||
|
||||
/**
|
||||
* Class containing a (de)serializable value.
|
||||
|
@ -214,7 +209,7 @@ template<
|
|||
eValueType V,
|
||||
|
||||
/** Type of the data inside the container. */
|
||||
typename ContainerItem>
|
||||
typename ContainerItem = typename Container::value_type>
|
||||
class ContainerValue : public Value {
|
||||
public:
|
||||
using Items = Container;
|
||||
|
@ -237,6 +232,18 @@ class ContainerValue : public Value {
|
|||
}
|
||||
};
|
||||
|
||||
class ArrayValue : public ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Array> {
|
||||
public:
|
||||
void append(std::shared_ptr<Value> value);
|
||||
void append_bool(bool value);
|
||||
void append_int(int value);
|
||||
void append_double(double value);
|
||||
void append_str(std::string value);
|
||||
void append_null();
|
||||
std::shared_ptr<DictionaryValue> append_dict();
|
||||
std::shared_ptr<ArrayValue> append_array();
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal storage type for DictionaryValue.
|
||||
*
|
||||
|
@ -260,14 +267,21 @@ class DictionaryValue
|
|||
*
|
||||
* The lookup is owned by the caller.
|
||||
*/
|
||||
const Lookup create_lookup() const
|
||||
{
|
||||
Lookup result;
|
||||
for (const Item &item : elements()) {
|
||||
result.add_as(item.first, item.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const Lookup create_lookup() const;
|
||||
|
||||
const std::shared_ptr<Value> *lookup(const StringRef key) const;
|
||||
std::optional<StringRefNull> lookup_str(const StringRef key) const;
|
||||
std::optional<int64_t> lookup_int(const StringRef key) const;
|
||||
std::optional<double> lookup_double(const StringRef key) const;
|
||||
const DictionaryValue *lookup_dict(const StringRef key) const;
|
||||
const ArrayValue *lookup_array(const StringRef key) const;
|
||||
|
||||
void append(std::string key, std::shared_ptr<Value> value);
|
||||
void append_int(std::string key, int64_t value);
|
||||
void append_double(std::string key, double value);
|
||||
void append_str(std::string key, std::string value);
|
||||
std::shared_ptr<DictionaryValue> append_dict(std::string key);
|
||||
std::shared_ptr<ArrayValue> append_array(std::string key);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -300,4 +314,7 @@ class JsonFormatter : public Formatter {
|
|||
std::unique_ptr<Value> deserialize(std::istream &is) override;
|
||||
};
|
||||
|
||||
void write_json_file(StringRef path, const Value &value);
|
||||
std::shared_ptr<Value> read_json_file(StringRef path);
|
||||
|
||||
} // namespace blender::io::serialize
|
||||
|
|
|
@ -551,9 +551,10 @@ template<typename T> class MutableSpan {
|
|||
* Replace a subset of all elements with the given value. This invokes undefined behavior when
|
||||
* one of the indices is out of bounds.
|
||||
*/
|
||||
constexpr void fill_indices(Span<int64_t> indices, const T &value)
|
||||
template<typename IndexT> constexpr void fill_indices(Span<IndexT> indices, const T &value)
|
||||
{
|
||||
for (int64_t i : indices) {
|
||||
static_assert(std::is_integral_v<IndexT>);
|
||||
for (IndexT i : indices) {
|
||||
BLI_assert(i < size_);
|
||||
data_[i] = value;
|
||||
}
|
||||
|
|
|
@ -106,8 +106,8 @@ typedef struct BLI_mempool_chunk {
|
|||
* The mempool, stores and tracks memory \a chunks and elements within those chunks \a free.
|
||||
*/
|
||||
struct BLI_mempool {
|
||||
/* Serialize access to mempools when debugging wih ASAN. */
|
||||
#ifdef WITH_ASAN
|
||||
/** Serialize access to memory-pools when debugging with ASAN. */
|
||||
ThreadMutex mutex;
|
||||
#endif
|
||||
/** Single linked list of allocated chunks. */
|
||||
|
|
|
@ -13,7 +13,7 @@ class MEMFreeImplicitSharing : public ImplicitSharingInfo {
|
|||
public:
|
||||
void *data;
|
||||
|
||||
MEMFreeImplicitSharing(void *data) : ImplicitSharingInfo(1), data(data)
|
||||
MEMFreeImplicitSharing(void *data) : data(data)
|
||||
{
|
||||
BLI_assert(data != nullptr);
|
||||
}
|
||||
|
@ -44,7 +44,10 @@ void *make_trivial_data_mutable_impl(void *old_data,
|
|||
}
|
||||
|
||||
BLI_assert(*sharing_info != nullptr);
|
||||
if ((*sharing_info)->is_shared()) {
|
||||
if ((*sharing_info)->is_mutable()) {
|
||||
(*sharing_info)->tag_ensured_mutable();
|
||||
}
|
||||
else {
|
||||
void *new_data = MEM_mallocN_aligned(size, alignment, __func__);
|
||||
memcpy(new_data, old_data, size);
|
||||
(*sharing_info)->remove_user_and_delete_if_last();
|
||||
|
@ -85,6 +88,7 @@ void *resize_trivial_array_impl(void *old_data,
|
|||
* could theoretically give better performance if the data can be reused in place. */
|
||||
void *new_data = static_cast<int *>(MEM_reallocN(old_data, new_size));
|
||||
info->data = new_data;
|
||||
(*sharing_info)->tag_ensured_mutable();
|
||||
return new_data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,22 @@ static bool BLI_path_is_abs_win32(const char *name);
|
|||
|
||||
// #define DEBUG_STRSIZE
|
||||
|
||||
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_digits_len)
|
||||
int BLI_path_sequence_decode(const char *string,
|
||||
char *head,
|
||||
const size_t head_maxncpy,
|
||||
char *tail,
|
||||
const size_t tail_maxncpy,
|
||||
ushort *r_digits_len)
|
||||
{
|
||||
#ifdef DEBUG_STRSIZE
|
||||
if (head) {
|
||||
memset(head, 0xff, sizeof(*head) * head_maxncpy);
|
||||
}
|
||||
if (tail) {
|
||||
memset(tail, 0xff, sizeof(*tail) * tail_maxncpy);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint nums = 0, nume = 0;
|
||||
int i;
|
||||
bool found_digit = false;
|
||||
|
@ -82,8 +96,7 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
|
|||
strcpy(tail, &string[nume + 1]);
|
||||
}
|
||||
if (head) {
|
||||
strcpy(head, string);
|
||||
head[nums] = 0;
|
||||
BLI_strncpy(head, string, MIN2(head_maxncpy, nums + 1));
|
||||
}
|
||||
if (r_digits_len) {
|
||||
*r_digits_len = nume - nums + 1;
|
||||
|
@ -93,7 +106,7 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
|
|||
}
|
||||
|
||||
if (tail) {
|
||||
strcpy(tail, string + name_end);
|
||||
BLI_strncpy(tail, string + name_end, tail_maxncpy);
|
||||
}
|
||||
if (head) {
|
||||
/* Name_end points to last character of head,
|
||||
|
@ -106,22 +119,28 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
|
|||
return 0;
|
||||
}
|
||||
|
||||
void BLI_path_sequence_encode(
|
||||
char *string, const char *head, const char *tail, ushort numlen, int pic)
|
||||
void BLI_path_sequence_encode(char *string,
|
||||
const size_t string_maxncpy,
|
||||
const char *head,
|
||||
const char *tail,
|
||||
ushort numlen,
|
||||
int pic)
|
||||
{
|
||||
BLI_sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
|
||||
#ifdef DEBUG_STRSIZE
|
||||
memset(string, 0xff, sizeof(*string) * string_maxncpy);
|
||||
#endif
|
||||
BLI_snprintf(string, string_maxncpy, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
|
||||
}
|
||||
|
||||
void BLI_path_normalize(char *path)
|
||||
{
|
||||
const char *path_orig = path;
|
||||
int path_len;
|
||||
|
||||
ptrdiff_t a;
|
||||
char *start, *eind;
|
||||
|
||||
path_len = strlen(path);
|
||||
int path_len = strlen(path);
|
||||
|
||||
/*
|
||||
* Skip absolute prefix.
|
||||
* ---------------------
|
||||
*/
|
||||
if (path[0] == '/' && path[1] == '/') {
|
||||
path = path + 2; /* Leave the initial `//` untouched. */
|
||||
path_len -= 2;
|
||||
|
@ -157,10 +176,14 @@ void BLI_path_normalize(char *path)
|
|||
}
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* Works on WIN32 as well, because the drive component is skipped. */
|
||||
const bool is_relative = path[0] && (path[0] != SEP);
|
||||
|
||||
/*
|
||||
* Strip redundant path components.
|
||||
* --------------------------------
|
||||
*/
|
||||
|
||||
/* NOTE(@ideasman42):
|
||||
* `memmove(start, eind, strlen(eind) + 1);`
|
||||
* is the same as
|
||||
|
@ -189,7 +212,6 @@ void BLI_path_normalize(char *path)
|
|||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (i > 0);
|
||||
|
||||
if (i < i_end) {
|
||||
|
@ -200,8 +222,7 @@ void BLI_path_normalize(char *path)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove redundant `./` prefix, while it could be kept, it confuses the loop below. */
|
||||
/* Remove redundant `./` prefix as it's redundant & complicates collapsing directories. */
|
||||
if (is_relative) {
|
||||
if ((path_len > 2) && (path[0] == '.') && (path[1] == SEP)) {
|
||||
memmove(path, path + 2, (path_len - 2) + 1);
|
||||
|
@ -209,69 +230,127 @@ void BLI_path_normalize(char *path)
|
|||
}
|
||||
}
|
||||
|
||||
const ptrdiff_t a_start = is_relative ? 0 : 1;
|
||||
start = path;
|
||||
while ((start = strstr(start, SEP_STR ".."))) {
|
||||
if (!ELEM(start[3], SEP, '\0')) {
|
||||
start += 3;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Collapse Parent Directories.
|
||||
* ----------------------------
|
||||
*
|
||||
* Example: `<parent>/<child>/../` -> `<parent>/`
|
||||
*
|
||||
* Notes:
|
||||
* - Leading `../` are skipped as they cannot be collapsed (see `start_base`).
|
||||
* - Multiple parent directories are handled at once to reduce number of `memmove` calls.
|
||||
*/
|
||||
|
||||
a = (start - path) - 1;
|
||||
if (a >= a_start) {
|
||||
/* `<prefix>/<parent>/../<postfix> => <prefix>/<postfix>`. */
|
||||
eind = start + (4 - 1) /* `strlen("/../") - 1` */; /* Strip "/.." and keep the char after. */
|
||||
while (a > 0 && path[a] != SEP) { /* Find start of `<parent>`. */
|
||||
a--;
|
||||
}
|
||||
#define IS_PARENT_DIR(p) ((p)[0] == '.' && (p)[1] == '.' && ELEM((p)[2], SEP, '\0'))
|
||||
|
||||
if (is_relative && (a == 0) && *eind) {
|
||||
/* When the path does not start with a slash, don't copy the first `/` to the destination
|
||||
* as it will make a relative path into an absolute path. */
|
||||
eind += 1;
|
||||
}
|
||||
const size_t eind_len = path_len - (eind - path);
|
||||
BLI_assert(eind_len == strlen(eind));
|
||||
|
||||
/* Only remove the parent if it's not also a `..`. */
|
||||
if (is_relative && STRPREFIX(path + ((path[a] == SEP) ? a + 1 : a), ".." SEP_STR)) {
|
||||
start += 3 /* `strlen("/..")` */;
|
||||
}
|
||||
else {
|
||||
start = path + a;
|
||||
BLI_assert(start < eind);
|
||||
memmove(start, eind, eind_len + 1);
|
||||
path_len -= (eind - start);
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
BLI_assert(!is_relative || (path[0] != SEP));
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Support for odd paths: eg `/../home/me` --> `/home/me`
|
||||
* this is a valid path in blender but we can't handle this the usual way below
|
||||
* simply strip this prefix then evaluate the path as usual.
|
||||
* Python's `os.path.normpath()` does this. */
|
||||
|
||||
/* NOTE: previous version of following call used an offset of 3 instead of 4,
|
||||
* which meant that the `/../home/me` example actually became `home/me`.
|
||||
* Using offset of 3 gives behavior consistent with the aforementioned
|
||||
* Python routine. */
|
||||
eind = start + 3;
|
||||
const size_t eind_len = path_len - (eind - path);
|
||||
memmove(start, eind, eind_len + 1);
|
||||
path_len -= 3;
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
BLI_assert(!is_relative || (path[0] != SEP));
|
||||
}
|
||||
/* First non prefix path component. */
|
||||
char *path_first_non_slash_part = path;
|
||||
while (*path_first_non_slash_part && *path_first_non_slash_part == SEP) {
|
||||
path_first_non_slash_part++;
|
||||
}
|
||||
|
||||
if (is_relative && path_len == 0 && (path == path_orig)) {
|
||||
path[0] = '.';
|
||||
path[1] = '\0';
|
||||
path_len += 1;
|
||||
/* Maintain a pointer to the end of leading `..` component.
|
||||
* Skip leading parent directories because logically they cannot be collapsed. */
|
||||
char *start_base = path_first_non_slash_part;
|
||||
while (IS_PARENT_DIR(start_base)) {
|
||||
start_base += 3;
|
||||
}
|
||||
|
||||
/* It's possible the entire path is made of up `../`,
|
||||
* in this case there is nothing to do. */
|
||||
if (start_base < path + path_len) {
|
||||
/* Step over directories, always starting out on the character after the slash. */
|
||||
char *start = start_base;
|
||||
char *start_temp;
|
||||
while (((start_temp = strstr(start, SEP_STR ".." SEP_STR)) ||
|
||||
/* Check if the string ends with `/..` & assign when found, else NULL. */
|
||||
(start_temp = ((start <= &path[path_len - 3]) &&
|
||||
STREQ(&path[path_len - 3], SEP_STR "..")) ?
|
||||
&path[path_len - 3] :
|
||||
NULL))) {
|
||||
start = start_temp + 1; /* Skip the `/`. */
|
||||
BLI_assert(start_base != start);
|
||||
|
||||
/* Step `end_all` forwards (over all `..`). */
|
||||
char *end_all = start;
|
||||
do {
|
||||
BLI_assert(IS_PARENT_DIR(end_all));
|
||||
end_all += 3;
|
||||
BLI_assert(end_all <= path + path_len + 1);
|
||||
} while (IS_PARENT_DIR(end_all));
|
||||
|
||||
/* Step `start` backwards (until `end` meets `end_all` or `start` meets `start_base`). */
|
||||
char *end = start;
|
||||
do {
|
||||
BLI_assert(start_base < start);
|
||||
BLI_assert(*(start - 1) == SEP);
|
||||
/* Step `start` backwards one. */
|
||||
do {
|
||||
start--;
|
||||
} while (start_base < start && *(start - 1) != SEP);
|
||||
BLI_assert(*start != SEP); /* Ensure the loop ran at least once. */
|
||||
BLI_assert(!IS_PARENT_DIR(start)); /* Clamping by `start_base` prevents this. */
|
||||
end += 3;
|
||||
} while ((start != start_base) && (end < end_all));
|
||||
|
||||
if (end > path + path_len) {
|
||||
BLI_assert(*(end - 1) == '\0');
|
||||
end--;
|
||||
end_all--;
|
||||
}
|
||||
BLI_assert(start < end && start >= start_base);
|
||||
const size_t start_len = path_len - (end - path);
|
||||
memmove(start, end, start_len + 1);
|
||||
path_len -= end - start;
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
/* Other `..` directories may have been moved to the front, step `start_base` past them. */
|
||||
if (UNLIKELY(start == start_base && (end != end_all))) {
|
||||
start_base += (end_all - end);
|
||||
start = (start_base < path + path_len) ? start_base : start_base - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
/* Characters before the `start_base` must *only* be `../../../` (multiples of 3). */
|
||||
BLI_assert((start_base - path_first_non_slash_part) % 3 == 0);
|
||||
/* All `..` ahead of `start_base` were collapsed (including trailing `/..`). */
|
||||
BLI_assert(!(start_base < path + path_len) ||
|
||||
(!strstr(start_base, SEP_STR ".." SEP_STR) &&
|
||||
!(path_len >= 3 && STREQ(&path[path_len - 3], SEP_STR ".."))));
|
||||
|
||||
/*
|
||||
* Final Prefix Cleanup.
|
||||
* ---------------------
|
||||
*/
|
||||
if (is_relative) {
|
||||
if (path_len == 0 && (path == path_orig)) {
|
||||
path[0] = '.';
|
||||
path[1] = '\0';
|
||||
path_len = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Support for odd paths: eg `/../home/me` --> `/home/me`
|
||||
* this is a valid path in blender but we can't handle this the usual way below
|
||||
* simply strip this prefix then evaluate the path as usual.
|
||||
* Python's `os.path.normpath()` does this. */
|
||||
if (start_base != path_first_non_slash_part) {
|
||||
char *start = start_base > path + path_len ? start_base - 1 : start_base;
|
||||
/* As long as `start` is set correctly, it should never begin with `../`
|
||||
* as these directories are expected to be skipped. */
|
||||
BLI_assert(!IS_PARENT_DIR(start));
|
||||
const size_t start_len = path_len - (start - path);
|
||||
memmove(path_first_non_slash_part, start, start_len + 1);
|
||||
BLI_assert(strlen(start) == start_len);
|
||||
path_len -= start - path_first_non_slash_part;
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(strlen(path) == path_len);
|
||||
|
||||
#undef IS_PARENT_DIR
|
||||
}
|
||||
|
||||
void BLI_path_normalize_dir(char *dir, size_t dir_maxlen)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_fileops.hh"
|
||||
#include "BLI_serialize.hh"
|
||||
|
||||
#include "json.hpp"
|
||||
|
@ -197,6 +198,149 @@ static std::unique_ptr<Value> convert_from_json(const nlohmann::ordered_json &j)
|
|||
return std::make_unique<NullValue>();
|
||||
}
|
||||
|
||||
void ArrayValue::append(std::shared_ptr<Value> value)
|
||||
{
|
||||
this->elements().append(std::move(value));
|
||||
}
|
||||
|
||||
void ArrayValue::append_bool(const bool value)
|
||||
{
|
||||
this->append(std::make_shared<BooleanValue>(value));
|
||||
}
|
||||
|
||||
void ArrayValue::append_int(const int value)
|
||||
{
|
||||
this->append(std::make_shared<IntValue>(value));
|
||||
}
|
||||
|
||||
void ArrayValue::append_double(const double value)
|
||||
{
|
||||
this->append(std::make_shared<DoubleValue>(value));
|
||||
}
|
||||
|
||||
void ArrayValue::append_str(std::string value)
|
||||
{
|
||||
this->append(std::make_shared<StringValue>(std::move(value)));
|
||||
}
|
||||
|
||||
void ArrayValue::append_null()
|
||||
{
|
||||
this->append(std::make_shared<NullValue>());
|
||||
}
|
||||
|
||||
std::shared_ptr<DictionaryValue> ArrayValue::append_dict()
|
||||
{
|
||||
auto value = std::make_shared<DictionaryValue>();
|
||||
this->append(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
std::shared_ptr<ArrayValue> ArrayValue::append_array()
|
||||
{
|
||||
auto value = std::make_shared<ArrayValue>();
|
||||
this->append(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
const DictionaryValue::Lookup DictionaryValue::create_lookup() const
|
||||
{
|
||||
Lookup result;
|
||||
for (const Item &item : elements()) {
|
||||
result.add_as(item.first, item.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Value> *DictionaryValue::lookup(const StringRef key) const
|
||||
{
|
||||
for (const auto &item : this->elements()) {
|
||||
if (item.first == key) {
|
||||
return &item.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<StringRefNull> DictionaryValue::lookup_str(const StringRef key) const
|
||||
{
|
||||
if (const std::shared_ptr<Value> *value = this->lookup(key)) {
|
||||
if (const StringValue *str_value = (*value)->as_string_value()) {
|
||||
return StringRefNull(str_value->value());
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<int64_t> DictionaryValue::lookup_int(const StringRef key) const
|
||||
{
|
||||
if (const std::shared_ptr<Value> *value = this->lookup(key)) {
|
||||
if (const IntValue *int_value = (*value)->as_int_value()) {
|
||||
return int_value->value();
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<double> DictionaryValue::lookup_double(const StringRef key) const
|
||||
{
|
||||
if (const std::shared_ptr<Value> *value = this->lookup(key)) {
|
||||
if (const DoubleValue *double_value = (*value)->as_double_value()) {
|
||||
return double_value->value();
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const DictionaryValue *DictionaryValue::lookup_dict(const StringRef key) const
|
||||
{
|
||||
if (const std::shared_ptr<Value> *value = this->lookup(key)) {
|
||||
return (*value)->as_dictionary_value();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ArrayValue *DictionaryValue::lookup_array(const StringRef key) const
|
||||
{
|
||||
if (const std::shared_ptr<Value> *value = this->lookup(key)) {
|
||||
return (*value)->as_array_value();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DictionaryValue::append(std::string key, std::shared_ptr<Value> value)
|
||||
{
|
||||
this->elements().append({std::move(key), std::move(value)});
|
||||
}
|
||||
|
||||
void DictionaryValue::append_int(std::string key, const int64_t value)
|
||||
{
|
||||
this->append(std::move(key), std::make_shared<IntValue>(value));
|
||||
}
|
||||
|
||||
void DictionaryValue::append_double(std::string key, const double value)
|
||||
{
|
||||
this->append(std::move(key), std::make_shared<DoubleValue>(value));
|
||||
}
|
||||
|
||||
void DictionaryValue::append_str(std::string key, const std::string value)
|
||||
{
|
||||
this->append(std::move(key), std::make_shared<StringValue>(value));
|
||||
}
|
||||
|
||||
std::shared_ptr<DictionaryValue> DictionaryValue::append_dict(std::string key)
|
||||
{
|
||||
auto value = std::make_shared<DictionaryValue>();
|
||||
this->append(std::move(key), value);
|
||||
return value;
|
||||
}
|
||||
|
||||
std::shared_ptr<ArrayValue> DictionaryValue::append_array(std::string key)
|
||||
{
|
||||
auto value = std::make_shared<ArrayValue>();
|
||||
this->append(std::move(key), value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void JsonFormatter::serialize(std::ostream &os, const Value &value)
|
||||
{
|
||||
nlohmann::ordered_json j;
|
||||
|
@ -216,4 +360,18 @@ std::unique_ptr<Value> JsonFormatter::deserialize(std::istream &is)
|
|||
return convert_from_json(j);
|
||||
}
|
||||
|
||||
void write_json_file(const StringRef path, const Value &value)
|
||||
{
|
||||
JsonFormatter formatter;
|
||||
fstream stream(path, std::ios::out);
|
||||
formatter.serialize(stream, value);
|
||||
}
|
||||
|
||||
std::shared_ptr<Value> read_json_file(const StringRef path)
|
||||
{
|
||||
JsonFormatter formatter;
|
||||
fstream stream(path, std::ios::in);
|
||||
return formatter.deserialize(stream);
|
||||
}
|
||||
|
||||
} // namespace blender::io::serialize
|
||||
|
|
|
@ -28,6 +28,11 @@ class SharedDataContainer {
|
|||
public:
|
||||
SharedDataContainer() : data_(MEM_new<ImplicitlySharedData>(__func__)) {}
|
||||
|
||||
const ImplicitSharingInfo *sharing_info() const
|
||||
{
|
||||
return data_.get();
|
||||
}
|
||||
|
||||
const ImplicitlySharedData *get_for_read() const
|
||||
{
|
||||
return data_.get();
|
||||
|
@ -39,6 +44,7 @@ class SharedDataContainer {
|
|||
return nullptr;
|
||||
}
|
||||
if (data_->is_mutable()) {
|
||||
data_->tag_ensured_mutable();
|
||||
return data_.get();
|
||||
}
|
||||
data_ = data_->copy();
|
||||
|
@ -80,4 +86,29 @@ TEST(implicit_sharing, CopyOnWriteAccess)
|
|||
EXPECT_EQ(d.get_for_write(), data_b1);
|
||||
}
|
||||
|
||||
TEST(implicit_sharing, WeakUser)
|
||||
{
|
||||
SharedDataContainer a;
|
||||
const ImplicitSharingInfo *sharing_info = a.sharing_info();
|
||||
EXPECT_FALSE(sharing_info->is_expired());
|
||||
EXPECT_TRUE(sharing_info->is_mutable());
|
||||
sharing_info->add_weak_user();
|
||||
EXPECT_FALSE(sharing_info->is_expired());
|
||||
EXPECT_TRUE(sharing_info->is_mutable());
|
||||
a = {};
|
||||
EXPECT_TRUE(sharing_info->is_expired());
|
||||
sharing_info->remove_weak_user_and_delete_if_last();
|
||||
}
|
||||
|
||||
TEST(implicit_sharing, Version)
|
||||
{
|
||||
SharedDataContainer a;
|
||||
const ImplicitSharingInfo *sharing_info = a.sharing_info();
|
||||
const int old_version = sharing_info->version();
|
||||
a.get_for_read();
|
||||
EXPECT_EQ(old_version, sharing_info->version());
|
||||
a.get_for_write();
|
||||
EXPECT_LT(old_version, sharing_info->version());
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
||||
|
|
|
@ -84,11 +84,16 @@ TEST(path_util, Normalize_Dot)
|
|||
NORMALIZE("/a/./././b/", "/a/b/");
|
||||
}
|
||||
/* #BLI_path_normalize: complex "/./" -> "/", "//" -> "/", "./path/../" -> "./". */
|
||||
TEST(path_util, Normalize_Complex)
|
||||
TEST(path_util, Normalize_ComplexAbsolute)
|
||||
{
|
||||
NORMALIZE("/a/./b/./c/./.././.././", "/a/");
|
||||
NORMALIZE("/a//.//b//.//c//.//..//.//..//.//", "/a/");
|
||||
}
|
||||
TEST(path_util, Normalize_ComplexRelative)
|
||||
{
|
||||
NORMALIZE("a/b/c/d/e/f/g/../a/../b/../../c/../../../d/../../../..", ".");
|
||||
NORMALIZE("a/b/c/d/e/f/g/../a/../../../../b/../../../c/../../d/..", ".");
|
||||
}
|
||||
/* #BLI_path_normalize: "//" -> "/" */
|
||||
TEST(path_util, Normalize_DoubleSlash)
|
||||
{
|
||||
|
@ -1054,7 +1059,8 @@ TEST(path_util, FrameGet)
|
|||
char head[FILE_MAX]; \
|
||||
char tail[FILE_MAX]; \
|
||||
ushort numdigits = 0; \
|
||||
const int result = BLI_path_sequence_decode(path, head, tail, &numdigits); \
|
||||
const int result = BLI_path_sequence_decode( \
|
||||
path, head, sizeof(head), tail, sizeof(tail), &numdigits); \
|
||||
EXPECT_EQ(result, expect_result); \
|
||||
EXPECT_STREQ(head, expect_head); \
|
||||
EXPECT_STREQ(tail, expect_tail); \
|
||||
|
|
|
@ -78,12 +78,11 @@ TEST(serialize, array_to_json)
|
|||
JsonFormatter json;
|
||||
std::stringstream out;
|
||||
ArrayValue value_array;
|
||||
ArrayValue::Items &array = value_array.elements();
|
||||
array.append_as(new IntValue(42));
|
||||
array.append_as(new StringValue("Hello JSON"));
|
||||
array.append_as(new NullValue);
|
||||
array.append_as(new BooleanValue(false));
|
||||
array.append_as(new BooleanValue(true));
|
||||
value_array.append_int(42);
|
||||
value_array.append_str("Hello JSON");
|
||||
value_array.append_null();
|
||||
value_array.append_bool(false);
|
||||
value_array.append_bool(true);
|
||||
|
||||
json.serialize(out, value_array);
|
||||
EXPECT_EQ(out.str(), "[42,\"Hello JSON\",null,false,true]");
|
||||
|
@ -94,8 +93,7 @@ TEST(serialize, object_to_json)
|
|||
JsonFormatter json;
|
||||
std::stringstream out;
|
||||
DictionaryValue value_object;
|
||||
DictionaryValue::Items &attributes = value_object.elements();
|
||||
attributes.append_as(std::pair(std::string("best_number"), new IntValue(42)));
|
||||
value_object.append_int("best_number", 42);
|
||||
|
||||
json.serialize(out, value_object);
|
||||
EXPECT_EQ(out.str(), "{\"best_number\":42}");
|
||||
|
|
|
@ -225,7 +225,7 @@ TEST(span, FillIndices)
|
|||
{
|
||||
std::array<int, 5> a = {0, 0, 0, 0, 0};
|
||||
MutableSpan<int> a_span(a);
|
||||
a_span.fill_indices({0, 2, 3}, 1);
|
||||
a_span.fill_indices(Span({0, 2, 3}), 1);
|
||||
EXPECT_EQ(a[0], 1);
|
||||
EXPECT_EQ(a[1], 0);
|
||||
EXPECT_EQ(a[2], 1);
|
||||
|
|
|
@ -1047,10 +1047,12 @@ class StringEscape : public testing::Test {
|
|||
void testEscapeWords(const CompareWordsArray &items)
|
||||
{
|
||||
size_t dst_test_len;
|
||||
char dst_test[64];
|
||||
char dst_test[64]; /* Must be big enough for all input. */
|
||||
for (const auto &item : items) {
|
||||
/* Validate the static size is big enough (test the test it's self). */
|
||||
EXPECT_LT((strlen(item[0]) * 2) + 1, sizeof(dst_test));
|
||||
/* Escape the string. */
|
||||
dst_test_len = BLI_str_escape(dst_test, item[0], SIZE_MAX);
|
||||
dst_test_len = BLI_str_escape(dst_test, item[0], sizeof(dst_test));
|
||||
EXPECT_STREQ(dst_test, item[1]);
|
||||
EXPECT_EQ(dst_test_len, strlen(dst_test));
|
||||
/* Escape back. */
|
||||
|
|
|
@ -428,10 +428,9 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
|
|||
if (base->lay & (1 << layer)) {
|
||||
/* Create collections when needed only. */
|
||||
if (collections[layer] == NULL) {
|
||||
char name[MAX_NAME];
|
||||
char name[MAX_ID_NAME - 2];
|
||||
|
||||
BLI_snprintf(
|
||||
name, sizeof(collection_master->id.name), DATA_("Collection %d"), layer + 1);
|
||||
BLI_snprintf(name, sizeof(name), DATA_("Collection %d"), layer + 1);
|
||||
|
||||
Collection *collection = BKE_collection_add(bmain, collection_master, name);
|
||||
collection->id.lib = scene->id.lib;
|
||||
|
|
|
@ -1263,8 +1263,7 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
|
|||
/* Ensure tiled image sources contain a UDIM token. */
|
||||
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
|
||||
if (ima->source == IMA_SRC_TILED) {
|
||||
char *filename = (char *)BLI_path_basename(ima->filepath);
|
||||
BKE_image_ensure_tile_token(filename);
|
||||
BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
#include "BLI_bitmap.h"
|
||||
#include "BLI_linklist_stack.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_stack.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_editmesh.h"
|
||||
|
@ -470,7 +470,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
const int cd_loop_clnors_offset,
|
||||
const bool has_clnors,
|
||||
/* Cache. */
|
||||
BLI_Stack *edge_vectors,
|
||||
blender::Vector<blender::float3, 16> *edge_vectors,
|
||||
/* Iterate. */
|
||||
BMLoop *l_curr,
|
||||
/* Result. */
|
||||
|
@ -534,7 +534,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
normalize_v3(vec_prev);
|
||||
}
|
||||
|
||||
BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, nullptr);
|
||||
BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, {});
|
||||
/* We know there is only one loop in this space,
|
||||
* no need to create a linklist in this case... */
|
||||
BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true);
|
||||
|
@ -586,7 +586,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) :
|
||||
nullptr;
|
||||
|
||||
BLI_assert((edge_vectors == nullptr) || BLI_stack_is_empty(edge_vectors));
|
||||
BLI_assert((edge_vectors == nullptr) || edge_vectors->is_empty());
|
||||
|
||||
lfan_pivot = l_curr;
|
||||
lfan_pivot_index = BM_elem_index_get(lfan_pivot);
|
||||
|
@ -605,7 +605,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
copy_v3_v3(vec_curr, vec_org);
|
||||
|
||||
if (r_lnors_spacearr) {
|
||||
BLI_stack_push(edge_vectors, vec_org);
|
||||
edge_vectors->append(vec_org);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -671,7 +671,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, lfan_pivot, false);
|
||||
if (e_next != e_org) {
|
||||
/* We store here all edges-normalized vectors processed. */
|
||||
BLI_stack_push(edge_vectors, vec_next);
|
||||
edge_vectors->append(vec_next);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,7 +700,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
lnor_len = 1.0f;
|
||||
}
|
||||
|
||||
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors);
|
||||
BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, *edge_vectors);
|
||||
|
||||
if (has_clnors) {
|
||||
if (clnors_invalid) {
|
||||
|
@ -863,19 +863,20 @@ static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
|
|||
* operating on vertices this is needed for multi-threading
|
||||
* so there is a guarantee that each thread has isolated loops.
|
||||
*/
|
||||
static void bm_mesh_loops_calc_normals_for_vert_with_clnors(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3],
|
||||
const short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
const bool do_rebuild,
|
||||
const float split_angle_cos,
|
||||
/* TLS */
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
BLI_Stack *edge_vectors,
|
||||
/* Iterate over. */
|
||||
BMVert *v)
|
||||
static void bm_mesh_loops_calc_normals_for_vert_with_clnors(
|
||||
BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3],
|
||||
const short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
const bool do_rebuild,
|
||||
const float split_angle_cos,
|
||||
/* TLS */
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
blender::Vector<blender::float3, 16> *edge_vectors,
|
||||
/* Iterate over. */
|
||||
BMVert *v)
|
||||
{
|
||||
/* Respecting face order is necessary so the initial starting loop is consistent
|
||||
* with looping over loops of all faces.
|
||||
|
@ -992,7 +993,7 @@ static void bm_mesh_loops_calc_normals_for_vert_without_clnors(
|
|||
const float split_angle_cos,
|
||||
/* TLS */
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
BLI_Stack *edge_vectors,
|
||||
blender::Vector<blender::float3, 16> *edge_vectors,
|
||||
/* Iterate over. */
|
||||
BMVert *v)
|
||||
{
|
||||
|
@ -1078,7 +1079,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
|
|||
|
||||
MLoopNorSpaceArray _lnors_spacearr = {nullptr};
|
||||
|
||||
BLI_Stack *edge_vectors = nullptr;
|
||||
std::unique_ptr<blender::Vector<blender::float3, 16>> edge_vectors = nullptr;
|
||||
|
||||
{
|
||||
char htype = 0;
|
||||
|
@ -1095,7 +1096,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
|
|||
}
|
||||
if (r_lnors_spacearr) {
|
||||
BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
|
||||
edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
|
||||
edge_vectors = std::make_unique<blender::Vector<blender::float3, 16>>();
|
||||
}
|
||||
|
||||
/* Clear all loops' tags (means none are to be skipped for now). */
|
||||
|
@ -1138,7 +1139,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
|
|||
clnors_data,
|
||||
cd_loop_clnors_offset,
|
||||
has_clnors,
|
||||
edge_vectors,
|
||||
edge_vectors.get(),
|
||||
l_curr,
|
||||
r_lnos,
|
||||
r_lnors_spacearr);
|
||||
|
@ -1146,7 +1147,6 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
|
|||
}
|
||||
|
||||
if (r_lnors_spacearr) {
|
||||
BLI_stack_free(edge_vectors);
|
||||
if (r_lnors_spacearr == &_lnors_spacearr) {
|
||||
BKE_lnor_spacearr_free(r_lnors_spacearr);
|
||||
}
|
||||
|
@ -1169,7 +1169,7 @@ typedef struct BMLoopsCalcNormalsWithCoordsData {
|
|||
} BMLoopsCalcNormalsWithCoordsData;
|
||||
|
||||
typedef struct BMLoopsCalcNormalsWithCoords_TLS {
|
||||
BLI_Stack *edge_vectors;
|
||||
blender::Vector<blender::float3, 16> *edge_vectors;
|
||||
|
||||
/** Copied from #BMLoopsCalcNormalsWithCoordsData.r_lnors_spacearr when it's not nullptr. */
|
||||
MLoopNorSpaceArray *lnors_spacearr;
|
||||
|
@ -1182,7 +1182,7 @@ static void bm_mesh_loops_calc_normals_for_vert_init_fn(const void *__restrict u
|
|||
auto *data = static_cast<const BMLoopsCalcNormalsWithCoordsData *>(userdata);
|
||||
auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(chunk);
|
||||
if (data->r_lnors_spacearr) {
|
||||
tls_data->edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
|
||||
tls_data->edge_vectors = MEM_new<blender::Vector<blender::float3, 16>>(__func__);
|
||||
BKE_lnor_spacearr_tls_init(data->r_lnors_spacearr, &tls_data->lnors_spacearr_buf);
|
||||
tls_data->lnors_spacearr = &tls_data->lnors_spacearr_buf;
|
||||
}
|
||||
|
@ -1210,7 +1210,7 @@ static void bm_mesh_loops_calc_normals_for_vert_free_fn(const void *__restrict u
|
|||
auto *tls_data = static_cast<BMLoopsCalcNormalsWithCoords_TLS *>(chunk);
|
||||
|
||||
if (data->r_lnors_spacearr) {
|
||||
BLI_stack_free(tls_data->edge_vectors);
|
||||
MEM_delete(tls_data->edge_vectors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ set(GLSL_SRC
|
|||
shaders/compositor_morphological_step.glsl
|
||||
shaders/compositor_normalize.glsl
|
||||
shaders/compositor_parallel_reduction.glsl
|
||||
shaders/compositor_plane_deform.glsl
|
||||
shaders/compositor_projector_lens_distortion.glsl
|
||||
shaders/compositor_read_pass.glsl
|
||||
shaders/compositor_realize_on_domain.glsl
|
||||
|
@ -227,6 +228,7 @@ set(SRC_SHADER_CREATE_INFOS
|
|||
shaders/infos/compositor_morphological_step_info.hh
|
||||
shaders/infos/compositor_normalize_info.hh
|
||||
shaders/infos/compositor_parallel_reduction_info.hh
|
||||
shaders/infos/compositor_plane_deform_info.hh
|
||||
shaders/infos/compositor_projector_lens_distortion_info.hh
|
||||
shaders/infos/compositor_read_pass_info.hh
|
||||
shaders/infos/compositor_realize_on_domain_info.hh
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_texture.h"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
@ -50,6 +51,9 @@ bool operator==(const CachedTextureKey &a, const CachedTextureKey &b)
|
|||
CachedTexture::CachedTexture(
|
||||
Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale)
|
||||
{
|
||||
ImagePool *image_pool = BKE_image_pool_new();
|
||||
BKE_texture_fetch_images_for_pool(texture, image_pool);
|
||||
|
||||
Array<float4> color_pixels(size.x * size.y);
|
||||
Array<float> value_pixels(size.x * size.y);
|
||||
threading::parallel_for(IndexRange(size.y), 1, [&](const IndexRange sub_y_range) {
|
||||
|
@ -61,7 +65,7 @@ CachedTexture::CachedTexture(
|
|||
/* Note that it is expected that the offset is scaled by the scale. */
|
||||
coordinates = (coordinates + offset) * scale;
|
||||
TexResult texture_result;
|
||||
BKE_texture_get_value(scene, texture, coordinates, &texture_result, true);
|
||||
BKE_texture_get_value_ex(scene, texture, coordinates, &texture_result, image_pool, true);
|
||||
color_pixels[y * size.x + x] = float4(texture_result.trgba);
|
||||
value_pixels[y * size.x + x] = texture_result.talpha ? texture_result.trgba[3] :
|
||||
texture_result.tin;
|
||||
|
@ -69,6 +73,8 @@ CachedTexture::CachedTexture(
|
|||
}
|
||||
});
|
||||
|
||||
BKE_image_pool_free(image_pool);
|
||||
|
||||
color_texture_ = GPU_texture_create_2d("Cached Color Texture",
|
||||
size.x,
|
||||
size.y,
|
||||
|
|
|
@ -71,18 +71,12 @@ static const DTreeContext *find_active_context(const DerivedNodeTree &tree)
|
|||
}
|
||||
|
||||
/* Return the output node which is marked as NODE_DO_OUTPUT. If multiple types of output nodes are
|
||||
* marked, then the preference will be CMP_NODE_COMPOSITE > CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER.
|
||||
* marked, then the preference will be CMP_NODE_VIEWER > CMP_NODE_SPLITVIEWER > CMP_NODE_COMPOSITE.
|
||||
* If no output node exists, a null node will be returned. */
|
||||
static DNode find_output_in_context(const DTreeContext *context)
|
||||
{
|
||||
const bNodeTree &tree = context->btree();
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeComposite")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
}
|
||||
}
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeViewer")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
|
@ -95,6 +89,12 @@ static DNode find_output_in_context(const DTreeContext *context)
|
|||
}
|
||||
}
|
||||
|
||||
for (const bNode *node : tree.nodes_by_type("CompositorNodeComposite")) {
|
||||
if (node->flag & NODE_DO_OUTPUT) {
|
||||
return DNode(context, node);
|
||||
}
|
||||
}
|
||||
|
||||
return DNode();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
/* Add 0.5 to evaluate the input sampler at the center of the pixel and divide by the image size
|
||||
* to get the coordinates into the sampler's expected [0, 1] range. */
|
||||
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(texture_size(input_tx));
|
||||
|
||||
vec3 transformed_coordinates = mat3(homography_matrix) * vec3(coordinates, 1.0);
|
||||
vec2 projected_coordinates = transformed_coordinates.xy / transformed_coordinates.z;
|
||||
|
||||
/* The derivatives of the projected coordinates with respect to x and y are the first and
|
||||
* second columns respectively, divided by the z projection factor as can be shown by
|
||||
* differentiating the above matrix multiplication with respect to x and y. */
|
||||
vec2 x_gradient = homography_matrix[0].xy / transformed_coordinates.z;
|
||||
vec2 y_gradient = homography_matrix[1].xy / transformed_coordinates.z;
|
||||
|
||||
vec4 sampled_color = textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
|
||||
|
||||
imageStore(output_img, texel, sampled_color);
|
||||
imageStore(mask_img, texel, sampled_color.aaaa);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform)
|
||||
.local_group_size(16, 16)
|
||||
.push_constant(Type::MAT4, "homography_matrix")
|
||||
.sampler(0, ImageType::FLOAT_2D, "input_tx")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "mask_img")
|
||||
.compute_source("compositor_plane_deform.glsl")
|
||||
.do_static_compilation(true);
|
|
@ -34,6 +34,7 @@ void node_composite_separate_rgba(vec4 color, out float r, out float g, out floa
|
|||
void node_composite_combine_hsva(float h, float s, float v, float a, out vec4 color)
|
||||
{
|
||||
hsv_to_rgb(vec4(h, s, v, a), color);
|
||||
color.rgb = max(color.rgb, vec3(0.0));
|
||||
}
|
||||
|
||||
void node_composite_separate_hsva(vec4 color, out float h, out float s, out float v, out float a)
|
||||
|
@ -51,6 +52,7 @@ void node_composite_separate_hsva(vec4 color, out float h, out float s, out floa
|
|||
void node_composite_combine_hsla(float h, float s, float l, float a, out vec4 color)
|
||||
{
|
||||
hsl_to_rgb(vec4(h, s, l, a), color);
|
||||
color.rgb = max(color.rgb, vec3(0.0));
|
||||
}
|
||||
|
||||
void node_composite_separate_hsla(vec4 color, out float h, out float s, out float l, out float a)
|
||||
|
|
|
@ -184,29 +184,29 @@ BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
|
|||
|
||||
BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
|
||||
{
|
||||
return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
return ((mr->p_origindex != nullptr) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
|
||||
NULL;
|
||||
nullptr;
|
||||
}
|
||||
|
||||
BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx)
|
||||
{
|
||||
return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
return ((mr->e_origindex != nullptr) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
|
||||
NULL;
|
||||
nullptr;
|
||||
}
|
||||
|
||||
BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
|
||||
{
|
||||
return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
return ((mr->v_origindex != nullptr) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
|
||||
BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
|
||||
NULL;
|
||||
nullptr;
|
||||
}
|
||||
|
||||
BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
|
||||
{
|
||||
const float(*vert_coords)[3] = mr->bm_vert_coords;
|
||||
if (vert_coords != NULL) {
|
||||
if (vert_coords != nullptr) {
|
||||
return vert_coords[BM_elem_index_get(eve)];
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *e
|
|||
BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
|
||||
{
|
||||
const float(*vert_normals)[3] = mr->bm_vert_normals;
|
||||
if (vert_normals != NULL) {
|
||||
if (vert_normals != nullptr) {
|
||||
return vert_normals[BM_elem_index_get(eve)];
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *e
|
|||
BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
|
||||
{
|
||||
const float(*poly_normals)[3] = mr->bm_poly_normals;
|
||||
if (poly_normals != NULL) {
|
||||
if (poly_normals != nullptr) {
|
||||
return poly_normals[BM_elem_index_get(efa)];
|
||||
}
|
||||
|
||||
|
|
|
@ -657,8 +657,7 @@ struct AssetIndex {
|
|||
AssetIndex(const FileIndexerEntries &indexer_entries)
|
||||
{
|
||||
std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>();
|
||||
DictionaryValue::Items &root_attributes = root->elements();
|
||||
root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION)));
|
||||
root->append_int(ATTRIBUTE_VERSION, CURRENT_VERSION);
|
||||
init_value_from_file_indexer_entries(*root, indexer_entries);
|
||||
|
||||
contents = std::move(root);
|
||||
|
|
|
@ -281,7 +281,10 @@ static void um_arraystore_cd_compact(CustomData *cdata,
|
|||
* solution might be to not pass "dynamic" layers (see `layer_type_is_dynamic`) to the
|
||||
* array store at all. */
|
||||
BLI_assert(layer->sharing_info->is_mutable());
|
||||
MEM_delete(layer->sharing_info);
|
||||
/* Intentionally don't call #MEM_delete, because we want to free the sharing info without
|
||||
* the data here. In general this would not be allowed because one can't be sure how to
|
||||
* free the data without the sharing info. */
|
||||
MEM_freeN(const_cast<blender::ImplicitSharingInfo *>(layer->sharing_info));
|
||||
}
|
||||
MEM_freeN(layer->data);
|
||||
layer->data = nullptr;
|
||||
|
|
|
@ -504,10 +504,10 @@ struct AddOperationExecutor {
|
|||
{
|
||||
if (self_->curve_roots_kdtree_ == nullptr) {
|
||||
self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_orig_->curves_num());
|
||||
const Span<int> offsets = curves_orig_->offsets();
|
||||
const Span<float3> positions = curves_orig_->positions();
|
||||
for (const int curve_i : curves_orig_->curves_range()) {
|
||||
const int root_point_i = curves_orig_->offsets()[curve_i];
|
||||
const float3 &root_pos_cu = curves_orig_->positions()[root_point_i];
|
||||
BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, root_pos_cu);
|
||||
BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, positions[offsets[curve_i]]);
|
||||
}
|
||||
BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
|
||||
}
|
||||
|
|
|
@ -854,13 +854,13 @@ static void action_space_subtype_item_extend(bContext * /*C*/,
|
|||
RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items);
|
||||
}
|
||||
|
||||
static void action_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
|
||||
static void action_space_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
|
||||
{
|
||||
SpaceAction *saction = (SpaceAction *)sl;
|
||||
memset(&saction->runtime, 0x0, sizeof(saction->runtime));
|
||||
}
|
||||
|
||||
static void action_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void action_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceAction *saction = (SpaceAction *)sl;
|
||||
bDopeSheet *ads = &saction->ads;
|
||||
|
@ -873,7 +873,7 @@ static void action_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLi
|
|||
BLO_read_id_address(reader, parent_id->lib, &saction->action);
|
||||
}
|
||||
|
||||
static void action_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void action_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceAction, sl);
|
||||
}
|
||||
|
@ -905,9 +905,9 @@ void ED_spacetype_action(void)
|
|||
st->space_subtype_item_extend = action_space_subtype_item_extend;
|
||||
st->space_subtype_get = action_space_subtype_get;
|
||||
st->space_subtype_set = action_space_subtype_set;
|
||||
st->blend_read_data = action_blend_read_data;
|
||||
st->blend_read_lib = action_blend_read_lib;
|
||||
st->blend_write = action_blend_write;
|
||||
st->blend_read_data = action_space_blend_read_data;
|
||||
st->blend_read_lib = action_space_blend_read_lib;
|
||||
st->blend_write = action_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_cnew<ARegionType>("spacetype action region");
|
||||
|
|
|
@ -907,7 +907,7 @@ static void buttons_id_remap(ScrArea *UNUSED(area),
|
|||
}
|
||||
}
|
||||
|
||||
static void buttons_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
static void buttons_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
{
|
||||
SpaceProperties *sbuts = (SpaceProperties *)sl;
|
||||
|
||||
|
@ -918,7 +918,7 @@ static void buttons_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *
|
|||
sbuts->runtime = NULL;
|
||||
}
|
||||
|
||||
static void buttons_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void buttons_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceProperties *sbuts = (SpaceProperties *)sl;
|
||||
BLO_read_id_address(reader, parent_id->lib, &sbuts->pinid);
|
||||
|
@ -927,7 +927,7 @@ static void buttons_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceL
|
|||
}
|
||||
}
|
||||
|
||||
static void buttons_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void buttons_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceProperties, sl);
|
||||
}
|
||||
|
@ -955,9 +955,9 @@ void ED_spacetype_buttons(void)
|
|||
st->listener = buttons_area_listener;
|
||||
st->context = buttons_context;
|
||||
st->id_remap = buttons_id_remap;
|
||||
st->blend_read_data = buttons_blend_read_data;
|
||||
st->blend_read_lib = buttons_blend_read_lib;
|
||||
st->blend_write = buttons_blend_write;
|
||||
st->blend_read_data = buttons_space_blend_read_data;
|
||||
st->blend_read_lib = buttons_space_blend_read_lib;
|
||||
st->blend_write = buttons_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
|
||||
|
|
|
@ -1121,7 +1121,7 @@ static void clip_id_remap(ScrArea * /*area*/, SpaceLink *slink, const struct IDR
|
|||
BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
|
||||
}
|
||||
|
||||
static void clip_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
|
||||
static void clip_space_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
|
||||
{
|
||||
SpaceClip *sclip = (SpaceClip *)sl;
|
||||
|
||||
|
@ -1130,14 +1130,14 @@ static void clip_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)
|
|||
sclip->scopes.ok = 0;
|
||||
}
|
||||
|
||||
static void clip_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void clip_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceClip *sclip = (SpaceClip *)sl;
|
||||
BLO_read_id_address(reader, parent_id->lib, &sclip->clip);
|
||||
BLO_read_id_address(reader, parent_id->lib, &sclip->mask_info.mask);
|
||||
}
|
||||
|
||||
static void clip_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void clip_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceClip, sl);
|
||||
}
|
||||
|
@ -1162,9 +1162,9 @@ void ED_spacetype_clip(void)
|
|||
st->dropboxes = clip_dropboxes;
|
||||
st->refresh = clip_refresh;
|
||||
st->id_remap = clip_id_remap;
|
||||
st->blend_read_data = clip_blend_read_data;
|
||||
st->blend_read_lib = clip_blend_read_lib;
|
||||
st->blend_write = clip_blend_write;
|
||||
st->blend_read_data = clip_space_blend_read_data;
|
||||
st->blend_read_lib = clip_space_blend_read_lib;
|
||||
st->blend_write = clip_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_cnew<ARegionType>("spacetype clip region");
|
||||
|
|
|
@ -307,7 +307,7 @@ static void console_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
|||
}
|
||||
}
|
||||
|
||||
static void console_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void console_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
SpaceConsole *con = (SpaceConsole *)sl;
|
||||
|
||||
|
@ -335,7 +335,7 @@ void ED_spacetype_console(void)
|
|||
st->keymap = console_keymap;
|
||||
st->dropboxes = console_dropboxes;
|
||||
st->blend_read_data = console_blend_read_data;
|
||||
st->blend_write = console_blend_write;
|
||||
st->blend_write = console_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype console region");
|
||||
|
|
|
@ -2975,7 +2975,7 @@ static void filenum_newname(char *name, size_t name_size, int add)
|
|||
int pic;
|
||||
ushort digits;
|
||||
|
||||
pic = BLI_path_sequence_decode(name, head, tail, &digits);
|
||||
pic = BLI_path_sequence_decode(name, head, sizeof(head), tail, sizeof(tail), &digits);
|
||||
|
||||
/* are we going from 100 -> 99 or from 10 -> 9 */
|
||||
if (add < 0 && digits > 0) {
|
||||
|
@ -2993,7 +2993,7 @@ static void filenum_newname(char *name, size_t name_size, int add)
|
|||
if (pic < 0) {
|
||||
pic = 0;
|
||||
}
|
||||
BLI_path_sequence_encode(name_temp, head, tail, digits, pic);
|
||||
BLI_path_sequence_encode(name_temp, sizeof(name_temp), head, tail, digits, pic);
|
||||
BLI_strncpy(name, name_temp, name_size);
|
||||
}
|
||||
|
||||
|
|
|
@ -926,7 +926,7 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper
|
|||
file_reset_filelist_showing_main_data(area, sfile);
|
||||
}
|
||||
|
||||
static void file_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
static void file_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
{
|
||||
SpaceFile *sfile = (SpaceFile *)sl;
|
||||
|
||||
|
@ -951,15 +951,15 @@ static void file_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
|||
}
|
||||
}
|
||||
|
||||
static void file_blend_read_lib(BlendLibReader *UNUSED(reader),
|
||||
ID *UNUSED(parent_id),
|
||||
SpaceLink *sl)
|
||||
static void file_space_blend_read_lib(BlendLibReader *UNUSED(reader),
|
||||
ID *UNUSED(parent_id),
|
||||
SpaceLink *sl)
|
||||
{
|
||||
SpaceFile *sfile = (SpaceFile *)sl;
|
||||
sfile->tags |= FILE_TAG_REBUILD_MAIN_FILES;
|
||||
}
|
||||
|
||||
static void file_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void file_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
SpaceFile *sfile = (SpaceFile *)sl;
|
||||
|
||||
|
@ -995,9 +995,9 @@ void ED_spacetype_file(void)
|
|||
st->space_subtype_set = file_space_subtype_set;
|
||||
st->context = file_context;
|
||||
st->id_remap = file_id_remap;
|
||||
st->blend_read_data = file_blend_read_data;
|
||||
st->blend_read_lib = file_blend_read_lib;
|
||||
st->blend_write = file_blend_write;
|
||||
st->blend_read_data = file_space_blend_read_data;
|
||||
st->blend_read_lib = file_space_blend_read_lib;
|
||||
st->blend_write = file_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
|
||||
|
|
|
@ -87,6 +87,59 @@ typedef struct tBeztCopyData {
|
|||
/** \name Utility Functions
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Helper function that iterates over all FCurves and selected segments and applies the given
|
||||
* function.
|
||||
*/
|
||||
static void apply_fcu_segment_function(bAnimContext *ac,
|
||||
const float factor,
|
||||
void (*segment_function)(FCurve *fcu,
|
||||
FCurveSegment *segment,
|
||||
const float factor))
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
|
||||
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
ListBase segments = find_fcurve_segments(fcu);
|
||||
|
||||
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
|
||||
segment_function(fcu, segment, factor);
|
||||
}
|
||||
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
BLI_freelistN(&segments);
|
||||
}
|
||||
|
||||
ANIM_animdata_update(ac, &anim_data);
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
static void common_draw_status_header(bContext *C, tGraphSliderOp *gso, const char *operator_name)
|
||||
{
|
||||
char status_str[UI_MAX_DRAW_STR];
|
||||
char mode_str[32];
|
||||
char slider_string[UI_MAX_DRAW_STR];
|
||||
|
||||
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
|
||||
|
||||
strcpy(mode_str, TIP_(operator_name));
|
||||
|
||||
if (hasNumInput(&gso->num)) {
|
||||
char str_ofs[NUM_STR_REP_LEN];
|
||||
|
||||
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
|
||||
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
|
||||
}
|
||||
else {
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
|
||||
}
|
||||
|
||||
ED_workspace_status_text(C, status_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a list with the original bezt arrays so we can restore them during modal operation.
|
||||
* The data is stored on the struct that is passed.
|
||||
|
@ -558,58 +611,16 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
|
|||
/** \name Blend to Neighbor Operator
|
||||
* \{ */
|
||||
|
||||
static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
|
||||
static void blend_to_neighbor_graph_keys(bAnimContext *ac, const float factor)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
|
||||
|
||||
bAnimListElem *ale;
|
||||
|
||||
/* Loop through filtered data and blend keys. */
|
||||
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
ListBase segments = find_fcurve_segments(fcu);
|
||||
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
|
||||
blend_to_neighbor_fcurve_segment(fcu, segment, factor);
|
||||
}
|
||||
BLI_freelistN(&segments);
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
}
|
||||
|
||||
ANIM_animdata_update(ac, &anim_data);
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso)
|
||||
{
|
||||
char status_str[UI_MAX_DRAW_STR];
|
||||
char mode_str[32];
|
||||
char slider_string[UI_MAX_DRAW_STR];
|
||||
|
||||
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
|
||||
|
||||
strcpy(mode_str, TIP_("Blend to Neighbor"));
|
||||
|
||||
if (hasNumInput(&gso->num)) {
|
||||
char str_ofs[NUM_STR_REP_LEN];
|
||||
|
||||
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
|
||||
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
|
||||
}
|
||||
else {
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
|
||||
}
|
||||
|
||||
ED_workspace_status_text(C, status_str);
|
||||
apply_fcu_segment_function(ac, factor, blend_to_neighbor_fcurve_segment);
|
||||
}
|
||||
|
||||
static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op)
|
||||
{
|
||||
tGraphSliderOp *gso = op->customdata;
|
||||
|
||||
blend_to_neighbor_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Blend to Neighbor");
|
||||
|
||||
/* Reset keyframe data to the state at invoke. */
|
||||
reset_bezts(gso);
|
||||
|
@ -631,7 +642,7 @@ static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *
|
|||
tGraphSliderOp *gso = op->customdata;
|
||||
gso->modal_update = blend_to_neighbor_modal_update;
|
||||
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
|
||||
blend_to_neighbor_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Blend to Neighbor");
|
||||
|
||||
return invoke_result;
|
||||
}
|
||||
|
@ -689,54 +700,14 @@ void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot)
|
|||
|
||||
static void breakdown_graph_keys(bAnimContext *ac, float factor)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
|
||||
|
||||
bAnimListElem *ale;
|
||||
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
ListBase segments = find_fcurve_segments(fcu);
|
||||
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
|
||||
breakdown_fcurve_segment(fcu, segment, factor);
|
||||
}
|
||||
BLI_freelistN(&segments);
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
}
|
||||
|
||||
ANIM_animdata_update(ac, &anim_data);
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
static void breakdown_draw_status_header(bContext *C, tGraphSliderOp *gso)
|
||||
{
|
||||
char status_str[UI_MAX_DRAW_STR];
|
||||
char mode_str[32];
|
||||
char slider_string[UI_MAX_DRAW_STR];
|
||||
|
||||
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
|
||||
|
||||
strcpy(mode_str, TIP_("Breakdown"));
|
||||
|
||||
if (hasNumInput(&gso->num)) {
|
||||
char str_ofs[NUM_STR_REP_LEN];
|
||||
|
||||
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
|
||||
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
|
||||
}
|
||||
else {
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
|
||||
}
|
||||
|
||||
ED_workspace_status_text(C, status_str);
|
||||
apply_fcu_segment_function(ac, factor, breakdown_fcurve_segment);
|
||||
}
|
||||
|
||||
static void breakdown_modal_update(bContext *C, wmOperator *op)
|
||||
{
|
||||
tGraphSliderOp *gso = op->customdata;
|
||||
|
||||
breakdown_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Breakdown");
|
||||
|
||||
/* Reset keyframe data to the state at invoke. */
|
||||
reset_bezts(gso);
|
||||
|
@ -756,7 +727,7 @@ static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
tGraphSliderOp *gso = op->customdata;
|
||||
gso->modal_update = breakdown_modal_update;
|
||||
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
|
||||
breakdown_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Breakdown");
|
||||
|
||||
return invoke_result;
|
||||
}
|
||||
|
@ -836,35 +807,11 @@ static void blend_to_default_graph_keys(bAnimContext *ac, const float factor)
|
|||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
static void blend_to_default_draw_status_header(bContext *C, tGraphSliderOp *gso)
|
||||
{
|
||||
char status_str[UI_MAX_DRAW_STR];
|
||||
char mode_str[32];
|
||||
char slider_string[UI_MAX_DRAW_STR];
|
||||
|
||||
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
|
||||
|
||||
strcpy(mode_str, TIP_("Blend to Default Value"));
|
||||
|
||||
if (hasNumInput(&gso->num)) {
|
||||
char str_ofs[NUM_STR_REP_LEN];
|
||||
|
||||
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
|
||||
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
|
||||
}
|
||||
else {
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
|
||||
}
|
||||
|
||||
ED_workspace_status_text(C, status_str);
|
||||
}
|
||||
|
||||
static void blend_to_default_modal_update(bContext *C, wmOperator *op)
|
||||
{
|
||||
tGraphSliderOp *gso = op->customdata;
|
||||
|
||||
blend_to_default_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Blend to Default Value");
|
||||
|
||||
/* Set notifier that keyframes have changed. */
|
||||
reset_bezts(gso);
|
||||
|
@ -885,7 +832,7 @@ static int blend_to_default_invoke(bContext *C, wmOperator *op, const wmEvent *e
|
|||
tGraphSliderOp *gso = op->customdata;
|
||||
gso->modal_update = blend_to_default_modal_update;
|
||||
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
|
||||
blend_to_default_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Blend to Default Value");
|
||||
|
||||
return invoke_result;
|
||||
}
|
||||
|
@ -942,54 +889,14 @@ void GRAPH_OT_blend_to_default(wmOperatorType *ot)
|
|||
|
||||
static void ease_graph_keys(bAnimContext *ac, const float factor)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
|
||||
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
ListBase segments = find_fcurve_segments(fcu);
|
||||
|
||||
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
|
||||
ease_fcurve_segment(fcu, segment, factor);
|
||||
}
|
||||
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
BLI_freelistN(&segments);
|
||||
}
|
||||
|
||||
ANIM_animdata_update(ac, &anim_data);
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
static void ease_draw_status_header(bContext *C, tGraphSliderOp *gso)
|
||||
{
|
||||
char status_str[UI_MAX_DRAW_STR];
|
||||
char mode_str[32];
|
||||
char slider_string[UI_MAX_DRAW_STR];
|
||||
|
||||
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
|
||||
|
||||
strcpy(mode_str, TIP_("Ease Keys"));
|
||||
|
||||
if (hasNumInput(&gso->num)) {
|
||||
char str_ofs[NUM_STR_REP_LEN];
|
||||
|
||||
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
|
||||
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
|
||||
}
|
||||
else {
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
|
||||
}
|
||||
|
||||
ED_workspace_status_text(C, status_str);
|
||||
apply_fcu_segment_function(ac, factor, ease_fcurve_segment);
|
||||
}
|
||||
|
||||
static void ease_modal_update(bContext *C, wmOperator *op)
|
||||
{
|
||||
tGraphSliderOp *gso = op->customdata;
|
||||
|
||||
ease_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Ease Keys");
|
||||
|
||||
/* Reset keyframes to the state at invoke. */
|
||||
reset_bezts(gso);
|
||||
|
@ -1009,7 +916,7 @@ static int ease_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
tGraphSliderOp *gso = op->customdata;
|
||||
gso->modal_update = ease_modal_update;
|
||||
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
|
||||
ease_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Ease Keys");
|
||||
|
||||
return invoke_result;
|
||||
}
|
||||
|
@ -1133,29 +1040,6 @@ static void gaussian_smooth_free_operator_data(void *operator_data)
|
|||
MEM_freeN(gauss_data);
|
||||
}
|
||||
|
||||
static void gaussian_smooth_draw_status_header(bContext *C, tGraphSliderOp *gso)
|
||||
{
|
||||
char status_str[UI_MAX_DRAW_STR];
|
||||
char slider_string[UI_MAX_DRAW_STR];
|
||||
|
||||
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
|
||||
|
||||
const char *mode_str = TIP_("Gaussian Smooth");
|
||||
|
||||
if (hasNumInput(&gso->num)) {
|
||||
char str_ofs[NUM_STR_REP_LEN];
|
||||
|
||||
outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
|
||||
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
|
||||
}
|
||||
else {
|
||||
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
|
||||
}
|
||||
|
||||
ED_workspace_status_text(C, status_str);
|
||||
}
|
||||
|
||||
static void gaussian_smooth_modal_update(bContext *C, wmOperator *op)
|
||||
{
|
||||
tGraphSliderOp *gso = op->customdata;
|
||||
|
@ -1166,7 +1050,7 @@ static void gaussian_smooth_modal_update(bContext *C, wmOperator *op)
|
|||
return;
|
||||
}
|
||||
|
||||
gaussian_smooth_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Gaussian Smooth");
|
||||
|
||||
const float factor = slider_factor_get_and_remember(op);
|
||||
tGaussOperatorData *operator_data = (tGaussOperatorData *)gso->operator_data;
|
||||
|
@ -1209,7 +1093,7 @@ static int gaussian_smooth_invoke(bContext *C, wmOperator *op, const wmEvent *ev
|
|||
|
||||
ED_slider_allow_overshoot_set(gso->slider, false);
|
||||
ED_slider_factor_set(gso->slider, 0.0f);
|
||||
gaussian_smooth_draw_status_header(C, gso);
|
||||
common_draw_status_header(C, gso, "Gaussian Smooth");
|
||||
|
||||
return invoke_result;
|
||||
}
|
||||
|
|
|
@ -833,7 +833,7 @@ static void graph_space_subtype_item_extend(bContext *UNUSED(C),
|
|||
RNA_enum_items_add(item, totitem, rna_enum_space_graph_mode_items);
|
||||
}
|
||||
|
||||
static void graph_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
static void graph_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
{
|
||||
SpaceGraph *sipo = (SpaceGraph *)sl;
|
||||
|
||||
|
@ -841,7 +841,7 @@ static void graph_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
|||
memset(&sipo->runtime, 0x0, sizeof(sipo->runtime));
|
||||
}
|
||||
|
||||
static void graph_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void graph_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceGraph *sipo = (SpaceGraph *)sl;
|
||||
bDopeSheet *ads = sipo->ads;
|
||||
|
@ -852,7 +852,7 @@ static void graph_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLin
|
|||
}
|
||||
}
|
||||
|
||||
static void graph_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void graph_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
SpaceGraph *sipo = (SpaceGraph *)sl;
|
||||
ListBase tmpGhosts = sipo->runtime.ghost_curves;
|
||||
|
@ -889,9 +889,9 @@ void ED_spacetype_ipo(void)
|
|||
st->space_subtype_item_extend = graph_space_subtype_item_extend;
|
||||
st->space_subtype_get = graph_space_subtype_get;
|
||||
st->space_subtype_set = graph_space_subtype_set;
|
||||
st->blend_read_data = graph_blend_read_data;
|
||||
st->blend_read_lib = graph_blend_read_lib;
|
||||
st->blend_write = graph_blend_write;
|
||||
st->blend_read_data = graph_space_blend_read_data;
|
||||
st->blend_read_lib = graph_space_blend_read_lib;
|
||||
st->blend_write = graph_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
|
||||
|
|
|
@ -1586,8 +1586,7 @@ static int image_file_browse_exec(bContext *C, wmOperator *op)
|
|||
|
||||
/* If loading into a tiled texture, ensure that the filename is tokenized. */
|
||||
if (ima->source == IMA_SRC_TILED) {
|
||||
char *filename = (char *)BLI_path_basename(filepath);
|
||||
BKE_image_ensure_tile_token(filename);
|
||||
BKE_image_ensure_tile_token(filepath, sizeof(filepath));
|
||||
}
|
||||
|
||||
PointerRNA imaptr;
|
||||
|
|
|
@ -55,7 +55,8 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
|
|||
ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
|
||||
|
||||
/* use the first file in the list as base filename */
|
||||
frame->framenr = BLI_path_sequence_decode(filename, head, tail, &digits);
|
||||
frame->framenr = BLI_path_sequence_decode(
|
||||
filename, head, sizeof(head), tail, sizeof(tail), &digits);
|
||||
|
||||
/* still in the same sequence */
|
||||
if (do_frame_range && (range != NULL) && STREQLEN(base_head, head, FILE_MAX) &&
|
||||
|
|
|
@ -1038,7 +1038,7 @@ static void image_space_subtype_item_extend(bContext *UNUSED(C),
|
|||
RNA_enum_items_add(item, totitem, rna_enum_space_image_mode_items);
|
||||
}
|
||||
|
||||
static void image_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
static void image_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
{
|
||||
SpaceImage *sima = (SpaceImage *)sl;
|
||||
|
||||
|
@ -1060,7 +1060,7 @@ static void image_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl
|
|||
#endif
|
||||
}
|
||||
|
||||
static void image_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void image_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceImage *sima = (SpaceImage *)sl;
|
||||
|
||||
|
@ -1073,7 +1073,7 @@ static void image_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLin
|
|||
BLO_read_id_address(reader, parent_id->lib, &sima->gpd);
|
||||
}
|
||||
|
||||
static void image_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void image_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceImage, sl);
|
||||
}
|
||||
|
@ -1103,9 +1103,9 @@ void ED_spacetype_image(void)
|
|||
st->space_subtype_item_extend = image_space_subtype_item_extend;
|
||||
st->space_subtype_get = image_space_subtype_get;
|
||||
st->space_subtype_set = image_space_subtype_set;
|
||||
st->blend_read_data = image_blend_read_data;
|
||||
st->blend_read_lib = image_blend_read_lib;
|
||||
st->blend_write = image_blend_write;
|
||||
st->blend_read_data = image_space_blend_read_data;
|
||||
st->blend_read_lib = image_space_blend_read_lib;
|
||||
st->blend_write = image_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
|
||||
|
|
|
@ -248,7 +248,7 @@ static void info_header_region_message_subscribe(const wmRegionMessageSubscribeP
|
|||
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
|
||||
}
|
||||
|
||||
static void info_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void info_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceInfo, sl);
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ void ED_spacetype_info(void)
|
|||
st->duplicate = info_duplicate;
|
||||
st->operatortypes = info_operatortypes;
|
||||
st->keymap = info_keymap;
|
||||
st->blend_write = info_blend_write;
|
||||
st->blend_write = info_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype info region");
|
||||
|
|
|
@ -565,13 +565,13 @@ static void nla_id_remap(ScrArea *UNUSED(area),
|
|||
BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT);
|
||||
}
|
||||
|
||||
static void nla_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
static void nla_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
{
|
||||
SpaceNla *snla = (SpaceNla *)sl;
|
||||
BLO_read_data_address(reader, &snla->ads);
|
||||
}
|
||||
|
||||
static void nla_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void nla_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceNla *snla = (SpaceNla *)sl;
|
||||
bDopeSheet *ads = snla->ads;
|
||||
|
@ -582,7 +582,7 @@ static void nla_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink
|
|||
}
|
||||
}
|
||||
|
||||
static void nla_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void nla_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
SpaceNla *snla = (SpaceNla *)sl;
|
||||
|
||||
|
@ -608,9 +608,9 @@ void ED_spacetype_nla(void)
|
|||
st->listener = nla_listener;
|
||||
st->keymap = nla_keymap;
|
||||
st->id_remap = nla_id_remap;
|
||||
st->blend_read_data = nla_blend_read_data;
|
||||
st->blend_read_lib = nla_blend_read_lib;
|
||||
st->blend_write = nla_blend_write;
|
||||
st->blend_read_data = nla_space_blend_read_data;
|
||||
st->blend_read_lib = nla_space_blend_read_lib;
|
||||
st->blend_write = nla_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
|
||||
|
|
|
@ -1037,7 +1037,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
|
|||
}
|
||||
}
|
||||
|
||||
static void node_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
static void node_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
{
|
||||
SpaceNode *snode = (SpaceNode *)sl;
|
||||
|
||||
|
@ -1051,7 +1051,7 @@ static void node_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
|||
snode->runtime = nullptr;
|
||||
}
|
||||
|
||||
static void node_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void node_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceNode *snode = (SpaceNode *)sl;
|
||||
|
||||
|
@ -1102,7 +1102,7 @@ static void node_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink
|
|||
}
|
||||
}
|
||||
|
||||
static void node_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void node_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
SpaceNode *snode = (SpaceNode *)sl;
|
||||
BLO_write_struct(writer, SpaceNode, snode);
|
||||
|
@ -1139,9 +1139,9 @@ void ED_spacetype_node()
|
|||
st->space_subtype_item_extend = node_space_subtype_item_extend;
|
||||
st->space_subtype_get = node_space_subtype_get;
|
||||
st->space_subtype_set = node_space_subtype_set;
|
||||
st->blend_read_data = node_blend_read_data;
|
||||
st->blend_read_lib = node_blend_read_lib;
|
||||
st->blend_write = node_blend_write;
|
||||
st->blend_read_data = node_space_blend_read_data;
|
||||
st->blend_read_lib = node_space_blend_read_lib;
|
||||
st->blend_write = node_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_cnew<ARegionType>("spacetype node region");
|
||||
|
|
|
@ -447,7 +447,7 @@ static void outliner_deactivate(struct ScrArea *area)
|
|||
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
|
||||
}
|
||||
|
||||
static void outliner_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
static void outliner_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
{
|
||||
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
|
||||
|
||||
|
@ -478,7 +478,9 @@ static void outliner_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
|||
space_outliner->runtime = nullptr;
|
||||
}
|
||||
|
||||
static void outliner_blend_read_lib(BlendLibReader *reader, ID * /*parent_id*/, SpaceLink *sl)
|
||||
static void outliner_space_blend_read_lib(BlendLibReader *reader,
|
||||
ID * /*parent_id*/,
|
||||
SpaceLink *sl)
|
||||
{
|
||||
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
|
||||
|
||||
|
@ -552,7 +554,7 @@ static void write_space_outliner(BlendWriter *writer, const SpaceOutliner *space
|
|||
}
|
||||
}
|
||||
|
||||
static void outliner_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void outliner_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
|
||||
write_space_outliner(writer, space_outliner);
|
||||
|
@ -580,9 +582,9 @@ void ED_spacetype_outliner(void)
|
|||
st->id_remap = outliner_id_remap;
|
||||
st->deactivate = outliner_deactivate;
|
||||
st->context = outliner_context;
|
||||
st->blend_read_data = outliner_blend_read_data;
|
||||
st->blend_read_lib = outliner_blend_read_lib;
|
||||
st->blend_write = outliner_blend_write;
|
||||
st->blend_read_data = outliner_space_blend_read_data;
|
||||
st->blend_read_lib = outliner_space_blend_read_lib;
|
||||
st->blend_write = outliner_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_cnew<ARegionType>("spacetype outliner region");
|
||||
|
|
|
@ -146,7 +146,7 @@ static void script_main_region_listener(const wmRegionListenerParams *UNUSED(par
|
|||
#endif
|
||||
}
|
||||
|
||||
static void script_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void script_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceScript *scpt = (SpaceScript *)sl;
|
||||
/*scpt->script = NULL; - 2.45 set to null, better re-run the script */
|
||||
|
@ -158,7 +158,7 @@ static void script_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLi
|
|||
}
|
||||
}
|
||||
|
||||
static void script_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void script_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
SpaceScript *scr = (SpaceScript *)sl;
|
||||
scr->but_refs = NULL;
|
||||
|
@ -179,8 +179,8 @@ void ED_spacetype_script(void)
|
|||
st->duplicate = script_duplicate;
|
||||
st->operatortypes = script_operatortypes;
|
||||
st->keymap = script_keymap;
|
||||
st->blend_read_lib = script_blend_read_lib;
|
||||
st->blend_write = script_blend_write;
|
||||
st->blend_read_lib = script_space_blend_read_lib;
|
||||
st->blend_write = script_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype script region");
|
||||
|
|
|
@ -952,7 +952,7 @@ static void sequencer_channel_region_draw(const bContext *C, ARegion *region)
|
|||
draw_channels(C, region);
|
||||
}
|
||||
|
||||
static void sequencer_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
static void sequencer_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
{
|
||||
SpaceSeq *sseq = (SpaceSeq *)sl;
|
||||
|
||||
|
@ -978,7 +978,7 @@ static void sequencer_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink
|
|||
memset(&sseq->runtime, 0x0, sizeof(sseq->runtime));
|
||||
}
|
||||
|
||||
static void sequencer_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void sequencer_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceSeq *sseq = (SpaceSeq *)sl;
|
||||
|
||||
|
@ -988,7 +988,7 @@ static void sequencer_blend_read_lib(BlendLibReader *reader, ID *parent_id, Spac
|
|||
BLO_read_id_address(reader, parent_id->lib, &sseq->gpd);
|
||||
}
|
||||
|
||||
static void sequencer_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void sequencer_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceSeq, sl);
|
||||
}
|
||||
|
@ -1013,9 +1013,9 @@ void ED_spacetype_sequencer(void)
|
|||
st->refresh = sequencer_refresh;
|
||||
st->listener = sequencer_listener;
|
||||
st->id_remap = sequencer_id_remap;
|
||||
st->blend_read_data = sequencer_blend_read_data;
|
||||
st->blend_read_lib = sequencer_blend_read_lib;
|
||||
st->blend_write = sequencer_blend_write;
|
||||
st->blend_read_data = sequencer_space_blend_read_data;
|
||||
st->blend_read_lib = sequencer_space_blend_read_lib;
|
||||
st->blend_write = sequencer_space_blend_write;
|
||||
|
||||
/* Create regions: */
|
||||
/* Main window. */
|
||||
|
|
|
@ -124,7 +124,7 @@ static void statusbar_header_region_message_subscribe(const wmRegionMessageSubsc
|
|||
WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
|
||||
}
|
||||
|
||||
static void statusbar_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void statusbar_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceStatusBar, sl);
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ void ED_spacetype_statusbar(void)
|
|||
st->duplicate = statusbar_duplicate;
|
||||
st->operatortypes = statusbar_operatortypes;
|
||||
st->keymap = statusbar_keymap;
|
||||
st->blend_write = statusbar_blend_write;
|
||||
st->blend_write = statusbar_space_blend_write;
|
||||
|
||||
/* regions: header window */
|
||||
art = MEM_callocN(sizeof(*art), "spacetype statusbar header region");
|
||||
|
|
|
@ -395,19 +395,19 @@ static void text_id_remap(ScrArea *UNUSED(area),
|
|||
BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
|
||||
}
|
||||
|
||||
static void text_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
static void text_space_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl)
|
||||
{
|
||||
SpaceText *st = (SpaceText *)sl;
|
||||
memset(&st->runtime, 0x0, sizeof(st->runtime));
|
||||
}
|
||||
|
||||
static void text_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void text_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
SpaceText *st = (SpaceText *)sl;
|
||||
BLO_read_id_address(reader, parent_id->lib, &st->text);
|
||||
}
|
||||
|
||||
static void text_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void text_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceText, sl);
|
||||
}
|
||||
|
@ -432,9 +432,9 @@ void ED_spacetype_text(void)
|
|||
st->context = text_context;
|
||||
st->dropboxes = text_dropboxes;
|
||||
st->id_remap = text_id_remap;
|
||||
st->blend_read_data = text_blend_read_data;
|
||||
st->blend_read_lib = text_blend_read_lib;
|
||||
st->blend_write = text_blend_write;
|
||||
st->blend_read_data = text_space_blend_read_data;
|
||||
st->blend_read_lib = text_space_blend_read_lib;
|
||||
st->blend_write = text_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype text region");
|
||||
|
|
|
@ -276,7 +276,7 @@ static void undo_history_menu_register(void)
|
|||
WM_menutype_add(mt);
|
||||
}
|
||||
|
||||
static void topbar_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void topbar_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceTopBar, sl);
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ void ED_spacetype_topbar(void)
|
|||
st->duplicate = topbar_duplicate;
|
||||
st->operatortypes = topbar_operatortypes;
|
||||
st->keymap = topbar_keymap;
|
||||
st->blend_write = topbar_blend_write;
|
||||
st->blend_write = topbar_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype topbar main region");
|
||||
|
|
|
@ -177,7 +177,7 @@ static void userpref_navigation_region_listener(const wmRegionListenerParams *UN
|
|||
|
||||
static void userpref_execute_region_listener(const wmRegionListenerParams *UNUSED(params)) {}
|
||||
|
||||
static void userpref_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void userpref_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
BLO_write_struct(writer, SpaceUserPref, sl);
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ void ED_spacetype_userpref(void)
|
|||
st->duplicate = userpref_duplicate;
|
||||
st->operatortypes = userpref_operatortypes;
|
||||
st->keymap = userpref_keymap;
|
||||
st->blend_write = userpref_blend_write;
|
||||
st->blend_write = userpref_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region");
|
||||
|
|
|
@ -2053,7 +2053,7 @@ static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRema
|
|||
BKE_viewer_path_id_remap(&view3d->viewer_path, mappings);
|
||||
}
|
||||
|
||||
static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
static void view3d_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
||||
{
|
||||
View3D *v3d = (View3D *)sl;
|
||||
|
||||
|
@ -2078,7 +2078,7 @@ static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
|
|||
BKE_viewer_path_blend_read_data(reader, &v3d->viewer_path);
|
||||
}
|
||||
|
||||
static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
static void view3d_space_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
|
||||
{
|
||||
View3D *v3d = (View3D *)sl;
|
||||
|
||||
|
@ -2092,7 +2092,7 @@ static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLi
|
|||
BKE_viewer_path_blend_read_lib(reader, parent_id->lib, &v3d->viewer_path);
|
||||
}
|
||||
|
||||
static void view3d_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
static void view3d_space_blend_write(BlendWriter *writer, SpaceLink *sl)
|
||||
{
|
||||
View3D *v3d = (View3D *)sl;
|
||||
BLO_write_struct(writer, View3D, v3d);
|
||||
|
@ -2127,9 +2127,9 @@ void ED_spacetype_view3d()
|
|||
st->gizmos = view3d_widgets;
|
||||
st->context = view3d_context;
|
||||
st->id_remap = view3d_id_remap;
|
||||
st->blend_read_data = view3d_blend_read_data;
|
||||
st->blend_read_lib = view3d_blend_read_lib;
|
||||
st->blend_write = view3d_blend_write;
|
||||
st->blend_read_data = view3d_space_blend_read_data;
|
||||
st->blend_read_lib = view3d_space_blend_read_lib;
|
||||
st->blend_write = view3d_space_blend_write;
|
||||
|
||||
/* regions: main window */
|
||||
art = MEM_cnew<ARegionType>("spacetype view3d main region");
|
||||
|
|
|
@ -856,10 +856,12 @@ float ED_view3d_grid_scale(const Scene *scene, View3D *v3d, const char **r_grid_
|
|||
}
|
||||
|
||||
#define STEPS_LEN 8
|
||||
void ED_view3d_grid_steps(const Scene *scene,
|
||||
View3D *v3d,
|
||||
RegionView3D *rv3d,
|
||||
float r_grid_steps[STEPS_LEN])
|
||||
static void view3d_grid_steps_ex(const Scene *scene,
|
||||
View3D *v3d,
|
||||
RegionView3D *rv3d,
|
||||
float r_grid_steps[STEPS_LEN],
|
||||
void const **r_usys_pt,
|
||||
int *r_len)
|
||||
{
|
||||
const void *usys;
|
||||
int len;
|
||||
|
@ -881,7 +883,7 @@ void ED_view3d_grid_steps(const Scene *scene,
|
|||
}
|
||||
for (; i < STEPS_LEN; i++) {
|
||||
/* Fill last slots */
|
||||
r_grid_steps[i] = 10.0f * r_grid_steps[i - 1];
|
||||
r_grid_steps[i] = r_grid_steps[len - 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -899,6 +901,20 @@ void ED_view3d_grid_steps(const Scene *scene,
|
|||
subdiv *= v3d->gridsubdiv;
|
||||
}
|
||||
}
|
||||
if (r_usys_pt) {
|
||||
*r_usys_pt = usys;
|
||||
}
|
||||
if (r_len) {
|
||||
*r_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
void ED_view3d_grid_steps(const Scene *scene,
|
||||
View3D *v3d,
|
||||
RegionView3D *rv3d,
|
||||
float r_grid_steps[STEPS_LEN])
|
||||
{
|
||||
view3d_grid_steps_ex(scene, v3d, rv3d, r_grid_steps, nullptr, nullptr);
|
||||
}
|
||||
|
||||
float ED_view3d_grid_view_scale(Scene *scene,
|
||||
|
@ -912,24 +928,20 @@ float ED_view3d_grid_view_scale(Scene *scene,
|
|||
/* Decrease the distance between grid snap points depending on zoom. */
|
||||
float dist = 12.0f / (region->sizex * rv3d->winmat[0][0]);
|
||||
float grid_steps[STEPS_LEN];
|
||||
ED_view3d_grid_steps(scene, v3d, rv3d, grid_steps);
|
||||
/* Skip last item, in case the 'mid_dist' is greater than the largest unit. */
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(grid_steps) - 1; i++) {
|
||||
const void *usys;
|
||||
int grid_steps_len;
|
||||
view3d_grid_steps_ex(scene, v3d, rv3d, grid_steps, &usys, &grid_steps_len);
|
||||
int i = 0;
|
||||
while (true) {
|
||||
grid_scale = grid_steps[i];
|
||||
if (grid_scale > dist) {
|
||||
if (grid_scale > dist || i == (grid_steps_len - 1)) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (r_grid_unit) {
|
||||
const void *usys;
|
||||
int len;
|
||||
BKE_unit_system_get(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
|
||||
|
||||
if (usys) {
|
||||
*r_grid_unit = IFACE_(BKE_unit_display_name_get(usys, len - i - 1));
|
||||
}
|
||||
if (r_grid_unit && usys) {
|
||||
*r_grid_unit = IFACE_(BKE_unit_display_name_get(usys, grid_steps_len - i - 1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -43,8 +43,44 @@
|
|||
|
||||
#include "view3d_navigate.h" /* own include */
|
||||
|
||||
/* Prototypes. */
|
||||
static void viewops_data_init_context(bContext *C, ViewOpsData *vod);
|
||||
static void viewops_data_init_navigation(bContext *C,
|
||||
const wmEvent *event,
|
||||
const eV3D_OpMode nav_type,
|
||||
const bool use_cursor_init,
|
||||
ViewOpsData *vod);
|
||||
static void viewops_data_end_navigation(bContext *C, ViewOpsData *vod);
|
||||
static int viewpan_invoke_impl(ViewOpsData *vod, PointerRNA *ptr);
|
||||
|
||||
const char *viewops_operator_idname_get(eV3D_OpMode nav_type)
|
||||
{
|
||||
switch (nav_type) {
|
||||
case V3D_OP_MODE_ZOOM:
|
||||
return "VIEW3D_OT_zoom";
|
||||
case V3D_OP_MODE_ROTATE:
|
||||
return "VIEW3D_OT_rotate";
|
||||
case V3D_OP_MODE_MOVE:
|
||||
return "VIEW3D_OT_move";
|
||||
case V3D_OP_MODE_VIEW_PAN:
|
||||
return "VIEW3D_OT_view_pan";
|
||||
case V3D_OP_MODE_VIEW_ROLL:
|
||||
return "VIEW3D_OT_view_roll";
|
||||
case V3D_OP_MODE_DOLLY:
|
||||
return "VIEW3D_OT_dolly";
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
case V3D_OP_MODE_NDOF_ORBIT:
|
||||
return "VIEW3D_OT_ndof_orbit";
|
||||
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
|
||||
return "VIEW3D_OT_ndof_orbit_zoom";
|
||||
#endif
|
||||
}
|
||||
BLI_assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Navigation Polls
|
||||
/** \name Generic Operator Callback Utils
|
||||
* \{ */
|
||||
|
||||
static bool view3d_navigation_poll_impl(bContext *C, const char viewlock)
|
||||
|
@ -57,6 +93,128 @@ static bool view3d_navigation_poll_impl(bContext *C, const char viewlock)
|
|||
return !(RV3D_LOCK_FLAGS(rv3d) & viewlock);
|
||||
}
|
||||
|
||||
static eV3D_OpEvent view3d_navigate_event(ViewOpsData *vod, const wmEvent *event)
|
||||
{
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
return VIEW_CONFIRM;
|
||||
case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
|
||||
vod->axis_snap = true;
|
||||
return VIEW_APPLY;
|
||||
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
|
||||
vod->rv3d->persp = vod->init.persp_with_auto_persp_applied;
|
||||
vod->axis_snap = false;
|
||||
return VIEW_APPLY;
|
||||
case VIEWROT_MODAL_SWITCH_ZOOM:
|
||||
case VIEWROT_MODAL_SWITCH_MOVE:
|
||||
case VIEWROT_MODAL_SWITCH_ROTATE: {
|
||||
const eV3D_OpMode nav_type_new = (event->val == VIEWROT_MODAL_SWITCH_ZOOM) ?
|
||||
V3D_OP_MODE_ZOOM :
|
||||
(event->val == VIEWROT_MODAL_SWITCH_MOVE) ?
|
||||
V3D_OP_MODE_MOVE :
|
||||
V3D_OP_MODE_ROTATE;
|
||||
if (nav_type_new == vod->nav_type) {
|
||||
break;
|
||||
}
|
||||
vod->nav_type = nav_type_new;
|
||||
return VIEW_APPLY;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event->type == TIMER && event->customdata == vod->timer) {
|
||||
/* Zoom uses timer for continuous zoom. */
|
||||
return VIEW_APPLY;
|
||||
}
|
||||
if (event->type == MOUSEMOVE) {
|
||||
return VIEW_APPLY;
|
||||
}
|
||||
if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
|
||||
return VIEW_CONFIRM;
|
||||
}
|
||||
if (event->type == EVT_ESCKEY && event->val == KM_PRESS) {
|
||||
return VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
return VIEW_PASS;
|
||||
}
|
||||
|
||||
static int view3d_navigation_modal(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const eV3D_OpEvent event_code,
|
||||
const int xy[2])
|
||||
{
|
||||
switch (vod->nav_type) {
|
||||
case V3D_OP_MODE_ZOOM:
|
||||
return viewzoom_modal_impl(C, vod, event_code, xy);
|
||||
case V3D_OP_MODE_ROTATE:
|
||||
return viewrotate_modal_impl(C, vod, event_code, xy);
|
||||
case V3D_OP_MODE_MOVE:
|
||||
return viewmove_modal_impl(C, vod, event_code, xy);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static int view3d_navigation_invoke_generic(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const wmEvent *event,
|
||||
PointerRNA *ptr,
|
||||
const eV3D_OpMode nav_type)
|
||||
{
|
||||
bool use_cursor_init = false;
|
||||
if (PropertyRNA *prop = RNA_struct_find_property(ptr, "use_cursor_init")) {
|
||||
use_cursor_init = RNA_property_boolean_get(ptr, prop);
|
||||
}
|
||||
|
||||
viewops_data_init_navigation(C, event, nav_type, use_cursor_init, vod);
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
|
||||
switch (nav_type) {
|
||||
case V3D_OP_MODE_ZOOM:
|
||||
return viewzoom_invoke_impl(C, vod, event, ptr);
|
||||
case V3D_OP_MODE_ROTATE:
|
||||
return viewrotate_invoke_impl(vod, event);
|
||||
case V3D_OP_MODE_MOVE:
|
||||
return viewmove_invoke_impl(vod, event);
|
||||
case V3D_OP_MODE_VIEW_PAN: {
|
||||
return viewpan_invoke_impl(vod, ptr);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
int view3d_navigate_invoke_impl(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event,
|
||||
const eV3D_OpMode nav_type)
|
||||
{
|
||||
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
|
||||
viewops_data_init_context(C, vod);
|
||||
int ret = view3d_navigation_invoke_generic(C, vod, event, op->ptr, nav_type);
|
||||
op->customdata = (void *)vod;
|
||||
|
||||
if (ret == OPERATOR_RUNNING_MODAL) {
|
||||
WM_event_add_modal_handler(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
viewops_data_free(C, vod);
|
||||
op->customdata = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Generic Callbacks
|
||||
* \{ */
|
||||
|
||||
bool view3d_location_poll(bContext *C)
|
||||
{
|
||||
return view3d_navigation_poll_impl(C, RV3D_LOCK_LOCATION);
|
||||
|
@ -72,11 +230,32 @@ bool view3d_zoom_or_dolly_poll(bContext *C)
|
|||
return view3d_navigation_poll_impl(C, RV3D_LOCK_ZOOM_AND_DOLLY);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
int view3d_navigate_modal_fn(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Generic Callbacks
|
||||
* \{ */
|
||||
const eV3D_OpMode nav_type_prev = vod->nav_type;
|
||||
const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
|
||||
if (nav_type_prev != vod->nav_type) {
|
||||
wmOperatorType *ot_new = WM_operatortype_find(viewops_operator_idname_get(vod->nav_type),
|
||||
false);
|
||||
WM_operator_type_set(op, ot_new);
|
||||
viewops_data_end_navigation(C, vod);
|
||||
return view3d_navigation_invoke_generic(C, vod, event, op->ptr, vod->nav_type);
|
||||
}
|
||||
|
||||
int ret = view3d_navigation_modal(C, vod, event_code, event->xy);
|
||||
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, vod);
|
||||
op->customdata = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void view3d_navigate_cancel_fn(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
@ -312,8 +491,12 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
|
|||
return is_set;
|
||||
}
|
||||
|
||||
static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth)
|
||||
static eViewOpsFlag viewops_flag_from_prefs(void)
|
||||
{
|
||||
const bool use_select = (U.uiflag & USER_ORBIT_SELECTION) != 0;
|
||||
const bool use_depth = (U.uiflag & VIEWOPS_FLAG_DEPTH_NAVIGATE) != 0;
|
||||
const bool use_zoom_to_mouse = (U.uiflag & USER_ZOOM_TO_MOUSEPOS) != 0;
|
||||
|
||||
enum eViewOpsFlag flag = VIEWOPS_FLAG_NONE;
|
||||
if (use_select) {
|
||||
flag |= VIEWOPS_FLAG_ORBIT_SELECT;
|
||||
|
@ -321,20 +504,15 @@ static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth)
|
|||
if (use_depth) {
|
||||
flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE;
|
||||
}
|
||||
if (use_zoom_to_mouse) {
|
||||
flag |= VIEWOPS_FLAG_ZOOM_TO_MOUSE;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
enum eViewOpsFlag viewops_flag_from_prefs(void)
|
||||
static void viewops_data_init_context(bContext *C, ViewOpsData *vod)
|
||||
{
|
||||
return viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0,
|
||||
(U.uiflag & USER_DEPTH_NAVIGATE) != 0);
|
||||
}
|
||||
|
||||
ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOpsFlag viewops_flag)
|
||||
{
|
||||
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
|
||||
|
||||
/* Store data. */
|
||||
vod->bmain = CTX_data_main(C);
|
||||
vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
|
@ -343,13 +521,46 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp
|
|||
vod->region = CTX_wm_region(C);
|
||||
vod->v3d = static_cast<View3D *>(vod->area->spacedata.first);
|
||||
vod->rv3d = static_cast<RegionView3D *>(vod->region->regiondata);
|
||||
}
|
||||
|
||||
static void viewops_data_init_navigation(bContext *C,
|
||||
const wmEvent *event,
|
||||
const eV3D_OpMode nav_type,
|
||||
const bool use_cursor_init,
|
||||
ViewOpsData *vod)
|
||||
{
|
||||
Depsgraph *depsgraph = vod->depsgraph;
|
||||
RegionView3D *rv3d = vod->rv3d;
|
||||
|
||||
eViewOpsFlag viewops_flag = viewops_flag_from_prefs();
|
||||
|
||||
if (use_cursor_init) {
|
||||
viewops_flag |= VIEWOPS_FLAG_USE_MOUSE_INIT;
|
||||
}
|
||||
|
||||
switch (nav_type) {
|
||||
case V3D_OP_MODE_ZOOM:
|
||||
case V3D_OP_MODE_MOVE:
|
||||
case V3D_OP_MODE_VIEW_PAN:
|
||||
case V3D_OP_MODE_DOLLY:
|
||||
viewops_flag &= ~VIEWOPS_FLAG_ORBIT_SELECT;
|
||||
break;
|
||||
case V3D_OP_MODE_ROTATE:
|
||||
viewops_flag |= VIEWOPS_FLAG_PERSP_ENSURE;
|
||||
break;
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
case V3D_OP_MODE_NDOF_ORBIT:
|
||||
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
|
||||
viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Could do this more nicely. */
|
||||
if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) {
|
||||
viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
|
||||
viewops_flag &= ~(VIEWOPS_FLAG_DEPTH_NAVIGATE | VIEWOPS_FLAG_ZOOM_TO_MOUSE);
|
||||
}
|
||||
|
||||
/* we need the depth info before changing any viewport options */
|
||||
|
@ -496,12 +707,27 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp
|
|||
vod->reverse = -1.0f;
|
||||
}
|
||||
|
||||
rv3d->rflag |= RV3D_NAVIGATING;
|
||||
vod->nav_type = nav_type;
|
||||
vod->viewops_flag = viewops_flag;
|
||||
|
||||
/* Default. */
|
||||
vod->use_dyn_ofs_ortho_correction = false;
|
||||
|
||||
rv3d->rflag |= RV3D_NAVIGATING;
|
||||
}
|
||||
|
||||
ViewOpsData *viewops_data_create(bContext *C,
|
||||
const wmEvent *event,
|
||||
const eV3D_OpMode nav_type,
|
||||
const bool use_cursor_init)
|
||||
{
|
||||
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
|
||||
viewops_data_init_context(C, vod);
|
||||
viewops_data_init_navigation(C, event, nav_type, use_cursor_init, vod);
|
||||
return vod;
|
||||
}
|
||||
|
||||
void viewops_data_free(bContext *C, ViewOpsData *vod)
|
||||
static void viewops_data_end_navigation(bContext *C, ViewOpsData *vod)
|
||||
{
|
||||
ARegion *region;
|
||||
if (vod) {
|
||||
|
@ -512,11 +738,7 @@ void viewops_data_free(bContext *C, ViewOpsData *vod)
|
|||
WM_event_remove_timer(CTX_wm_manager(C), vod->timer->win, vod->timer);
|
||||
}
|
||||
|
||||
if (vod->init.dial) {
|
||||
MEM_freeN(vod->init.dial);
|
||||
}
|
||||
|
||||
MEM_freeN(vod);
|
||||
MEM_SAFE_FREE(vod->init.dial);
|
||||
}
|
||||
else {
|
||||
region = CTX_wm_region(C);
|
||||
|
@ -527,6 +749,14 @@ void viewops_data_free(bContext *C, ViewOpsData *vod)
|
|||
ED_region_tag_redraw(region);
|
||||
}
|
||||
|
||||
void viewops_data_free(bContext *C, ViewOpsData *vod)
|
||||
{
|
||||
viewops_data_end_navigation(C, vod);
|
||||
if (vod) {
|
||||
MEM_freeN(vod);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -1658,10 +1888,10 @@ static const EnumPropertyItem prop_view_pan_items[] = {
|
|||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
static int viewpan_invoke_impl(ViewOpsData *vod, PointerRNA *ptr)
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
int pandir = RNA_enum_get(op->ptr, "type");
|
||||
int pandir = RNA_enum_get(ptr, "type");
|
||||
|
||||
if (pandir == V3D_VIEW_PANRIGHT) {
|
||||
x = -32;
|
||||
|
@ -1676,23 +1906,22 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
y = 25;
|
||||
}
|
||||
|
||||
ViewOpsData *vod = viewops_data_create(
|
||||
C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT));
|
||||
|
||||
viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y);
|
||||
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
viewops_data_free(C, vod);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_VIEW_PAN);
|
||||
}
|
||||
|
||||
void VIEW3D_OT_view_pan(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Pan View Direction";
|
||||
ot->description = "Pan the view in a given direction";
|
||||
ot->idname = "VIEW3D_OT_view_pan";
|
||||
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_VIEW_PAN);
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewpan_invoke;
|
||||
|
|
|
@ -32,6 +32,19 @@ struct rcti;
|
|||
struct wmEvent;
|
||||
struct wmOperator;
|
||||
|
||||
typedef enum eV3D_OpMode {
|
||||
V3D_OP_MODE_ZOOM = 0,
|
||||
V3D_OP_MODE_ROTATE,
|
||||
V3D_OP_MODE_MOVE,
|
||||
V3D_OP_MODE_VIEW_PAN,
|
||||
V3D_OP_MODE_VIEW_ROLL,
|
||||
V3D_OP_MODE_DOLLY,
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
V3D_OP_MODE_NDOF_ORBIT,
|
||||
V3D_OP_MODE_NDOF_ORBIT_ZOOM,
|
||||
#endif
|
||||
} eV3D_OpMode;
|
||||
|
||||
enum eV3D_OpPropFlag {
|
||||
V3D_OP_PROP_MOUSE_CO = (1 << 0),
|
||||
V3D_OP_PROP_DELTA = (1 << 1),
|
||||
|
@ -39,13 +52,13 @@ enum eV3D_OpPropFlag {
|
|||
V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3),
|
||||
};
|
||||
|
||||
enum {
|
||||
typedef enum eV3D_OpEvent {
|
||||
VIEW_PASS = 0,
|
||||
VIEW_APPLY,
|
||||
VIEW_CONFIRM,
|
||||
/** Only supported by some viewport operators. */
|
||||
VIEW_CANCEL,
|
||||
};
|
||||
} eV3D_OpEvent;
|
||||
|
||||
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
|
||||
enum {
|
||||
|
@ -58,7 +71,7 @@ enum {
|
|||
VIEWROT_MODAL_SWITCH_ROTATE = 6,
|
||||
};
|
||||
|
||||
enum eViewOpsFlag {
|
||||
typedef enum eViewOpsFlag {
|
||||
VIEWOPS_FLAG_NONE = 0,
|
||||
/** When enabled, rotate around the selection. */
|
||||
VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0),
|
||||
|
@ -72,8 +85,10 @@ enum eViewOpsFlag {
|
|||
VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2),
|
||||
/** When set, ignore any options that depend on initial cursor location. */
|
||||
VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3),
|
||||
};
|
||||
ENUM_OPERATORS(eViewOpsFlag, VIEWOPS_FLAG_USE_MOUSE_INIT);
|
||||
|
||||
VIEWOPS_FLAG_ZOOM_TO_MOUSE = (1 << 4),
|
||||
} eViewOpsFlag;
|
||||
ENUM_OPERATORS(eViewOpsFlag, VIEWOPS_FLAG_ZOOM_TO_MOUSE);
|
||||
|
||||
/** Generic View Operator Custom-Data */
|
||||
typedef struct ViewOpsData {
|
||||
|
@ -146,6 +161,9 @@ typedef struct ViewOpsData {
|
|||
float viewquat[4];
|
||||
} curr;
|
||||
|
||||
eV3D_OpMode nav_type;
|
||||
eViewOpsFlag viewops_flag;
|
||||
|
||||
float reverse;
|
||||
bool axis_snap; /* view rotate only */
|
||||
|
||||
|
@ -165,13 +183,22 @@ typedef struct ViewOpsData {
|
|||
|
||||
/* view3d_navigate.cc */
|
||||
|
||||
/**
|
||||
* Navigation operators that share the `ViewOpsData` utility.
|
||||
*/
|
||||
const char *viewops_operator_idname_get(eV3D_OpMode nav_type);
|
||||
|
||||
bool view3d_location_poll(struct bContext *C);
|
||||
bool view3d_rotation_poll(struct bContext *C);
|
||||
bool view3d_zoom_or_dolly_poll(struct bContext *C);
|
||||
|
||||
int view3d_navigate_invoke_impl(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event,
|
||||
const eV3D_OpMode nav_type);
|
||||
int view3d_navigate_modal_fn(bContext *C, wmOperator *op, const wmEvent *event);
|
||||
void view3d_navigate_cancel_fn(struct bContext *C, struct wmOperator *op);
|
||||
|
||||
enum eViewOpsFlag viewops_flag_from_prefs(void);
|
||||
void calctrackballvec(const struct rcti *rect, const int event_xy[2], float r_dir[3]);
|
||||
void viewmove_apply(ViewOpsData *vod, int x, int y);
|
||||
void viewmove_apply_reset(ViewOpsData *vod);
|
||||
|
@ -193,9 +220,10 @@ void viewops_data_free(struct bContext *C, ViewOpsData *vod);
|
|||
/**
|
||||
* Allocate, fill in context pointers and calculate the values for #ViewOpsData
|
||||
*/
|
||||
ViewOpsData *viewops_data_create(struct bContext *C,
|
||||
const struct wmEvent *event,
|
||||
enum eViewOpsFlag viewops_flag);
|
||||
ViewOpsData *viewops_data_create(bContext *C,
|
||||
const wmEvent *event,
|
||||
const eV3D_OpMode nav_type,
|
||||
const bool use_cursor_init);
|
||||
|
||||
void VIEW3D_OT_view_all(struct wmOperatorType *ot);
|
||||
void VIEW3D_OT_view_selected(struct wmOperatorType *ot);
|
||||
|
@ -219,6 +247,11 @@ void VIEW3D_OT_fly(struct wmOperatorType *ot);
|
|||
|
||||
/* view3d_navigate_move.c */
|
||||
|
||||
int viewmove_modal_impl(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const eV3D_OpEvent event_code,
|
||||
const int xy[2]);
|
||||
int viewmove_invoke_impl(ViewOpsData *vod, const wmEvent *event);
|
||||
void viewmove_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
void VIEW3D_OT_move(struct wmOperatorType *ot);
|
||||
|
||||
|
@ -249,6 +282,11 @@ void VIEW3D_OT_view_roll(struct wmOperatorType *ot);
|
|||
|
||||
/* view3d_navigate_rotate.c */
|
||||
|
||||
int viewrotate_modal_impl(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const eV3D_OpEvent event_code,
|
||||
const int xy[2]);
|
||||
int viewrotate_invoke_impl(ViewOpsData *vod, const wmEvent *event);
|
||||
void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
void VIEW3D_OT_rotate(struct wmOperatorType *ot);
|
||||
|
||||
|
@ -326,6 +364,11 @@ void VIEW3D_OT_walk(struct wmOperatorType *ot);
|
|||
|
||||
/* view3d_navigate_zoom.c */
|
||||
|
||||
int viewzoom_modal_impl(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const eV3D_OpEvent event_code,
|
||||
const int xy[2]);
|
||||
int viewzoom_invoke_impl(bContext *C, ViewOpsData *vod, const wmEvent *event, PointerRNA *ptr);
|
||||
void viewzoom_modal_keymap(struct wmKeyConfig *keyconf);
|
||||
void VIEW3D_OT_zoom(struct wmOperatorType *ot);
|
||||
|
||||
|
|
|
@ -246,11 +246,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
|
||||
vod = op->customdata = viewops_data_create(
|
||||
C,
|
||||
event,
|
||||
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
|
||||
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
||||
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_DOLLY, use_cursor_init);
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
|
||||
|
@ -314,7 +310,7 @@ void VIEW3D_OT_dolly(wmOperatorType *ot)
|
|||
/* identifiers */
|
||||
ot->name = "Dolly View";
|
||||
ot->description = "Dolly in/out in the view";
|
||||
ot->idname = "VIEW3D_OT_dolly";
|
||||
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_DOLLY);
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewdolly_invoke;
|
||||
|
|
|
@ -49,52 +49,17 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
|
|||
WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
|
||||
}
|
||||
|
||||
static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
int viewmove_modal_impl(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const eV3D_OpEvent event_code,
|
||||
const int xy[2])
|
||||
{
|
||||
|
||||
ViewOpsData *vod = op->customdata;
|
||||
short event_code = VIEW_PASS;
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
case VIEW_MODAL_CANCEL:
|
||||
event_code = VIEW_CANCEL;
|
||||
break;
|
||||
case VIEWROT_MODAL_SWITCH_ZOOM:
|
||||
WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL, event);
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
case VIEWROT_MODAL_SWITCH_ROTATE:
|
||||
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL, event);
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (event->type == EVT_ESCKEY) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
viewmove_apply(vod, event->xy[0], event->xy[1]);
|
||||
viewmove_apply(vod, xy[0], xy[1]);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
|
@ -111,66 +76,47 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
case VIEW_PASS:
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
||||
}
|
||||
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
int viewmove_invoke_impl(ViewOpsData *vod, const wmEvent *event)
|
||||
{
|
||||
ViewOpsData *vod;
|
||||
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
|
||||
vod = op->customdata = viewops_data_create(
|
||||
C,
|
||||
event,
|
||||
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
|
||||
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
||||
vod = op->customdata;
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
|
||||
if (event->type == MOUSEPAN) {
|
||||
/* invert it, trackpad scroll follows same principle as 2d windows this way */
|
||||
viewmove_apply(
|
||||
vod, 2 * event->xy[0] - event->prev_xy[0], 2 * event->xy[1] - event->prev_xy[1]);
|
||||
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
eV3D_OpEvent event_code = event->type == MOUSEPAN ? VIEW_CONFIRM : VIEW_PASS;
|
||||
|
||||
if (event_code == VIEW_CONFIRM) {
|
||||
/* Invert it, trackpad scroll follows same principle as 2d windows this way. */
|
||||
int mx = 2 * event->xy[0] - event->prev_xy[0];
|
||||
int my = 2 * event->xy[1] - event->prev_xy[1];
|
||||
viewmove_apply(vod, mx, my);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* add temp handler */
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_MOVE);
|
||||
}
|
||||
|
||||
void VIEW3D_OT_move(wmOperatorType *ot)
|
||||
{
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Pan View";
|
||||
ot->description = "Move the view";
|
||||
ot->idname = "VIEW3D_OT_move";
|
||||
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_MOVE);
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewmove_invoke;
|
||||
ot->modal = viewmove_modal;
|
||||
ot->modal = view3d_navigate_modal_fn;
|
||||
ot->poll = view3d_location_poll;
|
||||
ot->cancel = view3d_navigate_cancel_fn;
|
||||
|
||||
|
|
|
@ -435,8 +435,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
|
||||
const wmNDOFMotionData *ndof = event->customdata;
|
||||
|
||||
vod = op->customdata = viewops_data_create(
|
||||
C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_DEPTH_NAVIGATE));
|
||||
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_NDOF_ORBIT, false);
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
|
||||
|
@ -522,8 +521,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
|
|||
|
||||
const wmNDOFMotionData *ndof = event->customdata;
|
||||
|
||||
vod = op->customdata = viewops_data_create(
|
||||
C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_DEPTH_NAVIGATE));
|
||||
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_NDOF_ORBIT_ZOOM, false);
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
}
|
||||
else {
|
||||
/* makes op->customdata */
|
||||
vod = op->customdata = viewops_data_create(C, event, viewops_flag_from_prefs());
|
||||
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_VIEW_ROLL, false);
|
||||
vod->init.dial = BLI_dial_init((const float[2]){BLI_rcti_cent_x(&vod->region->winrct),
|
||||
BLI_rcti_cent_y(&vod->region->winrct)},
|
||||
FLT_EPSILON);
|
||||
|
@ -287,7 +287,7 @@ void VIEW3D_OT_view_roll(wmOperatorType *ot)
|
|||
/* identifiers */
|
||||
ot->name = "View Roll";
|
||||
ot->description = "Roll the view";
|
||||
ot->idname = "VIEW3D_OT_view_roll";
|
||||
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_VIEW_ROLL);
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewroll_invoke;
|
||||
|
|
|
@ -293,60 +293,17 @@ static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2])
|
|||
ED_region_tag_redraw(vod->region);
|
||||
}
|
||||
|
||||
static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
int viewrotate_modal_impl(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const eV3D_OpEvent event_code,
|
||||
const int xy[2])
|
||||
{
|
||||
ViewOpsData *vod = op->customdata;
|
||||
short event_code = VIEW_PASS;
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
case VIEW_MODAL_CANCEL:
|
||||
event_code = VIEW_CANCEL;
|
||||
break;
|
||||
case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
|
||||
vod->axis_snap = true;
|
||||
event_code = VIEW_APPLY;
|
||||
break;
|
||||
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
|
||||
vod->rv3d->persp = vod->init.persp_with_auto_persp_applied;
|
||||
vod->axis_snap = false;
|
||||
event_code = VIEW_APPLY;
|
||||
break;
|
||||
case VIEWROT_MODAL_SWITCH_ZOOM:
|
||||
WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL, event);
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
case VIEWROT_MODAL_SWITCH_MOVE:
|
||||
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL, event);
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (event->type == EVT_ESCKEY) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
viewrotate_apply(vod, event->xy);
|
||||
viewrotate_apply(vod, xy);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
|
@ -376,84 +333,60 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
case VIEW_PASS:
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true);
|
||||
}
|
||||
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
int viewrotate_invoke_impl(ViewOpsData *vod, const wmEvent *event)
|
||||
{
|
||||
ViewOpsData *vod;
|
||||
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
|
||||
/* makes op->customdata */
|
||||
vod = op->customdata = viewops_data_create(
|
||||
C,
|
||||
event,
|
||||
viewops_flag_from_prefs() | VIEWOPS_FLAG_PERSP_ENSURE |
|
||||
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
||||
|
||||
if (vod->use_dyn_ofs && (vod->rv3d->is_persp == false)) {
|
||||
vod->use_dyn_ofs_ortho_correction = true;
|
||||
}
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
eV3D_OpEvent event_code = ELEM(event->type, MOUSEROTATE, MOUSEPAN) ? VIEW_CONFIRM : VIEW_PASS;
|
||||
|
||||
if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
|
||||
/* Rotate direction we keep always same */
|
||||
int event_xy[2];
|
||||
if (event_code == VIEW_CONFIRM) {
|
||||
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
|
||||
const bool is_inverted = (event->flag & WM_EVENT_SCROLL_INVERT) &&
|
||||
(event->type != MOUSEROTATE);
|
||||
|
||||
if (event->type == MOUSEPAN) {
|
||||
if (event->flag & WM_EVENT_SCROLL_INVERT) {
|
||||
event_xy[0] = 2 * event->xy[0] - event->prev_xy[0];
|
||||
event_xy[1] = 2 * event->xy[1] - event->prev_xy[1];
|
||||
}
|
||||
else {
|
||||
copy_v2_v2_int(event_xy, event->prev_xy);
|
||||
}
|
||||
int m_xy[2];
|
||||
if (is_inverted) {
|
||||
m_xy[0] = 2 * event->xy[0] - event->prev_xy[0];
|
||||
m_xy[1] = 2 * event->xy[1] - event->prev_xy[1];
|
||||
}
|
||||
else {
|
||||
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
|
||||
copy_v2_v2_int(event_xy, event->prev_xy);
|
||||
copy_v2_v2_int(m_xy, event->prev_xy);
|
||||
}
|
||||
|
||||
viewrotate_apply(vod, event_xy);
|
||||
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
|
||||
viewrotate_apply(vod, m_xy);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* add temp handler */
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_ROTATE);
|
||||
}
|
||||
|
||||
void VIEW3D_OT_rotate(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Rotate View";
|
||||
ot->description = "Rotate the view";
|
||||
ot->idname = "VIEW3D_OT_rotate";
|
||||
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_ROTATE);
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewrotate_invoke;
|
||||
ot->modal = viewrotate_modal;
|
||||
ot->modal = view3d_navigate_modal_fn;
|
||||
ot->poll = view3d_rotation_poll;
|
||||
ot->cancel = view3d_navigate_cancel_fn;
|
||||
|
||||
|
|
|
@ -331,9 +331,10 @@ static void viewzoom_apply_3d(ViewOpsData *vod,
|
|||
static void viewzoom_apply(ViewOpsData *vod,
|
||||
const int xy[2],
|
||||
const eViewZoom_Style viewzoom,
|
||||
const bool zoom_invert,
|
||||
const bool zoom_to_pos)
|
||||
const bool zoom_invert)
|
||||
{
|
||||
const bool zoom_to_pos = (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) != 0;
|
||||
|
||||
if ((vod->rv3d->persp == RV3D_CAMOB) &&
|
||||
(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) {
|
||||
viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
|
||||
|
@ -343,62 +344,17 @@ static void viewzoom_apply(ViewOpsData *vod,
|
|||
}
|
||||
}
|
||||
|
||||
static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
int viewzoom_modal_impl(bContext *C,
|
||||
ViewOpsData *vod,
|
||||
const eV3D_OpEvent event_code,
|
||||
const int xy[2])
|
||||
{
|
||||
ViewOpsData *vod = op->customdata;
|
||||
short event_code = VIEW_PASS;
|
||||
bool use_autokey = false;
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
|
||||
/* Execute the events. */
|
||||
if (event->type == EVT_MODAL_MAP) {
|
||||
switch (event->val) {
|
||||
case VIEW_MODAL_CONFIRM:
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
case VIEW_MODAL_CANCEL:
|
||||
event_code = VIEW_CANCEL;
|
||||
break;
|
||||
case VIEWROT_MODAL_SWITCH_MOVE:
|
||||
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL, event);
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
case VIEWROT_MODAL_SWITCH_ROTATE:
|
||||
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL, event);
|
||||
event_code = VIEW_CONFIRM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event->type == MOUSEMOVE) {
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
else if (event->type == TIMER) {
|
||||
if (event->customdata == vod->timer) {
|
||||
/* Continuous zoom. */
|
||||
event_code = VIEW_APPLY;
|
||||
}
|
||||
}
|
||||
else if (event->type == vod->init.event_type) {
|
||||
if (event->val == KM_RELEASE) {
|
||||
event_code = VIEW_CONFIRM;
|
||||
}
|
||||
}
|
||||
else if (event->type == EVT_ESCKEY) {
|
||||
if (event->val == KM_PRESS) {
|
||||
event_code = VIEW_CANCEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (event_code) {
|
||||
case VIEW_APPLY: {
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
viewzoom_apply(vod,
|
||||
event->xy,
|
||||
(eViewZoom_Style)U.viewzoom,
|
||||
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
||||
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
||||
viewzoom_apply(vod, xy, (eViewZoom_Style)U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
|
||||
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
|
||||
use_autokey = true;
|
||||
}
|
||||
|
@ -423,64 +379,33 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
ret = OPERATOR_CANCELLED;
|
||||
break;
|
||||
}
|
||||
case VIEW_PASS:
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_autokey) {
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
||||
}
|
||||
|
||||
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
|
||||
if (ret & OPERATOR_FINISHED) {
|
||||
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
|
||||
}
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int viewzoom_exec(bContext *C, wmOperator *op)
|
||||
static void view_zoom_apply_step(bContext *C,
|
||||
Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
ScrArea *area,
|
||||
ARegion *region,
|
||||
const int delta,
|
||||
const int zoom_xy[2])
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d;
|
||||
RegionView3D *rv3d;
|
||||
ScrArea *area;
|
||||
ARegion *region;
|
||||
View3D *v3d = area->spacedata.first;
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
bool use_cam_zoom;
|
||||
float dist_range[2];
|
||||
|
||||
const int delta = RNA_int_get(op->ptr, "delta");
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
|
||||
if (op->customdata) {
|
||||
ViewOpsData *vod = op->customdata;
|
||||
|
||||
area = vod->area;
|
||||
region = vod->region;
|
||||
}
|
||||
else {
|
||||
area = CTX_wm_area(C);
|
||||
region = CTX_wm_region(C);
|
||||
}
|
||||
|
||||
v3d = area->spacedata.first;
|
||||
rv3d = region->regiondata;
|
||||
|
||||
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) &&
|
||||
!(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d));
|
||||
|
||||
int zoom_xy_buf[2];
|
||||
const int *zoom_xy = NULL;
|
||||
if (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
|
||||
zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") :
|
||||
region->winx / 2;
|
||||
zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") :
|
||||
region->winy / 2;
|
||||
zoom_xy = zoom_xy_buf;
|
||||
}
|
||||
|
||||
ED_view3d_dist_range_get(v3d, dist_range);
|
||||
|
||||
if (delta < 0) {
|
||||
|
@ -514,73 +439,94 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
|
|||
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
|
||||
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
|
||||
static int viewzoom_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
BLI_assert(op->customdata == NULL);
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
View3D *v3d = area->spacedata.first;
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
|
||||
const int delta = RNA_int_get(op->ptr, "delta");
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
|
||||
int zoom_xy_buf[2];
|
||||
const int *zoom_xy = NULL;
|
||||
const bool do_zoom_to_mouse_pos = (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS));
|
||||
if (do_zoom_to_mouse_pos) {
|
||||
zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") :
|
||||
region->winx / 2;
|
||||
zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") :
|
||||
region->winy / 2;
|
||||
zoom_xy = zoom_xy_buf;
|
||||
}
|
||||
|
||||
view_zoom_apply_step(C, depsgraph, scene, area, region, delta, zoom_xy);
|
||||
ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
int viewzoom_invoke_impl(bContext *C, ViewOpsData *vod, const wmEvent *event, PointerRNA *ptr)
|
||||
{
|
||||
eV3D_OpEvent event_code = ELEM(event->type, MOUSEZOOM, MOUSEPAN) ? VIEW_CONFIRM : VIEW_PASS;
|
||||
|
||||
if (event_code == VIEW_CONFIRM) {
|
||||
int xy[2];
|
||||
|
||||
PropertyRNA *prop;
|
||||
prop = RNA_struct_find_property(ptr, "mx");
|
||||
xy[0] = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : event->xy[0];
|
||||
|
||||
prop = RNA_struct_find_property(ptr, "my");
|
||||
xy[1] = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : event->xy[1];
|
||||
|
||||
const int delta = RNA_int_get(ptr, "delta");
|
||||
if (delta) {
|
||||
const bool do_zoom_to_mouse_pos = (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) != 0;
|
||||
view_zoom_apply_step(C,
|
||||
vod->depsgraph,
|
||||
vod->scene,
|
||||
vod->area,
|
||||
vod->region,
|
||||
delta,
|
||||
do_zoom_to_mouse_pos ? xy : NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
if (U.uiflag & USER_ZOOM_HORIZ) {
|
||||
vod->init.event_xy[0] = vod->prev.event_xy[0] = xy[0];
|
||||
}
|
||||
else {
|
||||
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
|
||||
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + xy[0] -
|
||||
event->prev_xy[0];
|
||||
}
|
||||
viewzoom_apply(vod, event->prev_xy, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0);
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
if (U.viewzoom == USER_ZOOM_CONTINUE) {
|
||||
/* needs a timer to continue redrawing */
|
||||
vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
|
||||
vod->prev.time = PIL_check_seconds_timer();
|
||||
}
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
/* viewdolly_invoke() copied this function, changes here may apply there */
|
||||
static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ViewOpsData *vod;
|
||||
|
||||
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
|
||||
|
||||
vod = op->customdata = viewops_data_create(
|
||||
C,
|
||||
event,
|
||||
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
|
||||
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
|
||||
|
||||
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
|
||||
|
||||
/* if one or the other zoom position aren't set, set from event */
|
||||
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
|
||||
RNA_int_set(op->ptr, "mx", event->xy[0]);
|
||||
RNA_int_set(op->ptr, "my", event->xy[1]);
|
||||
}
|
||||
|
||||
if (RNA_struct_property_is_set(op->ptr, "delta")) {
|
||||
viewzoom_exec(C, op);
|
||||
}
|
||||
else {
|
||||
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
|
||||
|
||||
if (U.uiflag & USER_ZOOM_HORIZ) {
|
||||
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0];
|
||||
}
|
||||
else {
|
||||
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
|
||||
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] -
|
||||
event->prev_xy[0];
|
||||
}
|
||||
viewzoom_apply(vod,
|
||||
event->prev_xy,
|
||||
USER_ZOOM_DOLLY,
|
||||
(U.uiflag & USER_ZOOM_INVERT) != 0,
|
||||
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
|
||||
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
|
||||
|
||||
viewops_data_free(C, op->customdata);
|
||||
op->customdata = NULL;
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
if (U.viewzoom == USER_ZOOM_CONTINUE) {
|
||||
/* needs a timer to continue redrawing */
|
||||
vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
|
||||
vod->prev.time = PIL_check_seconds_timer();
|
||||
}
|
||||
|
||||
/* add temp handler */
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
return OPERATOR_FINISHED;
|
||||
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_ZOOM);
|
||||
}
|
||||
|
||||
void VIEW3D_OT_zoom(wmOperatorType *ot)
|
||||
|
@ -588,12 +534,12 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
|
|||
/* identifiers */
|
||||
ot->name = "Zoom View";
|
||||
ot->description = "Zoom in/out in the view";
|
||||
ot->idname = "VIEW3D_OT_zoom";
|
||||
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_ZOOM);
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = viewzoom_invoke;
|
||||
ot->exec = viewzoom_exec;
|
||||
ot->modal = viewzoom_modal;
|
||||
ot->modal = view3d_navigate_modal_fn;
|
||||
ot->poll = view3d_zoom_or_dolly_poll;
|
||||
ot->cancel = view3d_navigate_cancel_fn;
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ class OptionalOutputsFunction : public MultiFunction {
|
|||
{
|
||||
if (params.single_output_is_required(0, "Out 1")) {
|
||||
MutableSpan<int> values = params.uninitialized_single_output<int>(0, "Out 1");
|
||||
values.fill_indices(mask, 5);
|
||||
values.fill_indices(mask.indices(), 5);
|
||||
}
|
||||
MutableSpan<std::string> values = params.uninitialized_single_output<std::string>(1, "Out 2");
|
||||
for (const int i : mask) {
|
||||
|
|
|
@ -518,8 +518,9 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
};
|
||||
|
||||
auto catmull_rom_to_nurbs = [&](IndexMask selection) {
|
||||
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
|
||||
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
|
||||
dst_curves.nurbs_orders_for_write().fill_indices(selection.indices(), 4);
|
||||
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection.indices(),
|
||||
NURBS_KNOT_MODE_BEZIER);
|
||||
fill_weights_if_necessary(selection);
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
|
@ -544,7 +545,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
};
|
||||
|
||||
auto poly_to_nurbs = [&](IndexMask selection) {
|
||||
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
|
||||
dst_curves.nurbs_orders_for_write().fill_indices(selection.indices(), 4);
|
||||
bke::curves::copy_point_data(
|
||||
src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
|
||||
fill_weights_if_necessary(selection);
|
||||
|
@ -553,7 +554,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
* start/end. */
|
||||
if (src_cyclic.is_single()) {
|
||||
dst_curves.nurbs_knots_modes_for_write().fill_indices(
|
||||
selection,
|
||||
selection.indices(),
|
||||
src_cyclic.get_internal_single() ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT);
|
||||
}
|
||||
else {
|
||||
|
@ -576,8 +577,9 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
const Span<float3> src_handles_l = src_curves.handle_positions_left();
|
||||
const Span<float3> src_handles_r = src_curves.handle_positions_right();
|
||||
|
||||
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
|
||||
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
|
||||
dst_curves.nurbs_orders_for_write().fill_indices(selection.indices(), 4);
|
||||
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection.indices(),
|
||||
NURBS_KNOT_MODE_BEZIER);
|
||||
fill_weights_if_necessary(selection);
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
|
|
|
@ -1065,7 +1065,7 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
|
|||
else {
|
||||
/* Only trimmed curves are no longer cyclic. */
|
||||
if (bke::SpanAttributeWriter cyclic = dst_attributes.lookup_for_write_span<bool>("cyclic")) {
|
||||
cyclic.span.fill_indices(selection, false);
|
||||
cyclic.span.fill_indices(selection.indices(), false);
|
||||
cyclic.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -962,16 +962,18 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
|
|||
|
||||
/**
|
||||
* Pack islands using a mix of other strategies.
|
||||
* \param islands: The islands to be packed. Will be modified with results.
|
||||
* \param islands: The islands to be packed.
|
||||
* \param scale: Scale islands by `scale` before packing.
|
||||
* \param margin: Add `margin` units around islands before packing.
|
||||
* \param params: Additional parameters. Scale and margin information is ignored.
|
||||
* \param r_phis: Island layout information will be written here.
|
||||
* \return Size of square covering the resulting packed UVs. The maximum `u` or `v` co-ordinate.
|
||||
*/
|
||||
static float pack_islands_scale_margin(const Span<PackIsland *> islands,
|
||||
const float scale,
|
||||
const float margin,
|
||||
const UVPackIsland_Params ¶ms)
|
||||
const UVPackIsland_Params ¶ms,
|
||||
MutableSpan<uv_phi> r_phis)
|
||||
{
|
||||
/* #BLI_box_pack_2d produces layouts with high packing efficiency, but has `O(n^3)`
|
||||
* time complexity, causing poor performance if there are lots of islands. See: #102843.
|
||||
|
@ -988,8 +990,6 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
|
|||
* - Call #pack_islands_alpaca_* on the remaining islands.
|
||||
*/
|
||||
|
||||
blender::Array<uv_phi> phis(islands.size());
|
||||
|
||||
/* First, copy information from our input into the AABB structure. */
|
||||
Array<UVAABBIsland *> aabbs(islands.size());
|
||||
for (const int64_t i : islands.index_range()) {
|
||||
|
@ -1056,7 +1056,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
|
|||
scale,
|
||||
margin,
|
||||
params,
|
||||
phis.as_mutable_span(),
|
||||
r_phis,
|
||||
&max_u,
|
||||
&max_v);
|
||||
break;
|
||||
|
@ -1066,7 +1066,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
|
|||
scale,
|
||||
margin,
|
||||
params.target_aspect_y,
|
||||
phis.as_mutable_span(),
|
||||
r_phis,
|
||||
&max_u,
|
||||
&max_v);
|
||||
break;
|
||||
|
@ -1076,25 +1076,11 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
|
|||
|
||||
/* Call Alpaca. */
|
||||
if (params.rotate) {
|
||||
pack_islands_alpaca_rotate(max_box_pack,
|
||||
aabbs.as_mutable_span(),
|
||||
params.target_aspect_y,
|
||||
phis.as_mutable_span(),
|
||||
&max_u,
|
||||
&max_v);
|
||||
pack_islands_alpaca_rotate(
|
||||
max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v);
|
||||
}
|
||||
else {
|
||||
pack_islands_alpaca_turbo(max_box_pack,
|
||||
aabbs.as_mutable_span(),
|
||||
params.target_aspect_y,
|
||||
phis.as_mutable_span(),
|
||||
&max_u,
|
||||
&max_v);
|
||||
}
|
||||
|
||||
/* Write back UVs. */
|
||||
for (int64_t i = 0; i < aabbs.size(); i++) {
|
||||
islands[i]->place_(scale, phis[i]);
|
||||
pack_islands_alpaca_turbo(max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v);
|
||||
}
|
||||
|
||||
return std::max(max_u / params.target_aspect_y, max_v);
|
||||
|
@ -1103,7 +1089,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
|
|||
/** Find the optimal scale to pack islands into the unit square.
|
||||
* returns largest scale that will pack `islands` into the unit square.
|
||||
*/
|
||||
static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vector,
|
||||
static float pack_islands_margin_fraction(const Span<PackIsland *> &islands,
|
||||
const float margin_fraction,
|
||||
const UVPackIsland_Params ¶ms)
|
||||
{
|
||||
|
@ -1118,7 +1104,10 @@ static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vecto
|
|||
float value_low = 0.0f;
|
||||
float scale_high = 0.0f;
|
||||
float value_high = 0.0f;
|
||||
float scale_last = 0.0f;
|
||||
|
||||
blender::Array<uv_phi> phis_a(islands.size());
|
||||
blender::Array<uv_phi> phis_b(islands.size());
|
||||
blender::Array<uv_phi> *phis_low = nullptr;
|
||||
|
||||
/* Scaling smaller than `min_scale_roundoff` is unlikely to fit and
|
||||
* will destroy information in existing UVs. */
|
||||
|
@ -1166,19 +1155,23 @@ static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vecto
|
|||
/* Modified binary-search to improve robustness. */
|
||||
scale = sqrtf(scale * sqrtf(scale_low * scale_high));
|
||||
}
|
||||
|
||||
BLI_assert(scale_low < scale);
|
||||
BLI_assert(scale < scale_high);
|
||||
}
|
||||
|
||||
scale = std::max(scale, min_scale_roundoff);
|
||||
|
||||
/* Evaluate our `f`. */
|
||||
scale_last = scale;
|
||||
blender::Array<uv_phi> *phis_target = (phis_low == &phis_a) ? &phis_b : &phis_a;
|
||||
const float max_uv = pack_islands_scale_margin(
|
||||
island_vector, scale_last, margin_fraction, params);
|
||||
islands, scale, margin_fraction, params, *phis_target);
|
||||
const float value = sqrtf(max_uv) - 1.0f;
|
||||
|
||||
if (value <= 0.0f) {
|
||||
scale_low = scale;
|
||||
value_low = value;
|
||||
phis_low = phis_target;
|
||||
}
|
||||
else {
|
||||
scale_high = scale;
|
||||
|
@ -1188,28 +1181,25 @@ static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vecto
|
|||
scale_low = scale;
|
||||
break;
|
||||
}
|
||||
if (!phis_low) {
|
||||
phis_low = phis_target; /* May as well do "something", even if it's wrong. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool flush = true;
|
||||
if (flush) {
|
||||
if (phis_low) {
|
||||
/* Write back best pack as a side-effect. */
|
||||
if (scale_last != scale_low) {
|
||||
scale_last = scale_low;
|
||||
const float max_uv = pack_islands_scale_margin(
|
||||
island_vector, scale_last, margin_fraction, params);
|
||||
BLI_assert(max_uv == value_low);
|
||||
UNUSED_VARS(max_uv);
|
||||
/* TODO (?): `if (max_uv < 1.0f) { scale_last /= max_uv; }` */
|
||||
for (const int64_t i : islands.index_range()) {
|
||||
islands[i]->place_(scale_low, (*phis_low)[i]);
|
||||
}
|
||||
}
|
||||
return scale_last;
|
||||
return scale_low;
|
||||
}
|
||||
|
||||
static float calc_margin_from_aabb_length_sum(const Span<PackIsland *> &island_vector,
|
||||
const UVPackIsland_Params ¶ms)
|
||||
{
|
||||
/* Logic matches behavior from #geometry::uv_parametrizer_pack.
|
||||
/* Logic matches previous behavior from #geometry::uv_parametrizer_pack.
|
||||
* Attempt to give predictable results not dependent on current UV scale by using
|
||||
* `aabb_length_sum` (was "`area`") to multiply the margin by the length (was "area"). */
|
||||
double aabb_length_sum = 0.0f;
|
||||
|
@ -1361,21 +1351,22 @@ void pack_islands(const Span<PackIsland *> &islands,
|
|||
const UVPackIsland_Params ¶ms,
|
||||
float r_scale[2])
|
||||
{
|
||||
BLI_assert(0.0f <= params.margin);
|
||||
BLI_assert(0.0f <= params.target_aspect_y);
|
||||
|
||||
if (islands.size() == 0) {
|
||||
r_scale[0] = 1.0f;
|
||||
r_scale[1] = 1.0f;
|
||||
return; /* Nothing to do, just create a safe default. */
|
||||
}
|
||||
|
||||
if (params.merge_overlap) {
|
||||
return OverlapMerger::pack_islands_overlap(islands, params, r_scale);
|
||||
}
|
||||
|
||||
finalize_geometry(islands, params);
|
||||
|
||||
if (params.margin == 0.0f) {
|
||||
/* Special case for zero margin. Margin_method is ignored as all formulas give same result. */
|
||||
const float max_uv = pack_islands_scale_margin(islands, 1.0f, 0.0f, params);
|
||||
r_scale[0] = 1.0f / max_uv;
|
||||
r_scale[1] = r_scale[0];
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.margin_method == ED_UVPACK_MARGIN_FRACTION) {
|
||||
if (params.margin_method == ED_UVPACK_MARGIN_FRACTION && params.margin > 0.0f) {
|
||||
/* Uses a line search on scale. ~10x slower than other method. */
|
||||
const float scale = pack_islands_margin_fraction(islands, params.margin, params);
|
||||
r_scale[0] = scale;
|
||||
|
@ -1390,14 +1381,20 @@ void pack_islands(const Span<PackIsland *> &islands,
|
|||
case ED_UVPACK_MARGIN_SCALED: /* Default for Blender 3.3 and later. */
|
||||
margin = calc_margin_from_aabb_length_sum(islands, params);
|
||||
break;
|
||||
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
|
||||
BLI_assert_unreachable(); /* Handled above. */
|
||||
case ED_UVPACK_MARGIN_FRACTION: /* Added as an option in Blender 3.4. */
|
||||
BLI_assert(params.margin == 0.0f); /* Other (slower) cases are handled above. */
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
const float max_uv = pack_islands_scale_margin(islands, 1.0f, margin, params);
|
||||
blender::Array<uv_phi> phis(islands.size());
|
||||
|
||||
const float scale = 1.0f;
|
||||
const float max_uv = pack_islands_scale_margin(islands, scale, margin, params, phis);
|
||||
for (const int64_t i : islands.index_range()) {
|
||||
islands[i]->place_(scale, phis[i]);
|
||||
}
|
||||
r_scale[0] = 1.0f / max_uv;
|
||||
r_scale[1] = r_scale[0];
|
||||
}
|
||||
|
|
|
@ -158,6 +158,18 @@ if(WITH_IMAGE_WEBP)
|
|||
add_definitions(-DWITH_WEBP)
|
||||
endif()
|
||||
|
||||
if(WITH_TBB)
|
||||
add_definitions(-DWITH_TBB)
|
||||
|
||||
list(APPEND INC_SYS
|
||||
${TBB_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
list(APPEND LIB
|
||||
${TBB_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND INC
|
||||
../../../intern/opencolorio
|
||||
)
|
||||
|
|
|
@ -139,9 +139,14 @@ static int an_stringdec(const char *string, char *head, char *tail, ushort *numl
|
|||
return true;
|
||||
}
|
||||
|
||||
static void an_stringenc(char *string, const char *head, const char *tail, ushort numlen, int pic)
|
||||
static void an_stringenc(char *string,
|
||||
const size_t string_maxncpy,
|
||||
const char *head,
|
||||
const char *tail,
|
||||
ushort numlen,
|
||||
int pic)
|
||||
{
|
||||
BLI_path_sequence_encode(string, head, tail, numlen, pic);
|
||||
BLI_path_sequence_encode(string, string_maxncpy, head, tail, numlen, pic);
|
||||
}
|
||||
|
||||
#ifdef WITH_AVI
|
||||
|
@ -1614,7 +1619,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
|
|||
case ANIM_SEQUENCE:
|
||||
pic = an_stringdec(anim->first, head, tail, &digits);
|
||||
pic += position;
|
||||
an_stringenc(anim->name, head, tail, digits, pic);
|
||||
an_stringenc(anim->name, sizeof(anim->name), head, tail, digits, pic);
|
||||
ibuf = IMB_loadiffname(anim->name, IB_rect, anim->colorspace);
|
||||
if (ibuf) {
|
||||
anim->cur_position = position;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "BLI_linklist.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_memory_utils.hh"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
|
@ -378,6 +379,7 @@ static std::string get_in_memory_texture_filename(Image *ima)
|
|||
|
||||
ImageFormatData imageFormat;
|
||||
BKE_image_format_from_imbuf(&imageFormat, imbuf);
|
||||
BKE_image_release_ibuf(ima, imbuf, nullptr);
|
||||
|
||||
char file_name[FILE_MAX];
|
||||
/* Use the image name for the file name. */
|
||||
|
@ -405,6 +407,7 @@ static void export_in_memory_texture(Image *ima,
|
|||
}
|
||||
|
||||
ImBuf *imbuf = BKE_image_acquire_ibuf(ima, nullptr, nullptr);
|
||||
BLI_SCOPED_DEFER([&]() { BKE_image_release_ibuf(ima, imbuf, nullptr); });
|
||||
if (!imbuf) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -519,7 +519,10 @@ static std::string float3_to_string(const float3 &numbers)
|
|||
MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false)
|
||||
{
|
||||
mtl_filepath_ = obj_filepath;
|
||||
const bool ok = BLI_path_extension_replace(mtl_filepath_.data(), FILE_MAX, ".mtl");
|
||||
/* It only makes sense to replace this extension if it's at least as long as the existing one. */
|
||||
BLI_assert(strlen(BLI_path_extension(obj_filepath)) == 4);
|
||||
const bool ok = BLI_path_extension_replace(
|
||||
mtl_filepath_.data(), mtl_filepath_.size() + 1, ".mtl");
|
||||
if (!ok) {
|
||||
throw std::system_error(ENAMETOOLONG, std::system_category(), "");
|
||||
}
|
||||
|
|
|
@ -155,8 +155,8 @@ static std::string get_image_filepath(const bNode *tex_node)
|
|||
char head[FILE_MAX], tail[FILE_MAX];
|
||||
ushort numlen;
|
||||
int framenr = static_cast<NodeTexImage *>(tex_node->storage)->iuser.framenr;
|
||||
BLI_path_sequence_decode(path, head, tail, &numlen);
|
||||
BLI_path_sequence_encode(path, head, tail, numlen, framenr);
|
||||
BLI_path_sequence_decode(path, head, sizeof(head), tail, sizeof(tail), &numlen);
|
||||
BLI_path_sequence_encode(path, sizeof(path), head, tail, numlen, framenr);
|
||||
}
|
||||
|
||||
return path;
|
||||
|
|
|
@ -279,7 +279,8 @@ class obj_exporter_regression_test : public obj_exporter_test {
|
|||
strncpy(params.filepath, out_file_path.c_str(), FILE_MAX - 1);
|
||||
params.blen_filepath = bfile->main->filepath;
|
||||
std::string golden_file_path = blender::tests::flags_test_asset_dir() + SEP_STR + golden_obj;
|
||||
BLI_split_dir_part(golden_file_path.c_str(), params.file_base_for_tests, PATH_MAX);
|
||||
BLI_split_dir_part(
|
||||
golden_file_path.c_str(), params.file_base_for_tests, sizeof(params.file_base_for_tests));
|
||||
export_frame(depsgraph, params, out_file_path.c_str());
|
||||
std::string output_str = read_temp_file_in_string(out_file_path);
|
||||
|
||||
|
|
|
@ -687,10 +687,12 @@ typedef struct FluidDomainSettings {
|
|||
int viewsettings;
|
||||
char _pad12[4]; /* Unused. */
|
||||
|
||||
/* Pointcache options. */
|
||||
/* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading
|
||||
* old files. */
|
||||
struct PointCache *point_cache[2]; /* Definition is in DNA_object_force_types.h. */
|
||||
/**
|
||||
* Point-cache options.
|
||||
* Smoke uses only one cache from now on (index [0]),
|
||||
* but keeping the array for now for reading old files.
|
||||
*/
|
||||
struct PointCache *point_cache[2];
|
||||
struct ListBase ptcaches[2];
|
||||
int cache_comp;
|
||||
int cache_high_comp;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue