WIP: Brush assets project #106303
|
@ -214,8 +214,10 @@ int Cache::addChannel(const void *device, const char *name, unsigned int maxItem
|
|||
entry = new CacheEntry();
|
||||
if (entry == NULL)
|
||||
return -1;
|
||||
if (!m_cache.insert(CacheMap::value_type(device,entry)).second)
|
||||
if (!m_cache.insert(CacheMap::value_type(device,entry)).second) {
|
||||
delete entry;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
entry = it->second;
|
||||
}
|
||||
|
|
|
@ -674,7 +674,7 @@ const bTheme U_theme_default = {
|
|||
.meta = RGBA(0x5b4d91ff),
|
||||
.text_strip = RGBA(0x824c8fff),
|
||||
.color_strip = RGBA(0x8f8f8fff),
|
||||
.active_strip = RGBA(0xd9d9d9ff),
|
||||
.active_strip = RGBA(0xffffffff),
|
||||
.selected_strip = RGBA(0xff8f0dff),
|
||||
.gp_vertex_size = 3,
|
||||
.gp_vertex_select = RGBA(0xff8500ff),
|
||||
|
|
|
@ -823,7 +823,7 @@
|
|||
meta_strip="#5b4d91"
|
||||
mask_strip="#8f5656"
|
||||
text_strip="#824c8f"
|
||||
active_strip="#d9d9d9"
|
||||
active_strip="#ffffff"
|
||||
selected_strip="#ff6a00"
|
||||
frame_current="#5680c2"
|
||||
time_scrub_background="#292929e6"
|
||||
|
|
|
@ -175,21 +175,23 @@ class DATA_PT_EEVEE_light_influence(DataButtonsPanel, Panel):
|
|||
light = context.light
|
||||
layout.use_property_split = True
|
||||
|
||||
col = layout.column()
|
||||
col.active = ob.visible_diffuse
|
||||
col.prop(light, "diffuse_factor", text="Diffuse")
|
||||
col = layout.column(align=True)
|
||||
|
||||
col = layout.column()
|
||||
col.active = ob.visible_glossy
|
||||
col.prop(light, "specular_factor", text="Glossy")
|
||||
sub = col.column(align=True)
|
||||
sub.active = ob.visible_diffuse
|
||||
sub.prop(light, "diffuse_factor", text="Diffuse")
|
||||
|
||||
col = layout.column()
|
||||
col.active = ob.visible_transmission
|
||||
col.prop(light, "transmission_factor", text="Transmission")
|
||||
sub = col.column(align=True)
|
||||
sub.active = ob.visible_glossy
|
||||
sub.prop(light, "specular_factor", text="Glossy")
|
||||
|
||||
col = layout.column()
|
||||
col.active = ob.visible_volume_scatter
|
||||
col.prop(light, "volume_factor", text="Volume Scatter", text_ctxt=i18n_contexts.id_id)
|
||||
sub = col.column(align=True)
|
||||
sub.active = ob.visible_transmission
|
||||
sub.prop(light, "transmission_factor", text="Transmission")
|
||||
|
||||
sub = col.column(align=True)
|
||||
sub.active = ob.visible_volume_scatter
|
||||
sub.prop(light, "volume_factor", text="Volume Scatter", text_ctxt=i18n_contexts.id_id)
|
||||
|
||||
|
||||
class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
|
||||
|
|
|
@ -313,7 +313,7 @@ class EEVEE_NEXT_MATERIAL_PT_settings_surface(MaterialButtonsPanel, Panel):
|
|||
if mat.surface_render_method == 'BLENDED':
|
||||
col.prop(mat, "show_transparent_back", text="Transparency Overlap")
|
||||
elif mat.surface_render_method == 'DITHERED':
|
||||
col.prop(mat, "use_screen_refraction", text="Raytraced Refraction")
|
||||
col.prop(mat, "use_screen_refraction", text="Raytraced Transmission")
|
||||
|
||||
col = layout.column(heading="Light Probe Volume")
|
||||
col.prop(mat, "lightprobe_volume_single_sided", text="Single Sided")
|
||||
|
|
|
@ -123,16 +123,16 @@ class Animation : public ::Animation {
|
|||
|
||||
/** Assign this animation to the ID.
|
||||
*
|
||||
* \param binding The binding this ID should be animated by, may be nullptr if it is to be
|
||||
* \param binding: The binding this ID should be animated by, may be nullptr if it is to be
|
||||
* assigned later. In that case, the ID will not actually receive any animation.
|
||||
* \param animated_id The ID that should be animated by this Animation data-block.
|
||||
* \param animated_id: The ID that should be animated by this Animation data-block.
|
||||
*/
|
||||
bool assign_id(Binding *binding, ID &animated_id);
|
||||
|
||||
/**
|
||||
* Unassign this Animation from the animated ID.
|
||||
*
|
||||
* \param animated_id ID that is animated by this Animation. Calling this
|
||||
* \param animated_id: ID that is animated by this Animation. Calling this
|
||||
* function when this ID is _not_ animated by this Animation is not allowed,
|
||||
* and considered a bug.
|
||||
*/
|
||||
|
|
|
@ -50,7 +50,7 @@ BoneCollection *ANIM_bonecoll_new(const char *name) ATTR_WARN_UNUSED_RESULT;
|
|||
*
|
||||
* \see ANIM_armature_bonecoll_remove
|
||||
*
|
||||
* \param do_id_user_count whether to update user counts for IDs referenced from IDProperties of
|
||||
* \param do_id_user_count: Whether to update user counts for IDs referenced from IDProperties of
|
||||
* the bone collection. Needs to be false when freeing an evaluated copy, true otherwise.
|
||||
*/
|
||||
void ANIM_bonecoll_free(BoneCollection *bcoll, bool do_id_user_count = true);
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace blender::animrig {
|
|||
*
|
||||
* Animate the given ID, using the animation data-block and the given binding.
|
||||
*
|
||||
* \param flush_to_original when true, look up the original data-block (assuming
|
||||
* \param flush_to_original: when true, look up the original data-block (assuming
|
||||
* the given one is an evaluated copy) and update that too.
|
||||
*/
|
||||
void evaluate_and_apply_animation(PointerRNA &animated_id_ptr,
|
||||
|
|
|
@ -231,8 +231,8 @@ bool autokeyframe_property(bContext *C,
|
|||
* expected to be the size of the property array.
|
||||
* \param frame: is expected to be in the local time of the action, meaning it has to be NLA mapped
|
||||
* already.
|
||||
* \param keying_mask is expected to have the same size as `rna_path`. A false bit means that index
|
||||
* will be skipped.
|
||||
* \param keying_mask: is expected to have the same size as `rna_path`.
|
||||
* A false bit means that index will be skipped.
|
||||
* \returns How often keyframe insertion was successful and how often it failed / for which reason.
|
||||
*/
|
||||
CombinedKeyingResult insert_key_action(Main *bmain,
|
||||
|
|
|
@ -28,7 +28,7 @@ EvaluationResult blend_layer_results(const EvaluationResult &last_result,
|
|||
/**
|
||||
* Apply the result of the animation evaluation to the given data-block.
|
||||
*
|
||||
* \param flush_to_original when true, look up the original data-block (assuming the given one is
|
||||
* \param flush_to_original: when true, look up the original data-block (assuming the given one is
|
||||
* an evaluated copy) and update that too.
|
||||
*/
|
||||
void apply_evaluation_result(const EvaluationResult &evaluation_result,
|
||||
|
|
|
@ -100,7 +100,7 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, int flag);
|
|||
/**
|
||||
* Same as #BKE_animdata_copy, but allows to duplicate Action IDs into a library.
|
||||
*
|
||||
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* \param owner_library: the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* not use any library (i.e. become a local ID). Use `std::nullopt` for default behavior (i.e.
|
||||
* behavior of the #BKE_animdata_copy function).
|
||||
*/
|
||||
|
|
|
@ -64,7 +64,7 @@ void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
|
|||
* The user count is set to 1, all other content (apart from name and links) being
|
||||
* initialized to zero.
|
||||
*
|
||||
* \note: By default, IDs allocated in a Main database will get the current library of the Main,
|
||||
* \note By default, IDs allocated in a Main database will get the current library of the Main,
|
||||
* i.e. usually (besides in readfile case), they will have a `nullptr` `lib` pointer and be local
|
||||
* data. IDs allocated outside of a Main database will always get a `nullptr` `lib` pointer.
|
||||
*/
|
||||
|
@ -73,7 +73,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag)
|
|||
/**
|
||||
* Same as for #BKE_libblock_alloc, but allows creating a data-block for a given owner library.
|
||||
*
|
||||
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* \param owner_library: the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* not use any library (i.e. become a local ID). Use `std::nullopt` for default behavior (i.e.
|
||||
* behavior of the #BKE_libblock_alloc function).
|
||||
*/
|
||||
|
@ -120,7 +120,7 @@ void BKE_lib_libblock_session_uid_renew(ID *id);
|
|||
/**
|
||||
* Generic helper to create a new empty data-block of given type in given \a bmain database.
|
||||
*
|
||||
* \note: By default, IDs created in a Main database will get the current library of the Main,
|
||||
* \note By default, IDs created in a Main database will get the current library of the Main,
|
||||
* i.e. usually (besides in readfile case), they will have a `nullptr` `lib` pointer and be local
|
||||
* data. IDs created outside of a Main database will always get a `nullptr` `lib` pointer.
|
||||
*
|
||||
|
@ -130,7 +130,7 @@ void *BKE_id_new(Main *bmain, short type, const char *name);
|
|||
/**
|
||||
* Same as for #BKE_id_new, but allows creating a data-block for (within) a given owner library.
|
||||
*
|
||||
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* \param owner_library: the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* not use any library (i.e. become a local ID). Use `std::nullopt` for default behavior (i.e.
|
||||
* behavior of the #BKE_id_new function).
|
||||
*/
|
||||
|
@ -223,7 +223,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int orig_flag
|
|||
* Same as #BKE_libblock_copy_ex, but allows copying data into a library, and not as local data
|
||||
* only.
|
||||
*
|
||||
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* \param owner_library: the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* not use any library (i.e. become a local ID). Use std::nullopt for default behavior (i.e.
|
||||
* behavior of the #BKE_libblock_copy_ex function).
|
||||
*/
|
||||
|
@ -501,7 +501,7 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag);
|
|||
*
|
||||
* See #BKE_id_copy_ex for details.
|
||||
*
|
||||
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* \param owner_library: the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
|
||||
* not use any library (i.e. become a local ID). Use std::nullopt for default behavior (i.e.
|
||||
* behavior of the #BKE_id_copy_ex function).
|
||||
*/
|
||||
|
|
|
@ -348,21 +348,21 @@ struct LibQueryUnusedIDsData {
|
|||
* Amount of detected as unused data-blocks, per type and total as the last value of the array
|
||||
* (#INDEX_ID_NULL).
|
||||
*
|
||||
* \note: Return value, set by the executed function.
|
||||
* \note Return value, set by the executed function.
|
||||
*/
|
||||
std::array<int, INDEX_ID_MAX> num_total;
|
||||
/**
|
||||
* Amount of detected as unused local data-blocks, per type and total as the last value of the
|
||||
* array (#INDEX_ID_NULL).
|
||||
*
|
||||
* \note: Return value, set by the executed function.
|
||||
* \note Return value, set by the executed function.
|
||||
*/
|
||||
std::array<int, INDEX_ID_MAX> num_local;
|
||||
/**
|
||||
* Amount of detected as unused linked data-blocks, per type and total as the last value of the
|
||||
* array (#INDEX_ID_NULL).
|
||||
*
|
||||
* \note: Return value, set by the executed function.
|
||||
* \note Return value, set by the executed function.
|
||||
*/
|
||||
std::array<int, INDEX_ID_MAX> num_linked;
|
||||
};
|
||||
|
|
|
@ -139,7 +139,7 @@ struct Main {
|
|||
/** The currently opened .blend file was written from a newer version of Blender, and has forward
|
||||
* compatibility issues (data loss).
|
||||
*
|
||||
* \note: In practice currently this is only based on the version numbers, in the future it
|
||||
* \note In practice currently this is only based on the version numbers, in the future it
|
||||
* could try to use more refined detection on load. */
|
||||
bool has_forward_compatibility_issues;
|
||||
|
||||
|
|
|
@ -511,7 +511,7 @@ void BKE_nla_tweakmode_clear_flags(struct AnimData *adt);
|
|||
* the Action.
|
||||
*
|
||||
* This function just writes to the AnimData-owned data. It is intended to be
|
||||
* used in blendfile reading code, which performs a reference count later
|
||||
* used in blend-file reading code, which performs a reference count later
|
||||
* anyway.
|
||||
*/
|
||||
void BKE_nla_tweakmode_exit_nofollowptr(AnimData *adt);
|
||||
|
@ -559,8 +559,8 @@ void BKE_nla_liboverride_post_process(ID *id, struct AnimData *adt);
|
|||
/**
|
||||
* Print the ADT flags, NLA tracks, strips, their flags, and other info, to the console.
|
||||
*
|
||||
* \param adt the ADT to show. If NULL, it will be determined from owner_id.
|
||||
* \param owner_id the ID that owns this ADT. If given, its name will be printed in the console
|
||||
* \param adt: the ADT to show. If NULL, it will be determined from owner_id.
|
||||
* \param owner_id: the ID that owns this ADT. If given, its name will be printed in the console
|
||||
* output. If NULL, that won't happen.
|
||||
*
|
||||
* Either of the parameters can be NULL, but not both.
|
||||
|
|
|
@ -220,13 +220,12 @@ void draw_cb(const Mesh &mesh,
|
|||
const PBVHFrustumPlanes &draw_frustum,
|
||||
FunctionRef<void(draw::pbvh::PBVHBatches *batches,
|
||||
const draw::pbvh::PBVH_GPU_Args &args)> draw_fn);
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
/**
|
||||
* Get the PBVH root's bounding box.
|
||||
*/
|
||||
blender::Bounds<blender::float3> BKE_pbvh_bounding_box(const PBVH *pbvh);
|
||||
Bounds<float3> bounds_get(const PBVH &pbvh);
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh);
|
||||
|
||||
|
@ -296,15 +295,14 @@ bool BKE_pbvh_node_fully_unmasked_get(const PBVHNode *node);
|
|||
|
||||
void BKE_pbvh_mark_rebuild_pixels(PBVH *pbvh);
|
||||
|
||||
blender::Span<int> BKE_pbvh_node_get_grid_indices(const PBVHNode &node);
|
||||
|
||||
int BKE_pbvh_node_num_unique_verts(const PBVH &pbvh, const PBVHNode &node);
|
||||
blender::Span<int> BKE_pbvh_node_get_vert_indices(const PBVHNode *node);
|
||||
blender::Span<int> BKE_pbvh_node_get_unique_vert_indices(const PBVHNode *node);
|
||||
blender::Span<int> BKE_pbvh_node_get_corner_indices(const PBVHNode *node);
|
||||
|
||||
namespace blender::bke::pbvh {
|
||||
|
||||
Span<int> node_grid_indices(const PBVHNode &node);
|
||||
|
||||
Span<int> node_verts(const PBVHNode &node);
|
||||
Span<int> node_unique_verts(const PBVHNode &node);
|
||||
Span<int> node_corners(const PBVHNode &node);
|
||||
|
||||
/**
|
||||
* Gather the indices of all faces (not triangles) used by the node.
|
||||
* For convenience, pass a reference to the data in the result.
|
||||
|
@ -317,9 +315,10 @@ Span<int> node_face_indices_calc_mesh(const PBVH &pbvh, const PBVHNode &node, Ve
|
|||
*/
|
||||
Span<int> node_face_indices_calc_grids(const PBVH &pbvh, const PBVHNode &node, Vector<int> &faces);
|
||||
|
||||
Bounds<float3> node_bounds(const PBVHNode &node);
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
blender::Bounds<blender::float3> BKE_pbvh_node_get_BB(const PBVHNode *node);
|
||||
blender::Bounds<blender::float3> BKE_pbvh_node_get_original_BB(const PBVHNode *node);
|
||||
|
||||
float BKE_pbvh_node_get_tmin(const PBVHNode *node);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
/**
|
||||
* Initialize a #ReportList struct.
|
||||
*
|
||||
* \note: Not thread-safe, should only be called from the 'owner' thread of the report list.
|
||||
* \note Not thread-safe, should only be called from the 'owner' thread of the report list.
|
||||
*/
|
||||
void BKE_reports_init(ReportList *reports, int flag);
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ void BKE_reports_init(ReportList *reports, int flag);
|
|||
* Also calls #BKE_reports_clear. The given `reports` should not be used anymore unless it is
|
||||
* re-initialized first.
|
||||
*
|
||||
* \note: Not thread-safe, should only be called from the current owner of the report list, once
|
||||
* \note Not thread-safe, should only be called from the current owner of the report list, once
|
||||
* no other concurrent access is possible.
|
||||
*/
|
||||
void BKE_reports_free(ReportList *reports);
|
||||
|
|
|
@ -229,7 +229,7 @@ struct ReuseOldBMainData {
|
|||
/** Data generated and used by calling WM code to handle keeping WM and UI IDs as best as
|
||||
* possible across file reading.
|
||||
*
|
||||
* \note: May be null in undo (memfile) case.. */
|
||||
* \note May be null in undo (memfile) case. */
|
||||
BlendFileReadWMSetupData *wm_setup_data;
|
||||
|
||||
/** Storage for all remapping rules (old_id -> new_id) required by the preservation of old IDs
|
||||
|
|
|
@ -360,7 +360,7 @@ class AnimDataConvertor {
|
|||
/**
|
||||
* Convert relevant FCurves, i.e. modify their RNA path to match destination data.
|
||||
*
|
||||
* \note: Edited FCurves will remain in the source animation data after this process. Once all
|
||||
* \note Edited FCurves will remain in the source animation data after this process. Once all
|
||||
* source animation data has been processed, #fcurves_convert_finalize has to be called.
|
||||
*/
|
||||
void fcurves_convert()
|
||||
|
|
|
@ -1657,14 +1657,18 @@ bool BKE_pbvh_get_color_layer(Mesh *mesh, CustomDataLayer **r_layer, AttrDomain
|
|||
return *r_layer != nullptr;
|
||||
}
|
||||
|
||||
Bounds<float3> BKE_pbvh_bounding_box(const PBVH *pbvh)
|
||||
namespace blender::bke::pbvh {
|
||||
|
||||
Bounds<float3> bounds_get(const PBVH &pbvh)
|
||||
{
|
||||
if (pbvh->nodes.is_empty()) {
|
||||
if (pbvh.nodes.is_empty()) {
|
||||
return float3(0);
|
||||
}
|
||||
return pbvh->nodes.first().vb;
|
||||
return pbvh.nodes.first().vb;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
const CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh)
|
||||
{
|
||||
BLI_assert(pbvh->header.type == PBVH_GRIDS);
|
||||
|
@ -1788,23 +1792,23 @@ bool BKE_pbvh_node_fully_unmasked_get(const PBVHNode *node)
|
|||
return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked);
|
||||
}
|
||||
|
||||
blender::Span<int> BKE_pbvh_node_get_corner_indices(const PBVHNode *node)
|
||||
{
|
||||
return node->corner_indices;
|
||||
}
|
||||
|
||||
blender::Span<int> BKE_pbvh_node_get_vert_indices(const PBVHNode *node)
|
||||
{
|
||||
return node->vert_indices;
|
||||
}
|
||||
|
||||
blender::Span<int> BKE_pbvh_node_get_unique_vert_indices(const PBVHNode *node)
|
||||
{
|
||||
return node->vert_indices.as_span().take_front(node->uniq_verts);
|
||||
}
|
||||
|
||||
namespace blender::bke::pbvh {
|
||||
|
||||
Span<int> node_corners(const PBVHNode &node)
|
||||
{
|
||||
return node.corner_indices;
|
||||
}
|
||||
|
||||
Span<int> node_verts(const PBVHNode &node)
|
||||
{
|
||||
return node.vert_indices;
|
||||
}
|
||||
|
||||
Span<int> node_unique_verts(const PBVHNode &node)
|
||||
{
|
||||
return node.vert_indices.as_span().take_front(node.uniq_verts);
|
||||
}
|
||||
|
||||
Span<int> node_face_indices_calc_mesh(const PBVH &pbvh, const PBVHNode &node, Vector<int> &faces)
|
||||
{
|
||||
faces.clear();
|
||||
|
@ -1835,32 +1839,22 @@ Span<int> node_face_indices_calc_grids(const PBVH &pbvh, const PBVHNode &node, V
|
|||
return faces.as_span();
|
||||
}
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
int BKE_pbvh_node_num_unique_verts(const PBVH &pbvh, const PBVHNode &node)
|
||||
{
|
||||
switch (pbvh.header.type) {
|
||||
case PBVH_GRIDS:
|
||||
return node.prim_indices.size() * pbvh.gridkey.grid_area;
|
||||
case PBVH_FACES:
|
||||
return node.uniq_verts;
|
||||
case PBVH_BMESH:
|
||||
return node.bm_unique_verts.size();
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Span<int> BKE_pbvh_node_get_grid_indices(const PBVHNode &node)
|
||||
Span<int> node_grid_indices(const PBVHNode &node)
|
||||
{
|
||||
return node.prim_indices;
|
||||
}
|
||||
|
||||
Bounds<float3> BKE_pbvh_node_get_BB(const PBVHNode *node)
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
namespace blender::bke::pbvh {
|
||||
|
||||
Bounds<float3> node_bounds(const PBVHNode &node)
|
||||
{
|
||||
return node->vb;
|
||||
return node.vb;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
Bounds<float3> BKE_pbvh_node_get_original_BB(const PBVHNode *node)
|
||||
{
|
||||
return node->orig_vb;
|
||||
|
@ -2279,7 +2273,7 @@ void clip_ray_ortho(
|
|||
bb_root = BKE_pbvh_node_get_original_BB(&pbvh->nodes.first());
|
||||
}
|
||||
else {
|
||||
bb_root = BKE_pbvh_node_get_BB(&pbvh->nodes.first());
|
||||
bb_root = node_bounds(pbvh->nodes.first());
|
||||
}
|
||||
|
||||
/* Calc rough clipping to avoid overflow later. See #109555. */
|
||||
|
@ -2362,7 +2356,6 @@ static bool nearest_to_ray_aabb_dist_sq(PBVHNode *node,
|
|||
bb_max = node->orig_vb.max;
|
||||
}
|
||||
else {
|
||||
/* BKE_pbvh_node_get_BB */
|
||||
bb_min = node->vb.min;
|
||||
bb_max = node->vb.max;
|
||||
}
|
||||
|
@ -2864,7 +2857,18 @@ PBVHProxyNode &BKE_pbvh_node_add_proxy(PBVH &pbvh, PBVHNode &node)
|
|||
* pointers to multiple proxies. */
|
||||
PBVHProxyNode &proxy_node = node.proxies.last();
|
||||
|
||||
const int num_unique_verts = BKE_pbvh_node_num_unique_verts(pbvh, node);
|
||||
int num_unique_verts = 0;
|
||||
switch (pbvh.header.type) {
|
||||
case PBVH_GRIDS:
|
||||
num_unique_verts = node.prim_indices.size() * pbvh.gridkey.grid_area;
|
||||
break;
|
||||
case PBVH_FACES:
|
||||
num_unique_verts = node.uniq_verts;
|
||||
break;
|
||||
case PBVH_BMESH:
|
||||
num_unique_verts = node.bm_unique_verts.size();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Brushes expect proxies to be zero-initialized, so that they can do additive operation to them.
|
||||
*/
|
||||
|
|
|
@ -1188,6 +1188,11 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
|
|||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
BLO_read_data_address(reader, ®ion->regiondata);
|
||||
|
||||
if (region->regiondata == nullptr) {
|
||||
/* To avoid crashing on some old files. */
|
||||
region->regiondata = MEM_cnew<RegionView3D>("region view3d");
|
||||
}
|
||||
|
||||
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
||||
|
||||
BLO_read_data_address(reader, &rv3d->localvd);
|
||||
|
|
|
@ -3090,6 +3090,9 @@ static void link_global(FileData *fd, BlendFileData *bfd)
|
|||
bfd->curscene = bfd->curscreen->scene;
|
||||
}
|
||||
}
|
||||
if (bfd->curscene == nullptr) {
|
||||
bfd->curscene = static_cast<Scene *>(bfd->main->scenes.first);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -95,9 +95,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh &bm, Mesh &mesh, const CustomData_MeshMasks
|
|||
* A version of #BM_mesh_bm_to_me_for_eval but copying data layers and Mesh attributes is optional.
|
||||
* It also allows shape-keys but don't re-assigns shape-key indices.
|
||||
*
|
||||
* \param mask Custom data masks to control which layers are copied.
|
||||
* If nullptr, no layer data is copied.
|
||||
* \param add_mesh_attributes If true, adds mesh attributes during the conversion.
|
||||
* \param mask: Custom data masks to control which layers are copied.
|
||||
* If nullptr, no layer data is copied.
|
||||
* \param add_mesh_attributes: If true, adds mesh attributes during the conversion.
|
||||
*/
|
||||
void BM_mesh_bm_to_me_compact(BMesh &bm,
|
||||
Mesh &mesh,
|
||||
|
|
|
@ -116,7 +116,7 @@ void FileOutputOperation::deinit_execution()
|
|||
const int2 size = int2(get_width(), get_height());
|
||||
if (size == int2(0)) {
|
||||
for (const FileOutputInput &input : file_output_inputs_) {
|
||||
/* Ownership of outputs buffers are transfered to file outputs, so if we are not writing a
|
||||
/* Ownership of outputs buffers are transferred to file outputs, so if we are not writing a
|
||||
* file output, we need to free the output buffer here. */
|
||||
if (input.output_buffer) {
|
||||
MEM_freeN(input.output_buffer);
|
||||
|
@ -143,7 +143,7 @@ void FileOutputOperation::execute_single_layer()
|
|||
for (const FileOutputInput &input : file_output_inputs_) {
|
||||
/* We only write images, not single values. */
|
||||
if (!input.image_input || input.image_input->get_flags().is_constant_operation) {
|
||||
/* Ownership of outputs buffers are transfered to file outputs, so if we are not writing a
|
||||
/* Ownership of outputs buffers are transferred to file outputs, so if we are not writing a
|
||||
* file output, we need to free the output buffer here. */
|
||||
if (input.output_buffer) {
|
||||
MEM_freeN(input.output_buffer);
|
||||
|
@ -236,7 +236,7 @@ void FileOutputOperation::execute_multi_layer()
|
|||
for (const FileOutputInput &input : file_output_inputs_) {
|
||||
/* We only write images, not single values. */
|
||||
if (!input.image_input || input.image_input->get_flags().is_constant_operation) {
|
||||
/* Ownership of outputs buffers are transfered to file outputs, so if we are not writing a
|
||||
/* Ownership of outputs buffers are transferred to file outputs, so if we are not writing a
|
||||
* file output, we need to free the output buffer here. */
|
||||
if (input.output_buffer) {
|
||||
MEM_freeN(input.output_buffer);
|
||||
|
|
|
@ -116,7 +116,7 @@ void Camera::sync()
|
|||
data.winmat = view.winmat();
|
||||
data.type = CAMERA_ORTHO;
|
||||
|
||||
/* \note: Follow camera parameters where distances are positive in front of the camera. */
|
||||
/* \note Follow camera parameters where distances are positive in front of the camera. */
|
||||
data.clip_near = -view.far_clip();
|
||||
data.clip_far = -view.near_clip();
|
||||
data.fisheye_fov = data.fisheye_lens = -1.0f;
|
||||
|
@ -191,7 +191,7 @@ void Camera::sync()
|
|||
is_camera_object_ = true;
|
||||
}
|
||||
else if (inst_.drw_view) {
|
||||
/* \note: Follow camera parameters where distances are positive in front of the camera. */
|
||||
/* \note Follow camera parameters where distances are positive in front of the camera. */
|
||||
data.clip_near = -DRW_view_near_distance_get(inst_.drw_view);
|
||||
data.clip_far = -DRW_view_far_distance_get(inst_.drw_view);
|
||||
data.fisheye_fov = data.fisheye_lens = -1.0f;
|
||||
|
|
|
@ -98,8 +98,14 @@ void LightProbeModule::sync_volume(const Object *ob, ObjectHandle &handle)
|
|||
grid.dilation_radius = lightprobe->grid_dilation_radius;
|
||||
grid.intensity = lightprobe->intensity;
|
||||
|
||||
grid.viewport_display = lightprobe->flag & LIGHTPROBE_FLAG_SHOW_DATA;
|
||||
grid.viewport_display_size = lightprobe->data_display_size;
|
||||
const bool has_valid_cache = grid.cache && grid.cache->grid_static_cache;
|
||||
grid.viewport_display = has_valid_cache && (lightprobe->flag & LIGHTPROBE_FLAG_SHOW_DATA);
|
||||
if (grid.viewport_display) {
|
||||
int3 cache_size = grid.cache->grid_static_cache->size;
|
||||
float3 scale = math::transform_direction(ob->object_to_world(),
|
||||
1.0f / float3(cache_size + 1));
|
||||
grid.viewport_display_size = math::reduce_min(scale) * lightprobe->data_display_size;
|
||||
}
|
||||
|
||||
/* Force reupload. */
|
||||
inst_.volume_probes.bricks_free(grid.bricks);
|
||||
|
@ -154,8 +160,9 @@ void LightProbeModule::sync_sphere(const Object *ob, ObjectHandle &handle)
|
|||
cube.parallax_distance = parallax_distance / influence_distance;
|
||||
cube.clipping_distances = float2(light_probe.clipsta, light_probe.clipend);
|
||||
|
||||
float3 scale = influence_distance * math::to_scale(ob->object_to_world());
|
||||
cube.viewport_display = light_probe.flag & LIGHTPROBE_FLAG_SHOW_DATA;
|
||||
cube.viewport_display_size = light_probe.data_display_size;
|
||||
cube.viewport_display_size = light_probe.data_display_size * math::reduce_add(scale / 3.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -415,7 +415,7 @@ MaterialArray &MaterialModule::material_array_get(Object *ob, bool has_motion)
|
|||
for (auto i : IndexRange(materials_len)) {
|
||||
::Material *blender_mat = material_from_slot(ob, i);
|
||||
Material &mat = material_sync(ob, blender_mat, to_material_geometry(ob), has_motion);
|
||||
/* \note: Perform a whole copy since next material_sync() can move the Material memory location
|
||||
/* \note Perform a whole copy since next material_sync() can move the Material memory location
|
||||
* (i.e: because of its container growing) */
|
||||
material_array_.materials.append(mat);
|
||||
material_array_.gpu_materials.append(mat.shading.gpumat);
|
||||
|
|
|
@ -772,7 +772,7 @@ GPUTexture *DeferredLayer::render(View &main_view,
|
|||
inst_.manager->submit(combine_ps_);
|
||||
|
||||
if (use_feedback_output_ && !use_clamp_direct_) {
|
||||
/* We skip writting the radiance during the combine pass. Do a simple fast copy. */
|
||||
/* We skip writing the radiance during the combine pass. Do a simple fast copy. */
|
||||
GPU_texture_copy(radiance_feedback_tx_, rb.combined_tx);
|
||||
}
|
||||
|
||||
|
|
|
@ -500,7 +500,7 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
|
|||
light.sun.clipmap_base_offset_pos = (offset_vector * (1 << 16)) /
|
||||
max_ii(levels_range.size() - 1, 1);
|
||||
|
||||
/* \note: cascade_level_range starts the range at the unique LOD to apply to all tile-maps. */
|
||||
/* \note cascade_level_range starts the range at the unique LOD to apply to all tile-maps. */
|
||||
int level = levels_range.first();
|
||||
for (int i : IndexRange(levels_range.size())) {
|
||||
ShadowTileMap *tilemap = tilemaps_[i];
|
||||
|
|
|
@ -509,7 +509,7 @@ class ShadowDirectional : public NonCopyable, NonMovable {
|
|||
static float coverage_get(int lvl)
|
||||
{
|
||||
/* This function should be kept in sync with shadow_directional_level(). */
|
||||
/* \note: If we would to introduce a global scaling option it would be here. */
|
||||
/* \note If we would to introduce a global scaling option it would be here. */
|
||||
return exp2(lvl);
|
||||
}
|
||||
|
||||
|
|
|
@ -251,7 +251,7 @@ bool SyncModule::sync_sculpt(Object *ob,
|
|||
|
||||
/* Use a valid bounding box. The PBVH module already does its own culling, but a valid */
|
||||
/* bounding box is still needed for directional shadow tile-map bounds computation. */
|
||||
const Bounds<float3> bounds = BKE_pbvh_bounding_box(ob_ref.object->sculpt->pbvh);
|
||||
const Bounds<float3> bounds = bke::pbvh::bounds_get(*ob_ref.object->sculpt->pbvh);
|
||||
const float3 center = math::midpoint(bounds.min, bounds.max);
|
||||
const float3 half_extent = bounds.max - center + inflate_bounds;
|
||||
inst_.manager->update_handle_bounds(res_handle, center, half_extent);
|
||||
|
|
|
@ -17,7 +17,9 @@ void main()
|
|||
|
||||
vec3 vN = vec3(lP, sqrt(max(0.0, 1.0 - dist_sqr)));
|
||||
vec3 N = drw_normal_view_to_world(vN);
|
||||
vec3 V = drw_world_incident_vector(P);
|
||||
vec3 L = reflect(-V, N);
|
||||
|
||||
out_color = reflection_probes_sample(N, 0, reflection_probe_buf[probe_index].atlas_coord);
|
||||
out_color = reflection_probes_sample(L, 0, reflection_probe_buf[probe_index].atlas_coord);
|
||||
out_color.a = 0.0;
|
||||
}
|
||||
|
|
|
@ -23,14 +23,20 @@ void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmit
|
|||
float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position());
|
||||
vec3 V = drw_world_incident_vector(g_data.P);
|
||||
|
||||
vec3 surface_N = vec3(0.0);
|
||||
bool valid_N = false;
|
||||
ClosureLightStack stack;
|
||||
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT; i++) {
|
||||
stack.cl[i] = closure_light_new(g_closure_get(i), V);
|
||||
ClosureUndetermined cl = g_closure_get(i);
|
||||
if (!valid_N && (cl.weight > 0.0)) {
|
||||
surface_N = cl.N;
|
||||
}
|
||||
stack.cl[i] = closure_light_new(cl, V);
|
||||
}
|
||||
|
||||
/* TODO(fclem): If transmission (no SSS) is present, we could reduce LIGHT_CLOSURE_EVAL_COUNT
|
||||
* by 1 for this evaluation and skip evaluating the transmission closure twice. */
|
||||
light_eval_reflection(stack, g_data.P, g_data.Ng, V, vPz);
|
||||
light_eval_reflection(stack, g_data.P, surface_N, V, vPz);
|
||||
|
||||
#if defined(MAT_SUBSURFACE) || defined(MAT_REFRACTION) || defined(MAT_TRANSLUCENT)
|
||||
|
||||
|
@ -47,7 +53,7 @@ void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmit
|
|||
stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
|
||||
/* Note: Only evaluates `stack.cl[0]`. */
|
||||
light_eval_transmission(stack, g_data.P, g_data.Ng, V, vPz);
|
||||
light_eval_transmission(stack, g_data.P, surface_N, V, vPz);
|
||||
|
||||
# if defined(MAT_SUBSURFACE)
|
||||
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {
|
||||
|
@ -63,7 +69,7 @@ void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmit
|
|||
}
|
||||
#endif
|
||||
|
||||
LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V);
|
||||
LightProbeSample samp = lightprobe_load(g_data.P, surface_N, V);
|
||||
|
||||
float clamp_indirect_sh = uniform_buf.clamp.surface_indirect;
|
||||
samp.volume_irradiance = spherical_harmonics_clamp(samp.volume_irradiance, clamp_indirect_sh);
|
||||
|
|
|
@ -182,7 +182,7 @@ ClosureLight closure_light_new_ex(ClosureUndetermined cl,
|
|||
break;
|
||||
}
|
||||
case CLOSURE_NONE_ID:
|
||||
/* TODO(fclem): Assert. */
|
||||
/* Can happen in forward. */
|
||||
break;
|
||||
}
|
||||
return cl_light;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
|
||||
|
|
|
@ -28,6 +28,8 @@ ReflectionProbeLowFreqLight reflection_probes_extract_low_freq(SphericalHarmonic
|
|||
/* To avoid color shift and negative values, we reduce saturation and directionality. */
|
||||
ReflectionProbeLowFreqLight result;
|
||||
result.ambient = sh.L0.M0.r + sh.L0.M0.g + sh.L0.M0.b;
|
||||
/* Bias to avoid division by zero. */
|
||||
result.ambient += 1e-6f;
|
||||
|
||||
mat3x4 L1_per_band;
|
||||
L1_per_band[0] = sh.L1.Mn1;
|
||||
|
@ -46,5 +48,5 @@ float reflection_probes_normalization_eval(vec3 L,
|
|||
{
|
||||
/* TODO(fclem): Adjusting directionality is tricky.
|
||||
* Needs to be revisited later on. For now only use the ambient term. */
|
||||
return (numerator.ambient * safe_rcp(denominator.ambient));
|
||||
return saturate(numerator.ambient / denominator.ambient);
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ int shadow_tile_offset(ivec2 tile, int tiles_index, int lod)
|
|||
/** \name Load / Store functions.
|
||||
* \{ */
|
||||
|
||||
/** \note: Will clamp if out of bounds. */
|
||||
/** \note Will clamp if out of bounds. */
|
||||
ShadowSamplingTile shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilemap_index)
|
||||
{
|
||||
/* NOTE(@fclem): This clamp can hide some small imprecision at clip-map transition.
|
||||
|
|
|
@ -722,7 +722,7 @@ SphericalHarmonicL1 spherical_harmonics_clamp(SphericalHarmonicL1 sh, float clam
|
|||
vec3 max_L1 = vec3(reduce_max(abs(per_channel[0].yzw)),
|
||||
reduce_max(abs(per_channel[1].yzw)),
|
||||
reduce_max(abs(per_channel[2].yzw)));
|
||||
/* Find maximum of the sh function over all chanels. */
|
||||
/* Find maximum of the sh function over all channels. */
|
||||
vec3 max_sh = abs(sh.L0.M0.rgb) * 0.282094792 + max_L1 * 0.488602512;
|
||||
|
||||
float fac = clamp_value * safe_rcp(reduce_max(max_sh));
|
||||
|
|
|
@ -69,10 +69,6 @@ GPU_SHADER_CREATE_INFO(eevee_geom_point_cloud)
|
|||
.vertex_out(eevee_surf_iface)
|
||||
.vertex_out(eevee_surf_point_cloud_iface)
|
||||
.vertex_out(eevee_surf_point_cloud_flat_iface)
|
||||
/* TODO(Miguel Pozo): Remove once we get rid of old EEVEE. */
|
||||
.define("pointRadius", "point_cloud_interp.radius")
|
||||
.define("pointPosition", "point_cloud_interp.position")
|
||||
.define("pointID", "point_cloud_interp_flat.id")
|
||||
.additional_info("draw_pointcloud_new",
|
||||
"draw_modelmat_new",
|
||||
"draw_resource_id_varying",
|
||||
|
|
|
@ -68,6 +68,7 @@ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_convolve)
|
|||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(eevee_display_probe_reflection_iface, "")
|
||||
.smooth(Type::VEC3, "P")
|
||||
.smooth(Type::VEC2, "lP")
|
||||
.flat(Type::INT, "probe_index");
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ class Instance {
|
|||
|
||||
if (is_object_data_visible) {
|
||||
if (object_state.sculpt_pbvh) {
|
||||
const Bounds<float3> bounds = BKE_pbvh_bounding_box(ob_ref.object->sculpt->pbvh);
|
||||
const Bounds<float3> bounds = bke::pbvh::bounds_get(*ob_ref.object->sculpt->pbvh);
|
||||
const float3 center = math::midpoint(bounds.min, bounds.max);
|
||||
const float3 half_extent = bounds.max - center;
|
||||
ResourceHandle handle = manager.resource_handle(ob_ref, nullptr, ¢er, &half_extent);
|
||||
|
|
|
@ -134,7 +134,7 @@ struct CutterSegments {
|
|||
* that intersect for the eye, but not in hard numbers. */
|
||||
static constexpr int BBOX_PADDING = 2;
|
||||
|
||||
/* When creating new intersection points, we don't want them too close to their neighbour,
|
||||
/* When creating new intersection points, we don't want them too close to their neighbor,
|
||||
* because that clutters the geometry. This threshold defines what 'too close' is. */
|
||||
static constexpr float DISTANCE_FACTOR_THRESHOLD = 0.01f;
|
||||
|
||||
|
|
|
@ -1884,6 +1884,8 @@ static bke::greasepencil::Layer &find_or_create_layer_in_dst_by_name(
|
|||
return *grease_pencil_dst.layers_for_write()[dst_layer_index];
|
||||
}
|
||||
|
||||
Layer &dst_layer = grease_pencil_dst.add_layer(layer_src.name());
|
||||
|
||||
/* Transfer Layer attributes. */
|
||||
bke::gather_attributes(grease_pencil_src.attributes(),
|
||||
bke::AttrDomain::Layer,
|
||||
|
@ -1892,7 +1894,7 @@ static bke::greasepencil::Layer &find_or_create_layer_in_dst_by_name(
|
|||
Span({layer_index}),
|
||||
grease_pencil_dst.attributes_for_write());
|
||||
|
||||
return grease_pencil_dst.add_layer(layer_src.name());
|
||||
return dst_layer;
|
||||
}
|
||||
|
||||
static bool grease_pencil_separate_selected(bContext &C,
|
||||
|
|
|
@ -98,7 +98,7 @@ void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob);
|
|||
/**
|
||||
* Allocate an array of `TransVert` for cursor/selection snapping (See
|
||||
* `ED_transverts_create_from_obedit` in `view3d_snap.cc`).
|
||||
* \note: the `TransVert` elements in \a tvs are expected to write to the positions of \a curves.
|
||||
* \note The `TransVert` elements in \a tvs are expected to write to the positions of \a curves.
|
||||
*/
|
||||
void transverts_from_curves_positions_create(bke::CurvesGeometry &curves, TransVertStore *tvs);
|
||||
|
||||
|
|
|
@ -43,17 +43,14 @@ void ED_keymap_sculpt(wmKeyConfig *keyconf);
|
|||
|
||||
/* `sculpt_transform.cc` */
|
||||
|
||||
void ED_sculpt_update_modal_transform(bContext *C, Object *ob);
|
||||
void ED_sculpt_init_transform(bContext *C,
|
||||
Object *ob,
|
||||
const float mval_fl[2],
|
||||
const char *undo_name);
|
||||
void ED_sculpt_end_transform(bContext *C, Object *ob);
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
void update_modal_transform(bContext *C, Object *ob);
|
||||
void init_transform(bContext *C, Object *ob, const float mval_fl[2], const char *undo_name);
|
||||
void end_transform(bContext *C, Object *ob);
|
||||
|
||||
/* `sculpt_undo.cc` */
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
namespace undo {
|
||||
|
||||
void register_type(UndoType *ut);
|
||||
|
|
|
@ -113,6 +113,14 @@ void UI_icon_draw_ex(float x,
|
|||
bool mono_border,
|
||||
const IconTextOverlay *text_overlay);
|
||||
|
||||
/**
|
||||
* Draw an monochrome icon into a given coordinate rectangle. The rectangle is used as-is,
|
||||
* and the icon image fills it. Icon is tinted with indicated color. If icon
|
||||
* is not found or the icon type is not monochrome, the function does nothing.
|
||||
*/
|
||||
void UI_icon_draw_mono_rect(
|
||||
float x, float y, float width, float height, int icon_id, const uchar color[4]);
|
||||
|
||||
void UI_icons_free();
|
||||
void UI_icons_free_drawinfo(void *drawinfo);
|
||||
|
||||
|
|
|
@ -1650,7 +1650,6 @@ static void icon_draw_rect(float x,
|
|||
float y,
|
||||
int w,
|
||||
int h,
|
||||
float /*aspect*/,
|
||||
int rw,
|
||||
int rh,
|
||||
const uint8_t *rect,
|
||||
|
@ -2014,8 +2013,7 @@ static void icon_draw_size(float x,
|
|||
const ImBuf *ibuf = static_cast<const ImBuf *>(icon->obj);
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
|
||||
icon_draw_rect(
|
||||
x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->byte_buffer.data, alpha, desaturate);
|
||||
icon_draw_rect(x, y, w, h, ibuf->x, ibuf->y, ibuf->byte_buffer.data, alpha, desaturate);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
}
|
||||
else if (di->type == ICON_TYPE_VECTOR) {
|
||||
|
@ -2055,7 +2053,7 @@ static void icon_draw_size(float x,
|
|||
}
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
|
||||
icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->byte_buffer.data, alpha, desaturate);
|
||||
icon_draw_rect(x, y, w, h, w, h, ibuf->byte_buffer.data, alpha, desaturate);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
}
|
||||
else if (di->type == ICON_TYPE_EVENT) {
|
||||
|
@ -2125,7 +2123,7 @@ static void icon_draw_size(float x,
|
|||
return;
|
||||
}
|
||||
|
||||
icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, desaturate);
|
||||
icon_draw_rect(x, y, w, h, iimg->w, iimg->h, iimg->rect, alpha, desaturate);
|
||||
}
|
||||
else if (di->type == ICON_TYPE_PREVIEW) {
|
||||
PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) :
|
||||
|
@ -2144,7 +2142,6 @@ static void icon_draw_size(float x,
|
|||
y,
|
||||
w,
|
||||
h,
|
||||
aspect,
|
||||
pi->w[size],
|
||||
pi->h[size],
|
||||
reinterpret_cast<const uint8_t *>(pi->rect[size]),
|
||||
|
@ -2696,6 +2693,35 @@ void UI_icon_draw_ex(float x,
|
|||
text_overlay);
|
||||
}
|
||||
|
||||
void UI_icon_draw_mono_rect(
|
||||
float x, float y, float width, float height, int icon_id, const uchar color[4])
|
||||
{
|
||||
Icon *icon = BKE_icon_get(icon_id);
|
||||
if (icon == nullptr) {
|
||||
return;
|
||||
}
|
||||
DrawInfo *di = icon_ensure_drawinfo(icon);
|
||||
if (di->type != ICON_TYPE_MONO_TEXTURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
float fcolor[4];
|
||||
straight_uchar_to_premul_float(fcolor, color);
|
||||
|
||||
icon_draw_texture(x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
di->data.texture.x,
|
||||
di->data.texture.y,
|
||||
di->data.texture.w,
|
||||
di->data.texture.h,
|
||||
fcolor[3],
|
||||
fcolor,
|
||||
false,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay,
|
||||
const int icon_indicator_number)
|
||||
{
|
||||
|
|
|
@ -2156,7 +2156,7 @@ void UI_view2d_text_cache_draw(ARegion *region)
|
|||
}
|
||||
|
||||
if (col_pack_prev != v2s->col.pack) {
|
||||
BLF_color3ubv(font_id, v2s->col.ub);
|
||||
BLF_color4ubv(font_id, v2s->col.ub);
|
||||
col_pack_prev = v2s->col.pack;
|
||||
}
|
||||
|
||||
|
|
|
@ -5109,16 +5109,15 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
|
|||
|
||||
Object *obedit = objects[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
if (em->bm->totedgesel == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool use_prepare = true;
|
||||
const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
|
||||
const int totedge_orig = em->bm->totedge;
|
||||
const int totface_orig = em->bm->totface;
|
||||
|
||||
if (em->bm->totedgesel == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use_prepare) {
|
||||
/* use when we have a single loop selected */
|
||||
PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span");
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "BKE_scene.hh"
|
||||
|
||||
#include "BLI_length_parameterize.hh"
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_geom.h"
|
||||
|
||||
|
@ -35,11 +36,22 @@ static constexpr float POINT_OVERRIDE_THRESHOLD_PX = 3.0f;
|
|||
static constexpr float POINT_RESAMPLE_MIN_DISTANCE_PX = 10.0f;
|
||||
|
||||
template<typename T>
|
||||
static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst)
|
||||
static inline void linear_interpolation(const T &a,
|
||||
const T &b,
|
||||
MutableSpan<T> dst,
|
||||
const bool include_first_point)
|
||||
{
|
||||
const float step = 1.0f / float(dst.size());
|
||||
for (const int i : dst.index_range()) {
|
||||
dst[i] = bke::attribute_math::mix2(float(i + 1) * step, a, b);
|
||||
if (include_first_point) {
|
||||
const float step = math::safe_rcp(float(dst.size() - 1));
|
||||
for (const int i : dst.index_range()) {
|
||||
dst[i] = bke::attribute_math::mix2(float(i) * step, a, b);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const float step = 1.0f / float(dst.size());
|
||||
for (const int i : dst.index_range()) {
|
||||
dst[i] = bke::attribute_math::mix2(float(i + 1) * step, a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,8 +378,13 @@ struct PaintOperationExecutor {
|
|||
const ColorGeometry4f prev_vertex_color = drawing_->vertex_colors().last();
|
||||
|
||||
/* Overwrite last point if it's very close. */
|
||||
const IndexRange points_range = curves.points_by_curve()[curves.curves_range().last()];
|
||||
const bool is_first_sample = (points_range.size() == 1);
|
||||
if (math::distance(coords, prev_coords) < POINT_OVERRIDE_THRESHOLD_PX) {
|
||||
curves.positions_for_write().last() = self.placement_.project(coords);
|
||||
/* Don't move the first point of the stroke. */
|
||||
if (!is_first_sample) {
|
||||
curves.positions_for_write().last() = self.placement_.project(coords);
|
||||
}
|
||||
drawing_->radii_for_write().last() = math::max(radius, prev_radius);
|
||||
drawing_->opacities_for_write().last() = math::max(opacity, prev_opacity);
|
||||
return;
|
||||
|
@ -395,10 +412,11 @@ struct PaintOperationExecutor {
|
|||
MutableSpan<float> new_opacities = drawing_->opacities_for_write().slice(new_points);
|
||||
MutableSpan<ColorGeometry4f> new_vertex_colors = drawing_->vertex_colors_for_write().slice(
|
||||
new_points);
|
||||
linear_interpolation<float2>(prev_coords, coords, new_screen_space_coords);
|
||||
linear_interpolation<float>(prev_radius, radius, new_radii);
|
||||
linear_interpolation<float>(prev_opacity, opacity, new_opacities);
|
||||
linear_interpolation<ColorGeometry4f>(prev_vertex_color, vertex_color, new_vertex_colors);
|
||||
linear_interpolation<float2>(prev_coords, coords, new_screen_space_coords, is_first_sample);
|
||||
linear_interpolation<float>(prev_radius, radius, new_radii, is_first_sample);
|
||||
linear_interpolation<float>(prev_opacity, opacity, new_opacities, is_first_sample);
|
||||
linear_interpolation<ColorGeometry4f>(
|
||||
prev_vertex_color, vertex_color, new_vertex_colors, is_first_sample);
|
||||
|
||||
/* Update screen space buffers with new points. */
|
||||
self.screen_space_coords_orig_.extend(new_screen_space_coords);
|
||||
|
|
|
@ -132,9 +132,9 @@ void mesh_show_all(Object &object, const Span<PBVHNode *> nodes)
|
|||
const VArraySpan hide_vert(attribute);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
const Span<int> verts = BKE_pbvh_node_get_vert_indices(node);
|
||||
const Span<int> verts = bke::pbvh::node_verts(*node);
|
||||
if (std::any_of(verts.begin(), verts.end(), [&](const int i) { return hide_vert[i]; })) {
|
||||
undo::push_node(&object, node, undo::Type::HideVert);
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
BKE_pbvh_node_mark_rebuild_draw(node);
|
||||
}
|
||||
}
|
||||
|
@ -157,13 +157,13 @@ void grids_show_all(Depsgraph &depsgraph, Object &object, const Span<PBVHNode *>
|
|||
if (!grid_hidden.is_empty()) {
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
const Span<int> grids = BKE_pbvh_node_get_grid_indices(*node);
|
||||
const Span<int> grids = bke::pbvh::node_grid_indices(*node);
|
||||
if (std::any_of(grids.begin(), grids.end(), [&](const int i) {
|
||||
return bits::any_bit_set(grid_hidden[i]);
|
||||
}))
|
||||
{
|
||||
any_changed = true;
|
||||
undo::push_node(&object, node, undo::Type::HideVert);
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
BKE_pbvh_node_mark_rebuild_draw(node);
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ static void vert_hide_update(Object &object,
|
|||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<bool> &new_hide = all_new_hide.local();
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
const Span<int> verts = BKE_pbvh_node_get_unique_vert_indices(node);
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(*node);
|
||||
|
||||
new_hide.reinitialize(verts.size());
|
||||
array_utils::gather(hide_vert.span.as_span(), verts, new_hide.as_mutable_span());
|
||||
|
@ -221,7 +221,7 @@ static void vert_hide_update(Object &object,
|
|||
}
|
||||
|
||||
any_changed = true;
|
||||
undo::push_node(&object, node, undo::Type::HideVert);
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
array_utils::scatter(new_hide.as_span(), verts, hide_vert.span);
|
||||
|
||||
BKE_pbvh_node_mark_update_visibility(node);
|
||||
|
@ -248,7 +248,7 @@ static void grid_hide_update(Depsgraph &depsgraph,
|
|||
bool any_changed = false;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
const Span<int> grids = BKE_pbvh_node_get_grid_indices(*node);
|
||||
const Span<int> grids = bke::pbvh::node_grid_indices(*node);
|
||||
BitGroupVector<> new_hide(grids.size(), grid_hidden.group_size());
|
||||
for (const int i : grids.index_range()) {
|
||||
new_hide[i].copy_from(grid_hidden[grids[i]].as_span());
|
||||
|
@ -266,7 +266,7 @@ static void grid_hide_update(Depsgraph &depsgraph,
|
|||
}
|
||||
|
||||
any_changed = true;
|
||||
undo::push_node(&object, node, undo::Type::HideVert);
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
|
||||
for (const int i : grids.index_range()) {
|
||||
grid_hidden[grids[i]].copy_from(new_hide[i].as_span());
|
||||
|
@ -327,7 +327,7 @@ static void partialvis_update_bmesh_nodes(Object *ob,
|
|||
bool any_changed = false;
|
||||
bool any_visible = false;
|
||||
|
||||
undo::push_node(ob, node, undo::Type::HideVert);
|
||||
undo::push_node(*ob, node, undo::Type::HideVert);
|
||||
|
||||
partialvis_update_bmesh_verts(
|
||||
BKE_pbvh_bmesh_node_unique_verts(node), action, vert_test_fn, &any_changed, &any_visible);
|
||||
|
@ -619,7 +619,7 @@ static void invert_visibility_mesh(Object &object, const Span<PBVHNode *> nodes)
|
|||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<int> &faces = all_index_data.local();
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
undo::push_node(&object, node, undo::Type::HideFace);
|
||||
undo::push_node(object, node, undo::Type::HideFace);
|
||||
bke::pbvh::node_face_indices_calc_mesh(pbvh, *node, faces);
|
||||
for (const int face : faces) {
|
||||
hide_poly.span[face] = !hide_poly.span[face];
|
||||
|
@ -643,8 +643,8 @@ static void invert_visibility_grids(Depsgraph &depsgraph,
|
|||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
undo::push_node(&object, node, undo::Type::HideVert);
|
||||
for (const int i : BKE_pbvh_node_get_grid_indices(*node)) {
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
for (const int i : bke::pbvh::node_grid_indices(*node)) {
|
||||
bits::invert(grid_hidden[i]);
|
||||
}
|
||||
BKE_pbvh_node_mark_update_visibility(node);
|
||||
|
@ -660,7 +660,7 @@ static void invert_visibility_bmesh(Object &object, const Span<PBVHNode *> nodes
|
|||
{
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
undo::push_node(&object, node, undo::Type::HideVert);
|
||||
undo::push_node(object, node, undo::Type::HideVert);
|
||||
bool fully_hidden = true;
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
BM_elem_flag_toggle(vert, BM_ELEM_HIDDEN);
|
||||
|
|
|
@ -145,7 +145,7 @@ static Span<int> get_visible_verts(const PBVHNode &node,
|
|||
if (BKE_pbvh_node_fully_hidden_get(&node)) {
|
||||
return {};
|
||||
}
|
||||
const Span<int> verts = BKE_pbvh_node_get_unique_vert_indices(&node);
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(node);
|
||||
if (hide_vert.is_empty()) {
|
||||
return verts;
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ static Span<int> get_hidden_verts(const PBVHNode &node,
|
|||
if (hide_vert.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
const Span<int> verts = BKE_pbvh_node_get_unique_vert_indices(&node);
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(node);
|
||||
if (BKE_pbvh_node_fully_hidden_get(&node)) {
|
||||
return verts;
|
||||
}
|
||||
|
@ -215,11 +215,11 @@ static bool try_remove_mask_mesh(Object &object, const Span<PBVHNode *> nodes)
|
|||
/* Store undo data for nodes with changed mask. */
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
const Span<int> verts = BKE_pbvh_node_get_unique_vert_indices(node);
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(*node);
|
||||
if (std::all_of(verts.begin(), verts.end(), [&](const int i) { return mask[i] == 0.0f; })) {
|
||||
continue;
|
||||
}
|
||||
undo::push_node(&object, node, undo::Type::Mask);
|
||||
undo::push_node(object, node, undo::Type::Mask);
|
||||
BKE_pbvh_node_mark_redraw(node);
|
||||
}
|
||||
});
|
||||
|
@ -250,7 +250,7 @@ static void fill_mask_mesh(Object &object, const float value, const Span<PBVHNod
|
|||
if (std::all_of(verts.begin(), verts.end(), [&](int i) { return mask.span[i] == value; })) {
|
||||
continue;
|
||||
}
|
||||
undo::push_node(&object, node, undo::Type::Mask);
|
||||
undo::push_node(object, node, undo::Type::Mask);
|
||||
mask.span.fill_indices(verts, value);
|
||||
BKE_pbvh_node_mark_redraw(node);
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ static void fill_mask_grids(Main &bmain,
|
|||
bool any_changed = false;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(*node);
|
||||
const Span<int> grid_indices = bke::pbvh::node_grid_indices(*node);
|
||||
if (std::all_of(grid_indices.begin(), grid_indices.end(), [&](const int grid) {
|
||||
CCGElem *elem = grids[grid];
|
||||
for (const int i : IndexRange(key.grid_area)) {
|
||||
|
@ -296,7 +296,7 @@ static void fill_mask_grids(Main &bmain,
|
|||
{
|
||||
continue;
|
||||
}
|
||||
undo::push_node(&object, node, undo::Type::Mask);
|
||||
undo::push_node(object, node, undo::Type::Mask);
|
||||
|
||||
if (grid_hidden.is_empty()) {
|
||||
for (const int grid : grid_indices) {
|
||||
|
@ -337,7 +337,7 @@ static void fill_mask_bmesh(Object &object, const float value, const Span<PBVHNo
|
|||
return;
|
||||
}
|
||||
|
||||
undo::push_node(&object, nodes.first(), undo::Type::Mask);
|
||||
undo::push_node(object, nodes.first(), undo::Type::Mask);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
bool redraw = false;
|
||||
|
@ -389,8 +389,8 @@ static void invert_mask_mesh(Object &object, const Span<PBVHNode *> nodes)
|
|||
".sculpt_mask", bke::AttrDomain::Point);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
undo::push_node(&object, node, undo::Type::Mask);
|
||||
for (const int vert : BKE_pbvh_node_get_unique_vert_indices(node)) {
|
||||
undo::push_node(object, node, undo::Type::Mask);
|
||||
for (const int vert : bke::pbvh::node_unique_verts(*node)) {
|
||||
if (!hide_vert.is_empty() && hide_vert[vert]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -420,9 +420,9 @@ static void invert_mask_grids(Main &bmain,
|
|||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
undo::push_node(&object, node, undo::Type::Mask);
|
||||
undo::push_node(object, node, undo::Type::Mask);
|
||||
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(*node);
|
||||
const Span<int> grid_indices = bke::pbvh::node_grid_indices(*node);
|
||||
if (grid_hidden.is_empty()) {
|
||||
for (const int grid : grid_indices) {
|
||||
CCGElem *elem = grids[grid];
|
||||
|
@ -456,7 +456,7 @@ static void invert_mask_bmesh(Object &object, const Span<PBVHNode *> nodes)
|
|||
return;
|
||||
}
|
||||
|
||||
undo::push_node(&object, nodes.first(), undo::Type::Mask);
|
||||
undo::push_node(object, nodes.first(), undo::Type::Mask);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
|
@ -584,7 +584,7 @@ static void mask_gesture_apply_task(gesture::GestureData &gesture_data,
|
|||
if (!any_masked) {
|
||||
any_masked = true;
|
||||
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
|
||||
if (is_multires) {
|
||||
BKE_pbvh_node_mark_positions_update(node);
|
||||
|
|
|
@ -1792,7 +1792,7 @@ static void vpaint_paint_leaves(bContext *C,
|
|||
Span<PBVHNode *> nodes)
|
||||
{
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Color);
|
||||
undo::push_node(*ob, node, undo::Type::Color);
|
||||
}
|
||||
|
||||
const Brush *brush = ob->sculpt->cache->brush;
|
||||
|
@ -2240,7 +2240,7 @@ static int vertex_color_set_exec(bContext *C, wmOperator *op)
|
|||
undo::push_begin(obact, op);
|
||||
Vector<PBVHNode *> nodes = blender::bke::pbvh::search_gather(obact->sculpt->pbvh, {});
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(obact, node, undo::Type::Color);
|
||||
undo::push_node(*obact, node, undo::Type::Color);
|
||||
}
|
||||
|
||||
paint_object_attributes_active_color_fill_ex(obact, paintcol, true, affect_alpha);
|
||||
|
|
|
@ -314,7 +314,7 @@ static void transform_active_color(bContext *C,
|
|||
|
||||
Vector<PBVHNode *> nodes = blender::bke::pbvh::search_gather(obact->sculpt->pbvh, {});
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(obact, node, undo::Type::Color);
|
||||
undo::push_node(*obact, node, undo::Type::Color);
|
||||
}
|
||||
|
||||
transform_active_color_data(*BKE_mesh_from_object(obact), transform_fn);
|
||||
|
|
|
@ -375,7 +375,9 @@ ePaintSymmetryFlags SCULPT_mesh_symmetry_xyz_get(Object *object)
|
|||
|
||||
/* Sculpt Face Sets and Visibility. */
|
||||
|
||||
namespace blender::ed::sculpt_paint::face_set {
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
namespace face_set {
|
||||
|
||||
int active_face_set_get(SculptSession *ss)
|
||||
{
|
||||
|
@ -399,9 +401,9 @@ int active_face_set_get(SculptSession *ss)
|
|||
return SCULPT_FACE_SET_NONE;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::face_set
|
||||
} // namespace face_set
|
||||
|
||||
namespace blender::ed::sculpt_paint::hide {
|
||||
namespace hide {
|
||||
|
||||
bool vert_visible_get(const SculptSession *ss, PBVHVertRef vertex)
|
||||
{
|
||||
|
@ -500,9 +502,9 @@ bool vert_all_faces_visible_get(const SculptSession *ss, PBVHVertRef vertex)
|
|||
return true;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::hide
|
||||
} // namespace hide
|
||||
|
||||
namespace blender::ed::sculpt_paint::face_set {
|
||||
namespace face_set {
|
||||
|
||||
int vert_face_set_get(SculptSession *ss, PBVHVertRef vertex)
|
||||
{
|
||||
|
@ -648,7 +650,7 @@ bool vert_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex)
|
|||
return false;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::face_set
|
||||
} // namespace face_set
|
||||
|
||||
/* Sculpt Neighbor Iterators */
|
||||
|
||||
|
@ -731,9 +733,8 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
|
|||
/* Skip connectivity from hidden faces. */
|
||||
continue;
|
||||
}
|
||||
const blender::IndexRange face = ss->faces[face_i];
|
||||
const blender::int2 f_adj_v = blender::bke::mesh::face_find_adjacent_verts(
|
||||
face, ss->corner_verts, vertex.i);
|
||||
const IndexRange face = ss->faces[face_i];
|
||||
const int2 f_adj_v = bke::mesh::face_find_adjacent_verts(face, ss->corner_verts, vertex.i);
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (f_adj_v[j] != vertex.i) {
|
||||
sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]);
|
||||
|
@ -794,11 +795,14 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
|
||||
void SCULPT_vertex_neighbors_get(SculptSession *ss,
|
||||
const PBVHVertRef vertex,
|
||||
const bool include_duplicates,
|
||||
SculptVertexNeighborIter *iter)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES:
|
||||
sculpt_vertex_neighbors_get_faces(ss, vertex, iter);
|
||||
|
@ -831,7 +835,6 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex
|
|||
BMVert *v = (BMVert *)vertex.i;
|
||||
return BM_vert_is_boundary(v);
|
||||
}
|
||||
|
||||
case PBVH_GRIDS: {
|
||||
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
|
||||
const int grid_index = vertex.i / key->grid_area;
|
||||
|
@ -931,7 +934,7 @@ PBVHVertRef SCULPT_nearest_vertex_get(Object *ob,
|
|||
|
||||
const float max_distance_sq = max_distance * max_distance;
|
||||
|
||||
Vector<PBVHNode *> nodes = blender::bke::pbvh::search_gather(ss->pbvh, [&](PBVHNode &node) {
|
||||
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(ss->pbvh, [&](PBVHNode &node) {
|
||||
return node_in_sphere(node, co, max_distance_sq, use_original);
|
||||
});
|
||||
if (nodes.is_empty()) {
|
||||
|
@ -1001,7 +1004,9 @@ void SCULPT_tag_update_overlays(bContext *C)
|
|||
* Iterate over connected vertices, starting from one or more initial vertices.
|
||||
* \{ */
|
||||
|
||||
namespace blender::ed::sculpt_paint::flood_fill {
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
namespace flood_fill {
|
||||
|
||||
void init_fill(SculptSession *ss, FillData *flood)
|
||||
{
|
||||
|
@ -1106,7 +1111,7 @@ void execute(
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::flood_fill
|
||||
} // namespace flood_fill
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@ -1183,6 +1188,8 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
|
|||
return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -1222,7 +1229,7 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
|
|||
blender::ed::sculpt_paint::undo::Type type)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
undo::Node *unode = undo::push_node(ob, node, type);
|
||||
undo::Node *unode = undo::push_node(*ob, node, type);
|
||||
SCULPT_orig_vert_data_unode_init(data, ob, unode);
|
||||
}
|
||||
|
||||
|
@ -1251,6 +1258,8 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter
|
|||
}
|
||||
}
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
static void sculpt_rake_data_update(SculptRakeData *srd, const float co[3])
|
||||
{
|
||||
float rake_dist = len_v3v3(srd->follow_co, co);
|
||||
|
@ -1265,7 +1274,7 @@ static void sculpt_rake_data_update(SculptRakeData *srd, const float co[3])
|
|||
/** \name Sculpt Dynamic Topology
|
||||
* \{ */
|
||||
|
||||
namespace blender::ed::sculpt_paint::dyntopo {
|
||||
namespace dyntopo {
|
||||
|
||||
bool stroke_is_dyntopo(const SculptSession *ss, const Brush *brush)
|
||||
{
|
||||
|
@ -1280,7 +1289,7 @@ bool stroke_is_dyntopo(const SculptSession *ss, const Brush *brush)
|
|||
SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::dyntopo
|
||||
} // namespace dyntopo
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@ -1288,161 +1297,231 @@ bool stroke_is_dyntopo(const SculptSession *ss, const Brush *brush)
|
|||
/** \name Sculpt Paint Mesh
|
||||
* \{ */
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
static void paint_mesh_restore_node(Object *ob, const undo::Type type, PBVHNode *node)
|
||||
static void restore_mask(Object &object, const Span<PBVHNode *> nodes)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
undo::Node *unode;
|
||||
if (ss->bm) {
|
||||
unode = undo::push_node(ob, node, type);
|
||||
}
|
||||
else {
|
||||
unode = undo::get_node(node, type);
|
||||
}
|
||||
|
||||
if (!unode) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case undo::Type::Mask: {
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob->data);
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
bke::SpanAttributeWriter<float> mask = attributes.lookup_or_add_for_write_span<float>(
|
||||
".sculpt_mask", bke::AttrDomain::Point);
|
||||
array_utils::scatter(
|
||||
unode->mask.as_span(), BKE_pbvh_node_get_unique_vert_indices(node), mask.span);
|
||||
mask.finish();
|
||||
break;
|
||||
SculptSession *ss = object.sculpt;
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
bke::SpanAttributeWriter<float> mask = attributes.lookup_or_add_for_write_span<float>(
|
||||
".sculpt_mask", bke::AttrDomain::Point);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
if (undo::Node *unode = undo::get_node(node, undo::Type::Mask)) {
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(*node);
|
||||
array_utils::scatter(unode->mask.as_span(), verts, mask.span);
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
}
|
||||
}
|
||||
case PBVH_BMESH: {
|
||||
const int offset = CustomData_get_offset_named(
|
||||
&ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
if (offset != -1) {
|
||||
});
|
||||
mask.finish();
|
||||
break;
|
||||
}
|
||||
case PBVH_BMESH: {
|
||||
const int offset = CustomData_get_offset_named(
|
||||
&ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
if (offset != -1) {
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (undo::push_node(object, node, undo::Type::Mask)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
const float orig_mask = BM_log_original_mask(ss->bm_log, vert);
|
||||
BM_ELEM_CD_SET_FLOAT(vert, offset, orig_mask);
|
||||
}
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
SubdivCCG &subdiv_ccg = *ss->subdiv_ccg;
|
||||
const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
int index = 0;
|
||||
for (const int grid : unode->grids) {
|
||||
CCGElem *elem = grids[grid];
|
||||
for (const int i : IndexRange(key.grid_area)) {
|
||||
if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
|
||||
*CCG_elem_offset_mask(&key, elem, i) = unode->mask[index];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
SubdivCCG &subdiv_ccg = *ss->subdiv_ccg;
|
||||
const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
if (undo::Node *unode = undo::get_node(node, undo::Type::Mask)) {
|
||||
int index = 0;
|
||||
for (const int grid : unode->grids) {
|
||||
CCGElem *elem = grids[grid];
|
||||
for (const int i : IndexRange(key.grid_area)) {
|
||||
if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
|
||||
*CCG_elem_offset_mask(&key, elem, i) = unode->mask[index];
|
||||
}
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void restore_color(Object &object, const Span<PBVHNode *> nodes)
|
||||
{
|
||||
SculptSession *ss = object.sculpt;
|
||||
const auto restore_generic = [&](PBVHNode *node, undo::Node *unode) {
|
||||
SculptOrigVertData orig_vert_data;
|
||||
SCULPT_orig_vert_data_unode_init(&orig_vert_data, &object, unode);
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_vert_data, &vd);
|
||||
SCULPT_vertex_color_set(ss, vd.vertex, orig_vert_data.col);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
BKE_pbvh_node_mark_update_color(node);
|
||||
};
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
if (undo::Node *unode = undo::get_node(node, undo::Type::Color)) {
|
||||
restore_generic(node, unode);
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case PBVH_BMESH: {
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (undo::Node *unode = undo::push_node(object, node, undo::Type::Color)) {
|
||||
restore_generic(node, unode);
|
||||
}
|
||||
}
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
break;
|
||||
}
|
||||
case undo::Type::Color: {
|
||||
SculptOrigVertData orig_vert_data;
|
||||
SCULPT_orig_vert_data_unode_init(&orig_vert_data, ob, unode);
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_vert_data, &vd);
|
||||
SCULPT_vertex_color_set(ss, vd.vertex, orig_vert_data.col);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
BKE_pbvh_node_mark_update_color(node);
|
||||
break;
|
||||
}
|
||||
case undo::Type::FaceSet: {
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES:
|
||||
case PBVH_GRIDS: {
|
||||
const Span<int> face_sets = unode->face_sets;
|
||||
const Span<int> faces = unode->face_indices;
|
||||
bke::SpanAttributeWriter<int> attribute = face_set::ensure_face_sets_mesh(*ob);
|
||||
blender::array_utils::scatter(face_sets, faces, attribute.span);
|
||||
attribute.finish();
|
||||
break;
|
||||
case PBVH_GRIDS: {
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
if (undo::Node *unode = undo::get_node(node, undo::Type::Color)) {
|
||||
restore_generic(node, unode);
|
||||
}
|
||||
}
|
||||
case PBVH_BMESH:
|
||||
break;
|
||||
}
|
||||
BKE_pbvh_node_mark_update_face_sets(node);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case undo::Type::Position: {
|
||||
SculptOrigVertData orig_vert_data;
|
||||
SCULPT_orig_vert_data_unode_init(&orig_vert_data, ob, unode);
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_vert_data, &vd);
|
||||
copy_v3_v3(vd.co, orig_vert_data.co);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
BKE_pbvh_node_mark_update(node);
|
||||
}
|
||||
}
|
||||
|
||||
static void restore_face_set(Object &object, const Span<PBVHNode *> nodes)
|
||||
{
|
||||
SculptSession *ss = object.sculpt;
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES:
|
||||
case PBVH_GRIDS: {
|
||||
bke::SpanAttributeWriter<int> attribute = face_set::ensure_face_sets_mesh(object);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
if (undo::Node *unode = undo::get_node(node, undo::Type::FaceSet)) {
|
||||
const Span<int> faces = unode->face_indices;
|
||||
const Span<int> face_sets = unode->face_sets;
|
||||
blender::array_utils::scatter(face_sets, faces, attribute.span);
|
||||
BKE_pbvh_node_mark_update_face_sets(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
attribute.finish();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case PBVH_BMESH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
|
||||
static void restore_position(Object &object, const Span<PBVHNode *> nodes)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
SculptSession *ss = object.sculpt;
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
MutableSpan positions = BKE_pbvh_get_vert_positions(ss->pbvh);
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
if (undo::Node *unode = undo::get_node(node, undo::Type::Position)) {
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(*node);
|
||||
array_utils::scatter(unode->position.as_span(), verts, positions);
|
||||
BKE_pbvh_node_mark_positions_update(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case PBVH_BMESH: {
|
||||
for (PBVHNode *node : nodes) {
|
||||
if (undo::push_node(object, node, undo::Type::Position)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
copy_v3_v3(vert->co, BM_log_original_vert_co(ss->bm_log, vert));
|
||||
}
|
||||
BKE_pbvh_node_mark_positions_update(node);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
SubdivCCG &subdiv_ccg = *ss->subdiv_ccg;
|
||||
const BitGroupVector<> grid_hidden = subdiv_ccg.grid_hidden;
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
if (undo::Node *unode = undo::get_node(node, undo::Type::Position)) {
|
||||
int index = 0;
|
||||
for (const int grid : unode->grids) {
|
||||
CCGElem *elem = grids[grid];
|
||||
for (const int i : IndexRange(key.grid_area)) {
|
||||
if (grid_hidden.is_empty() || !grid_hidden[grid][i]) {
|
||||
copy_v3_v3(CCG_elem_offset_co(&key, elem, i), unode->position[index]);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
BKE_pbvh_node_mark_positions_update(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update normals for potentially-changed positions. Theoretically this may be unnecessary if
|
||||
* the tool restoring to the initial state doesn't use the normals, but we have no easy way to
|
||||
* know that from here. */
|
||||
bke::pbvh::update_normals(*ss->pbvh, ss->subdiv_ccg);
|
||||
}
|
||||
|
||||
static void restore_from_undo_step(const Sculpt &sd, Object &object)
|
||||
{
|
||||
SculptSession *ss = object.sculpt;
|
||||
const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
|
||||
|
||||
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(ss->pbvh, {});
|
||||
|
||||
undo::Type type;
|
||||
switch (brush->sculpt_tool) {
|
||||
case SCULPT_TOOL_MASK:
|
||||
type = undo::Type::Mask;
|
||||
restore_mask(object, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_PAINT:
|
||||
case SCULPT_TOOL_SMEAR:
|
||||
type = undo::Type::Color;
|
||||
restore_color(object, nodes);
|
||||
break;
|
||||
case SCULPT_TOOL_DRAW_FACE_SETS:
|
||||
type = ss->cache->alt_smooth ? undo::Type::Position : undo::Type::FaceSet;
|
||||
if (ss->cache->alt_smooth) {
|
||||
restore_position(object, nodes);
|
||||
}
|
||||
else {
|
||||
restore_face_set(object, nodes);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
type = undo::Type::Position;
|
||||
restore_position(object, nodes);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ss->bm) {
|
||||
/* Disable multi-threading when dynamic-topology is enabled. Otherwise,
|
||||
* new entries might be inserted by #undo::push_node() into the #GHash
|
||||
* used internally by #BM_log_original_vert_co() by a different thread. See #33787. */
|
||||
for (const int i : nodes.index_range()) {
|
||||
paint_mesh_restore_node(ob, type, nodes[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
paint_mesh_restore_node(ob, type, nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (type == undo::Type::Position) {
|
||||
/* Update normals for potentially-changed positions. Theoretically this may be unnecessary if
|
||||
* the tool restoring to the initial state doesn't use the normals, but we have no easy way to
|
||||
* know that from here. */
|
||||
bke::pbvh::update_normals(*ss->pbvh, ss->subdiv_ccg);
|
||||
}
|
||||
/* Disable multi-threading when dynamic-topology is enabled. Otherwise,
|
||||
* new entries might be inserted by #undo::push_node() into the #GHash
|
||||
* used internally by #BM_log_original_vert_co() by a different thread. See #33787. */
|
||||
|
||||
BKE_pbvh_node_color_buffer_free(ss->pbvh);
|
||||
}
|
||||
|
@ -1803,7 +1882,7 @@ static void calc_area_normal_and_center_task(Object *ob,
|
|||
bool normal_test_r, area_test_r;
|
||||
|
||||
if (ss->cache && !ss->cache->accum) {
|
||||
unode = undo::push_node(ob, node, undo::Type::Position);
|
||||
unode = undo::push_node(*ob, node, undo::Type::Position);
|
||||
use_original = (!unode->position.is_empty() || unode->bm_entry);
|
||||
}
|
||||
|
||||
|
@ -2508,18 +2587,18 @@ bool node_in_sphere(const PBVHNode &node,
|
|||
const bool original)
|
||||
{
|
||||
const Bounds<float3> bounds = original ? BKE_pbvh_node_get_original_BB(&node) :
|
||||
BKE_pbvh_node_get_BB(&node);
|
||||
bke::pbvh::node_bounds(node);
|
||||
const float3 nearest = math::clamp(location, bounds.min, bounds.max);
|
||||
return math::distance_squared(location, nearest) < radius_sq;
|
||||
}
|
||||
|
||||
bool node_in_cylinder(const DistRayAABB_Precalc &ray_dist_precalc,
|
||||
const PBVHNode &node,
|
||||
float radius_sq,
|
||||
bool original)
|
||||
const float radius_sq,
|
||||
const bool original)
|
||||
{
|
||||
const Bounds<float3> bounds = (original) ? BKE_pbvh_node_get_original_BB(&node) :
|
||||
BKE_pbvh_node_get_BB(&node);
|
||||
bke::pbvh::node_bounds(node);
|
||||
|
||||
float dummy_co[3], dummy_depth;
|
||||
const float dist_sq = dist_squared_ray_to_aabb_v3(
|
||||
|
@ -3178,6 +3257,8 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const Span<float3> vertCos)
|
|||
BKE_keyblock_update_from_vertcos(ob, kb, reinterpret_cast<const float(*)[3]>(vertCos.data()));
|
||||
}
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
/* NOTE: we do the topology update before any brush actions to avoid
|
||||
* issues with the proxies. The size of the proxy can't change, so
|
||||
* topology must be updated first. */
|
||||
|
@ -3187,8 +3268,6 @@ static void sculpt_topology_update(Sculpt *sd,
|
|||
UnifiedPaintSettings * /*ups*/,
|
||||
PaintModeSettings * /*paint_mode_settings*/)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
/* Build a list of all nodes that are potentially within the brush's area of influence. */
|
||||
|
@ -3220,7 +3299,7 @@ static void sculpt_topology_update(Sculpt *sd,
|
|||
}
|
||||
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(ob,
|
||||
undo::push_node(*ob,
|
||||
node,
|
||||
brush->sculpt_tool == SCULPT_TOOL_MASK ? undo::Type::Mask :
|
||||
undo::Type::Position);
|
||||
|
@ -3249,7 +3328,6 @@ static void sculpt_topology_update(Sculpt *sd,
|
|||
|
||||
static void do_brush_action_task(Object *ob, const Brush *brush, PBVHNode *node)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
bool need_coords = ss->cache->supports_gravity;
|
||||
|
@ -3262,15 +3340,15 @@ static void do_brush_action_task(Object *ob, const Brush *brush, PBVHNode *node)
|
|||
need_coords = true;
|
||||
}
|
||||
else {
|
||||
undo::push_node(ob, node, undo::Type::FaceSet);
|
||||
undo::push_node(*ob, node, undo::Type::FaceSet);
|
||||
}
|
||||
}
|
||||
else if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
}
|
||||
else if (SCULPT_tool_is_paint(brush->sculpt_tool)) {
|
||||
undo::push_node(ob, node, undo::Type::Color);
|
||||
undo::push_node(*ob, node, undo::Type::Color);
|
||||
BKE_pbvh_node_mark_update_color(node);
|
||||
}
|
||||
else {
|
||||
|
@ -3278,7 +3356,7 @@ static void do_brush_action_task(Object *ob, const Brush *brush, PBVHNode *node)
|
|||
}
|
||||
|
||||
if (need_coords) {
|
||||
undo::push_node(ob, node, undo::Type::Position);
|
||||
undo::push_node(*ob, node, undo::Type::Position);
|
||||
BKE_pbvh_node_mark_update(node);
|
||||
}
|
||||
}
|
||||
|
@ -3289,8 +3367,6 @@ static void do_brush_action(Sculpt *sd,
|
|||
UnifiedPaintSettings *ups,
|
||||
PaintModeSettings *paint_mode_settings)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Vector<PBVHNode *> nodes, texnodes;
|
||||
|
||||
|
@ -3323,7 +3399,7 @@ static void do_brush_action(Sculpt *sd,
|
|||
|
||||
if (SCULPT_tool_needs_all_pbvh_nodes(brush)) {
|
||||
/* These brushes need to update all nodes as they are not constrained by the brush radius */
|
||||
nodes = blender::bke::pbvh::search_gather(ss->pbvh, {});
|
||||
nodes = bke::pbvh::search_gather(ss->pbvh, {});
|
||||
}
|
||||
else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
|
||||
nodes = cloth::brush_affected_nodes_gather(ss, brush);
|
||||
|
@ -3608,13 +3684,12 @@ static void sculpt_combine_proxies_node(Object &object,
|
|||
const bool use_orco,
|
||||
PBVHNode &node)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = object.sculpt;
|
||||
|
||||
float(*orco)[3] = nullptr;
|
||||
if (use_orco && !ss->bm) {
|
||||
orco = reinterpret_cast<float(*)[3]>(
|
||||
(undo::push_node(&object, &node, undo::Type::Position)->position.data()));
|
||||
(undo::push_node(object, &node, undo::Type::Position)->position.data()));
|
||||
}
|
||||
|
||||
MutableSpan<PBVHProxyNode> proxies = BKE_pbvh_node_get_proxies(&node);
|
||||
|
@ -3655,7 +3730,6 @@ static void sculpt_combine_proxies_node(Object &object,
|
|||
|
||||
static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
||||
|
@ -3673,7 +3747,7 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
|
|||
SCULPT_TOOL_BOUNDARY,
|
||||
SCULPT_TOOL_POSE);
|
||||
|
||||
Vector<PBVHNode *> nodes = blender::bke::pbvh::gather_proxies(ss->pbvh);
|
||||
Vector<PBVHNode *> nodes = bke::pbvh::gather_proxies(ss->pbvh);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
|
@ -3682,12 +3756,15 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
|
|||
});
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
|
||||
void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
Vector<PBVHNode *> nodes = blender::bke::pbvh::gather_proxies(ss->pbvh);
|
||||
Vector<PBVHNode *> nodes = bke::pbvh::gather_proxies(ss->pbvh);
|
||||
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
|
@ -3716,6 +3793,7 @@ static void sculpt_update_keyblock(Object *ob)
|
|||
void SCULPT_flush_stroke_deform(Sculpt * /*sd*/, Object *ob, bool is_proxy_used)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
if (is_proxy_used && ss->deform_modifiers_active) {
|
||||
|
@ -3732,7 +3810,7 @@ void SCULPT_flush_stroke_deform(Sculpt * /*sd*/, Object *ob, bool is_proxy_used)
|
|||
vertCos = ss->orig_cos;
|
||||
}
|
||||
|
||||
nodes = blender::bke::pbvh::search_gather(ss->pbvh, {});
|
||||
nodes = bke::pbvh::search_gather(ss->pbvh, {});
|
||||
|
||||
MutableSpan<float3> positions = mesh->vert_positions_for_write();
|
||||
|
||||
|
@ -3814,6 +3892,8 @@ void SCULPT_cache_calc_brushdata_symm(blender::ed::sculpt_paint::StrokeCache *ca
|
|||
}
|
||||
}
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
using BrushActionFunc = void (*)(Sculpt *sd,
|
||||
Object *ob,
|
||||
Brush *brush,
|
||||
|
@ -3827,11 +3907,10 @@ static void do_tiled(Sculpt *sd,
|
|||
PaintModeSettings *paint_mode_settings,
|
||||
BrushActionFunc action)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
StrokeCache *cache = ss->cache;
|
||||
const float radius = cache->radius;
|
||||
const blender::Bounds<blender::float3> bb = *BKE_object_boundbox_get(ob);
|
||||
const Bounds<float3> bb = *BKE_object_boundbox_get(ob);
|
||||
const float *bbMin = bb.min;
|
||||
const float *bbMax = bb.max;
|
||||
const float *step = sd->paint.tile_offset;
|
||||
|
@ -3928,7 +4007,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
|
|||
{
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
blender::ed::sculpt_paint::StrokeCache *cache = ss->cache;
|
||||
StrokeCache *cache = ss->cache;
|
||||
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
|
||||
float feather = calc_symmetry_feather(sd, ss->cache);
|
||||
|
@ -3955,6 +4034,8 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
|
||||
bool SCULPT_mode_poll(bContext *C)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
@ -3963,11 +4044,13 @@ bool SCULPT_mode_poll(bContext *C)
|
|||
|
||||
bool SCULPT_mode_poll_view3d(bContext *C)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
return (SCULPT_mode_poll(C) && CTX_wm_region_view3d(C) && !ED_gpencil_session_active());
|
||||
}
|
||||
|
||||
bool SCULPT_poll(bContext *C)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
return SCULPT_mode_poll(C) && blender::ed::sculpt_paint::paint_brush_tool_poll(C);
|
||||
}
|
||||
|
||||
|
@ -4076,10 +4159,11 @@ void SCULPT_cache_free(blender::ed::sculpt_paint::StrokeCache *cache)
|
|||
MEM_delete(cache);
|
||||
}
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
/* Initialize mirror modifier clipping. */
|
||||
static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
|
||||
{
|
||||
using namespace blender;
|
||||
ss->cache->clip_mirror_mtx = float4x4::identity();
|
||||
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
||||
|
@ -4114,9 +4198,7 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
|
|||
}
|
||||
}
|
||||
|
||||
static void smooth_brush_toggle_on(const bContext *C,
|
||||
Paint *paint,
|
||||
blender::ed::sculpt_paint::StrokeCache *cache)
|
||||
static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
@ -4158,9 +4240,7 @@ static void smooth_brush_toggle_on(const bContext *C,
|
|||
BKE_curvemapping_init(smooth_brush->curve);
|
||||
}
|
||||
|
||||
static void smooth_brush_toggle_off(const bContext *C,
|
||||
Paint *paint,
|
||||
blender::ed::sculpt_paint::StrokeCache *cache)
|
||||
static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Brush *brush = BKE_paint_brush(paint);
|
||||
|
@ -4195,7 +4275,6 @@ static void smooth_brush_toggle_off(const bContext *C,
|
|||
static void sculpt_update_cache_invariants(
|
||||
bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2])
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
StrokeCache *cache = MEM_new<StrokeCache>(__func__);
|
||||
ToolSettings *tool_settings = CTX_data_tool_settings(C);
|
||||
UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings;
|
||||
|
@ -4349,9 +4428,7 @@ static void sculpt_update_cache_invariants(
|
|||
#undef PIXEL_INPUT_THRESHHOLD
|
||||
}
|
||||
|
||||
static float sculpt_brush_dynamic_size_get(Brush *brush,
|
||||
blender::ed::sculpt_paint::StrokeCache *cache,
|
||||
float initial_size)
|
||||
static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, float initial_size)
|
||||
{
|
||||
switch (brush->sculpt_tool) {
|
||||
case SCULPT_TOOL_CLAY:
|
||||
|
@ -4410,7 +4487,6 @@ static bool sculpt_needs_delta_for_tip_orientation(Brush *brush)
|
|||
|
||||
static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
StrokeCache *cache = ss->cache;
|
||||
const float mval[2] = {
|
||||
|
@ -4569,8 +4645,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
|
|||
sculpt_rake_data_update(&cache->rake_data, grab_location);
|
||||
}
|
||||
|
||||
static void sculpt_update_cache_paint_variants(blender::ed::sculpt_paint::StrokeCache *cache,
|
||||
const Brush *brush)
|
||||
static void sculpt_update_cache_paint_variants(StrokeCache *cache, const Brush *brush)
|
||||
{
|
||||
cache->paint_brush.hardness = brush->hardness;
|
||||
if (brush->paint_flags & BRUSH_PAINT_HARDNESS_PRESSURE) {
|
||||
|
@ -4617,7 +4692,6 @@ static void sculpt_update_cache_paint_variants(blender::ed::sculpt_paint::Stroke
|
|||
/* Initialize the stroke cache variants from operator properties. */
|
||||
static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, PointerRNA *ptr)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
@ -4724,7 +4798,6 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
|
|||
SculptSession *ss,
|
||||
int stroke_mode)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
if (!brush) {
|
||||
return true;
|
||||
}
|
||||
|
@ -4745,8 +4818,11 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
|
|||
(brush->sculpt_tool == SCULPT_TOOL_PAINT));
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
|
||||
void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
|
@ -5204,7 +5280,7 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
|
|||
(brush->flag & BRUSH_DRAG_DOT))
|
||||
{
|
||||
|
||||
paint_mesh_restore_co(sd, ob);
|
||||
restore_from_undo_step(*sd, *ob);
|
||||
|
||||
if (ss->cache) {
|
||||
MEM_SAFE_FREE(ss->cache->layer_displacement_factor);
|
||||
|
@ -5301,7 +5377,7 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
|
|||
mesh->tag_positions_changed();
|
||||
}
|
||||
|
||||
mesh->bounds_set_eager(BKE_pbvh_bounding_box(ob->sculpt->pbvh));
|
||||
mesh->bounds_set_eager(bke::pbvh::bounds_get(*ob->sculpt->pbvh));
|
||||
if (ob->runtime->bounds_eval) {
|
||||
ob->runtime->bounds_eval = mesh->bounds_min_max();
|
||||
}
|
||||
|
@ -5452,9 +5528,7 @@ bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
|
|||
BKE_report(reports, RPT_ERROR, "Not supported in multiresolution mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_assert_msg(0, "PBVH corruption, type was invalid.");
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5745,7 +5819,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
|
|||
/* XXX Canceling strokes that way does not work with dynamic topology,
|
||||
* user will have to do real undo for now. See #46456. */
|
||||
if (ss->cache && !dyntopo::stroke_is_dyntopo(ss, brush)) {
|
||||
paint_mesh_restore_co(sd, ob);
|
||||
restore_from_undo_step(*sd, *ob);
|
||||
}
|
||||
|
||||
paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
|
||||
|
|
|
@ -113,7 +113,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *op)
|
|||
BKE_pbvh_node_mark_topology_update(node);
|
||||
}
|
||||
/* Get the bounding box, its center and size. */
|
||||
const Bounds<float3> bounds = BKE_pbvh_bounding_box(ob->sculpt->pbvh);
|
||||
const Bounds<float3> bounds = bke::pbvh::bounds_get(*ob->sculpt->pbvh);
|
||||
const float3 center = math::midpoint(bounds.min, bounds.max);
|
||||
const float3 dim = bounds.max - bounds.min;
|
||||
const float size = math::reduce_max(dim);
|
||||
|
@ -124,7 +124,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *op)
|
|||
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
|
||||
|
||||
undo::push_begin(ob, op);
|
||||
undo::push_node(ob, nullptr, undo::Type::Position);
|
||||
undo::push_node(*ob, nullptr, undo::Type::Position);
|
||||
|
||||
const double start_time = BLI_time_now_seconds();
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ void disable_with_undo(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *
|
|||
const bool use_undo = G.background ? (ED_undo_stack_get() != nullptr) : true;
|
||||
if (use_undo) {
|
||||
undo::push_begin_ex(ob, "Dynamic topology disable");
|
||||
undo::push_node(ob, nullptr, undo::Type::DyntopoEnd);
|
||||
undo::push_node(*ob, nullptr, undo::Type::DyntopoEnd);
|
||||
}
|
||||
SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, nullptr);
|
||||
if (use_undo) {
|
||||
|
@ -230,7 +230,7 @@ static void sculpt_dynamic_topology_enable_with_undo(Main *bmain, Depsgraph *dep
|
|||
}
|
||||
enable_ex(bmain, depsgraph, ob);
|
||||
if (use_undo) {
|
||||
undo::push_node(ob, nullptr, undo::Type::DyntopoBegin);
|
||||
undo::push_node(*ob, nullptr, undo::Type::DyntopoBegin);
|
||||
undo::push_end(ob);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1171,50 +1171,46 @@ static void sculpt_expand_restore_color_data(SculptSession *ss, Cache *expand_ca
|
|||
|
||||
static void write_mask_data(SculptSession *ss, const Span<float> mask)
|
||||
{
|
||||
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(ss->pbvh, {});
|
||||
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
Mesh *mesh = BKE_pbvh_get_mesh(ss->pbvh);
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
bke::SpanAttributeWriter<float> attribute = attributes.lookup_or_add_for_write_span<float>(
|
||||
".sculpt_mask", bke::AttrDomain::Point);
|
||||
for (PBVHNode *node : nodes) {
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
attribute.span[vd.index] = mask[vd.index];
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
BKE_pbvh_node_mark_redraw(node);
|
||||
}
|
||||
attributes.remove(".sculpt_mask");
|
||||
attributes.add<float>(".sculpt_mask",
|
||||
bke::AttrDomain::Point,
|
||||
bke::AttributeInitVArray(VArray<float>::ForSpan(mask)));
|
||||
break;
|
||||
}
|
||||
case PBVH_BMESH: {
|
||||
const int offset = CustomData_get_offset_named(
|
||||
&BKE_pbvh_get_bmesh(ss->pbvh)->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
for (PBVHNode *node : nodes) {
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
BM_ELEM_CD_SET_FLOAT(vd.bm_vert, offset, mask[vd.index]);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
BKE_pbvh_node_mark_redraw(node);
|
||||
BMesh &bm = *BKE_pbvh_get_bmesh(ss->pbvh);
|
||||
const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
|
||||
BM_mesh_elem_table_ensure(&bm, BM_VERT);
|
||||
for (const int i : mask.index_range()) {
|
||||
BM_ELEM_CD_SET_FLOAT(BM_vert_at_index(&bm, i), offset, mask[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
for (PBVHNode *node : nodes) {
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
*CCG_elem_mask(&vd.key, vd.grid) = mask[vd.index];
|
||||
break;
|
||||
const SubdivCCG &subdiv_ccg = *ss->subdiv_ccg;
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
const Span<CCGElem *> grids = subdiv_ccg.grids;
|
||||
|
||||
int index = 0;
|
||||
for (const int grid : grids.index_range()) {
|
||||
CCGElem *elem = grids[grid];
|
||||
for (const int i : IndexRange(key.grid_area)) {
|
||||
*CCG_elem_offset_mask(&key, elem, i) = mask[index];
|
||||
index++;
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
BKE_pbvh_node_mark_redraw(node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (PBVHNode *node : bke::pbvh::search_gather(ss->pbvh, {})) {
|
||||
BKE_pbvh_node_mark_update_mask(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Main function to restore the original state of the data to how it was before starting the expand
|
||||
|
@ -1392,25 +1388,6 @@ static void sculpt_expand_colors_update_task(SculptSession *ss, PBVHNode *node)
|
|||
}
|
||||
}
|
||||
|
||||
static void sculpt_expand_flush_updates(bContext *C)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
switch (ss->expand_cache->target) {
|
||||
case SCULPT_EXPAND_TARGET_MASK:
|
||||
SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_FACE_SETS:
|
||||
SCULPT_flush_update_step(C, SCULPT_UPDATE_FACE_SET);
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_COLORS:
|
||||
SCULPT_flush_update_step(C, SCULPT_UPDATE_COLOR);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the original mesh data state in the expand cache. */
|
||||
static void sculpt_expand_original_state_store(Object *ob, Cache *expand_cache)
|
||||
{
|
||||
|
@ -1492,10 +1469,12 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const PBVHV
|
|||
sculpt_expand_mask_update_task(ss, mask_write, expand_cache->nodes[i]);
|
||||
}
|
||||
});
|
||||
SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
|
||||
break;
|
||||
}
|
||||
case SCULPT_EXPAND_TARGET_FACE_SETS:
|
||||
sculpt_expand_face_sets_update(*ob, expand_cache);
|
||||
SCULPT_flush_update_step(C, SCULPT_UPDATE_FACE_SET);
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_COLORS:
|
||||
threading::parallel_for(expand_cache->nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
|
@ -1503,10 +1482,9 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const PBVHV
|
|||
sculpt_expand_colors_update_task(ss, expand_cache->nodes[i]);
|
||||
}
|
||||
});
|
||||
SCULPT_flush_update_step(C, SCULPT_UPDATE_COLOR);
|
||||
break;
|
||||
}
|
||||
|
||||
sculpt_expand_flush_updates(C);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2059,17 +2037,17 @@ static void sculpt_expand_undo_push(Object *ob, Cache *expand_cache)
|
|||
switch (expand_cache->target) {
|
||||
case SCULPT_EXPAND_TARGET_MASK:
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
}
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_FACE_SETS:
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::FaceSet);
|
||||
undo::push_node(*ob, node, undo::Type::FaceSet);
|
||||
}
|
||||
break;
|
||||
case SCULPT_EXPAND_TARGET_COLORS:
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Color);
|
||||
undo::push_node(*ob, node, undo::Type::Color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ static void do_draw_face_sets_brush_faces(Object *ob,
|
|||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
if (changed) {
|
||||
undo::push_node(ob, node, undo::Type::FaceSet);
|
||||
undo::push_node(*ob, node, undo::Type::FaceSet);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -310,7 +310,7 @@ static void do_draw_face_sets_brush_grids(Object *ob,
|
|||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
if (changed) {
|
||||
undo::push_node(ob, node, undo::Type::FaceSet);
|
||||
undo::push_node(*ob, node, undo::Type::FaceSet);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -397,7 +397,7 @@ static void do_draw_face_sets_brush_bmesh(Object *ob,
|
|||
}
|
||||
|
||||
if (changed) {
|
||||
undo::push_node(ob, node, undo::Type::FaceSet);
|
||||
undo::push_node(*ob, node, undo::Type::FaceSet);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -521,7 +521,7 @@ static void face_sets_update(Object &object,
|
|||
continue;
|
||||
}
|
||||
|
||||
undo::push_node(&object, node, undo::Type::FaceSet);
|
||||
undo::push_node(object, node, undo::Type::FaceSet);
|
||||
array_utils::scatter(new_face_sets.as_span(), faces, face_sets.span);
|
||||
BKE_pbvh_node_mark_update_face_sets(node);
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ static void clear_face_sets(Object &object, const Span<PBVHNode *> nodes)
|
|||
return face_sets[face] != default_face_set;
|
||||
}))
|
||||
{
|
||||
undo::push_node(&object, node, undo::Type::FaceSet);
|
||||
undo::push_node(object, node, undo::Type::FaceSet);
|
||||
BKE_pbvh_node_mark_update_face_sets(node);
|
||||
}
|
||||
}
|
||||
|
@ -826,7 +826,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
|||
|
||||
undo::push_begin(ob, op);
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::FaceSet);
|
||||
undo::push_node(*ob, node, undo::Type::FaceSet);
|
||||
}
|
||||
|
||||
const float threshold = RNA_float_get(op->ptr, "threshold");
|
||||
|
@ -1026,7 +1026,7 @@ static void face_hide_update(Object &object,
|
|||
}
|
||||
|
||||
any_changed = true;
|
||||
undo::push_node(&object, node, undo::Type::HideFace);
|
||||
undo::push_node(object, node, undo::Type::HideFace);
|
||||
array_utils::scatter(new_hide.as_span(), faces, hide_poly.span);
|
||||
BKE_pbvh_node_mark_update_visibility(node);
|
||||
}
|
||||
|
@ -1512,7 +1512,7 @@ static void sculpt_face_set_edit_modify_coordinates(
|
|||
undo::push_begin(ob, op);
|
||||
for (PBVHNode *node : nodes) {
|
||||
BKE_pbvh_node_mark_update(node);
|
||||
undo::push_node(ob, node, undo::Type::Position);
|
||||
undo::push_node(*ob, node, undo::Type::Position);
|
||||
}
|
||||
switch (mode) {
|
||||
case EditMode::FairPositions:
|
||||
|
@ -1710,7 +1710,7 @@ static void face_set_gesture_apply_mesh(gesture::GestureData &gesture_data,
|
|||
threading::parallel_for(gesture_data.nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
TLS &tls = all_tls.local();
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
undo::push_node(gesture_data.vc.obact, node, undo::Type::FaceSet);
|
||||
undo::push_node(*gesture_data.vc.obact, node, undo::Type::FaceSet);
|
||||
const Span<int> node_faces =
|
||||
BKE_pbvh_type(&pbvh) == PBVH_FACES ?
|
||||
bke::pbvh::node_face_indices_calc_mesh(pbvh, *node, tls.face_indices) :
|
||||
|
@ -1751,7 +1751,7 @@ static void face_set_gesture_apply_bmesh(gesture::GestureData &gesture_data,
|
|||
|
||||
threading::parallel_for(gesture_data.nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (PBVHNode *node : nodes.slice(range)) {
|
||||
undo::push_node(gesture_data.vc.obact, node, undo::Type::FaceSet);
|
||||
undo::push_node(*gesture_data.vc.obact, node, undo::Type::FaceSet);
|
||||
|
||||
bool any_updated = false;
|
||||
for (BMFace *face : BKE_pbvh_bmesh_node_faces(node)) {
|
||||
|
|
|
@ -171,7 +171,7 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
|
|||
undo::push_begin(ob, op);
|
||||
|
||||
for (PBVHNode *node : nodes) {
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
}
|
||||
|
||||
Array<float> prev_mask;
|
||||
|
|
|
@ -130,7 +130,7 @@ void cache_init(bContext *C,
|
|||
}
|
||||
|
||||
for (const int i : ss->filter_cache->nodes.index_range()) {
|
||||
undo::push_node(ob, ss->filter_cache->nodes[i], undo_type);
|
||||
undo::push_node(*ob, ss->filter_cache->nodes[i], undo_type);
|
||||
}
|
||||
|
||||
/* Setup orientation matrices. */
|
||||
|
|
|
@ -164,7 +164,7 @@ struct Node {
|
|||
Type type;
|
||||
|
||||
char idname[MAX_ID_NAME]; /* Name instead of pointer. */
|
||||
void *node; /* only during push, not valid afterwards! */
|
||||
const void *node; /* only during push, not valid afterwards! */
|
||||
|
||||
Array<float3> position;
|
||||
Array<float3> orig_position;
|
||||
|
@ -1612,8 +1612,8 @@ void SCULPT_cache_free(blender::ed::sculpt_paint::StrokeCache *cache);
|
|||
|
||||
namespace blender::ed::sculpt_paint::undo {
|
||||
|
||||
undo::Node *push_node(Object *ob, PBVHNode *node, undo::Type type);
|
||||
undo::Node *get_node(PBVHNode *node, undo::Type type);
|
||||
undo::Node *push_node(const Object &object, const PBVHNode *node, undo::Type type);
|
||||
undo::Node *get_node(const PBVHNode *node, undo::Type type);
|
||||
|
||||
/**
|
||||
* Pushes an undo step using the operator name. This is necessary for
|
||||
|
@ -1802,14 +1802,21 @@ void SCULPT_OT_face_sets_edit(wmOperatorType *ot);
|
|||
|
||||
void SCULPT_OT_face_set_lasso_gesture(wmOperatorType *ot);
|
||||
void SCULPT_OT_face_set_box_gesture(wmOperatorType *ot);
|
||||
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Transform Operators
|
||||
* \{ */
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
void SCULPT_OT_set_pivot_position(wmOperatorType *ot);
|
||||
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -53,7 +53,7 @@ static void mask_init_task(Object *ob,
|
|||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
PBVHVertexIter vd;
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
float mask;
|
||||
switch (mode) {
|
||||
|
|
|
@ -199,7 +199,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
|
|||
* are logged as added (as opposed to attempting to store just the
|
||||
* parts that symmetrize modifies). */
|
||||
undo::push_begin(ob, op);
|
||||
undo::push_node(ob, nullptr, undo::Type::DyntopoSymmetrize);
|
||||
undo::push_node(*ob, nullptr, undo::Type::DyntopoSymmetrize);
|
||||
BM_log_before_all_removed(ss->bm, ss->bm_log);
|
||||
|
||||
BM_mesh_toolflags_set(ss->bm, true);
|
||||
|
@ -329,7 +329,7 @@ void ensure_valid_pivot(const Object *ob, Scene *scene)
|
|||
|
||||
/* No valid pivot? Use bounding box center. */
|
||||
if (ups->average_stroke_counter == 0 || !ups->last_stroke_valid) {
|
||||
const Bounds<float3> bounds = BKE_pbvh_bounding_box(ob->sculpt->pbvh);
|
||||
const Bounds<float3> bounds = bke::pbvh::bounds_get(*ob->sculpt->pbvh);
|
||||
const float3 center = math::midpoint(bounds.min, bounds.max);
|
||||
const float3 location = math::transform_point(ob->object_to_world(), center);
|
||||
|
||||
|
@ -417,7 +417,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
|
|||
}
|
||||
dyntopo::enable_ex(bmain, depsgraph, ob);
|
||||
if (has_undo) {
|
||||
undo::push_node(ob, nullptr, undo::Type::DyntopoBegin);
|
||||
undo::push_node(*ob, nullptr, undo::Type::DyntopoBegin);
|
||||
undo::push_end(ob);
|
||||
}
|
||||
}
|
||||
|
@ -758,7 +758,7 @@ static void do_mask_by_color_contiguous_update_node(Object *ob,
|
|||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
bool update_node = false;
|
||||
|
||||
PBVHVertexIter vd;
|
||||
|
@ -869,7 +869,7 @@ static void do_mask_by_color_task(Object *ob,
|
|||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
bool update_node = false;
|
||||
|
||||
float active_color[4];
|
||||
|
@ -1044,7 +1044,7 @@ static void sculpt_bake_cavity_exec_task(Object *ob,
|
|||
SculptSession *ss = ob->sculpt;
|
||||
PBVHVertexIter vd;
|
||||
|
||||
undo::push_node(ob, node, undo::Type::Mask);
|
||||
undo::push_node(*ob, node, undo::Type::Mask);
|
||||
|
||||
auto_mask::NodeData automask_data = auto_mask::node_begin(*ob, &automasking, *node);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ static void apply_projection(gesture::GestureData &gesture_data, PBVHNode *node)
|
|||
PBVHVertexIter vd;
|
||||
bool any_updated = false;
|
||||
|
||||
undo::push_node(gesture_data.vc.obact, node, undo::Type::Position);
|
||||
undo::push_node(*gesture_data.vc.obact, node, undo::Type::Position);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (gesture_data.ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
float vertex_normal[3];
|
||||
|
|
|
@ -37,15 +37,10 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
using blender::float3;
|
||||
using blender::MutableSpan;
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
void ED_sculpt_init_transform(bContext *C,
|
||||
Object *ob,
|
||||
const float mval_fl[2],
|
||||
const char *undo_name)
|
||||
void init_transform(bContext *C, Object *ob, const float mval_fl[2], const char *undo_name)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
|
@ -75,10 +70,10 @@ void ED_sculpt_init_transform(bContext *C,
|
|||
}
|
||||
}
|
||||
|
||||
static void sculpt_transform_matrices_init(SculptSession *ss,
|
||||
const ePaintSymmetryFlags symm,
|
||||
const SculptTransformDisplacementMode t_mode,
|
||||
float r_transform_mats[8][4][4])
|
||||
static void transform_matrices_init(SculptSession *ss,
|
||||
const ePaintSymmetryFlags symm,
|
||||
const SculptTransformDisplacementMode t_mode,
|
||||
float r_transform_mats[8][4][4])
|
||||
{
|
||||
|
||||
float final_pivot_pos[3], d_t[3], d_r[4], d_s[3];
|
||||
|
@ -139,9 +134,8 @@ static void sculpt_transform_matrices_init(SculptSession *ss,
|
|||
}
|
||||
}
|
||||
|
||||
static void sculpt_transform_task(Object *ob, const float transform_mats[8][4][4], PBVHNode *node)
|
||||
static void transform_node(Object *ob, const float transform_mats[8][4][4], PBVHNode *node)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
SculptOrigVertData orig_data;
|
||||
|
@ -149,7 +143,7 @@ static void sculpt_transform_task(Object *ob, const float transform_mats[8][4][4
|
|||
|
||||
PBVHVertexIter vd;
|
||||
|
||||
undo::push_node(ob, node, undo::Type::Position);
|
||||
undo::push_node(*ob, node, undo::Type::Position);
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_data, &vd);
|
||||
float *start_co;
|
||||
|
@ -180,30 +174,27 @@ static void sculpt_transform_task(Object *ob, const float transform_mats[8][4][4
|
|||
|
||||
static void sculpt_transform_all_vertices(Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const ePaintSymmetryFlags symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
|
||||
float transform_mats[8][4][4];
|
||||
sculpt_transform_matrices_init(
|
||||
ss, symm, ss->filter_cache->transform_displacement_mode, transform_mats);
|
||||
transform_matrices_init(ss, symm, ss->filter_cache->transform_displacement_mode, transform_mats);
|
||||
|
||||
/* Regular transform applies all symmetry passes at once as it is split by symmetry areas
|
||||
* (each vertex can only be transformed once by the transform matrix of its area). */
|
||||
threading::parallel_for(ss->filter_cache->nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
sculpt_transform_task(ob, transform_mats, ss->filter_cache->nodes[i]);
|
||||
transform_node(ob, transform_mats, ss->filter_cache->nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void sculpt_elastic_transform_task(Object *ob,
|
||||
const float transform_radius,
|
||||
const float elastic_transform_mat[4][4],
|
||||
const float elastic_transform_pivot[3],
|
||||
PBVHNode *node)
|
||||
static void elastic_transform_node(Object *ob,
|
||||
const float transform_radius,
|
||||
const float elastic_transform_mat[4][4],
|
||||
const float elastic_transform_pivot[3],
|
||||
PBVHNode *node)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
const MutableSpan<float3> proxy = BKE_pbvh_node_add_proxy(*ss->pbvh, *node).co;
|
||||
|
@ -220,7 +211,7 @@ static void sculpt_elastic_transform_task(Object *ob,
|
|||
const float poisson_ratio = 0.4f;
|
||||
BKE_kelvinlet_init_params(¶ms, transform_radius, force, shear_modulus, poisson_ratio);
|
||||
|
||||
undo::push_node(ob, node, undo::Type::Position);
|
||||
undo::push_node(*ob, node, undo::Type::Position);
|
||||
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
|
@ -244,9 +235,8 @@ static void sculpt_elastic_transform_task(Object *ob,
|
|||
BKE_pbvh_node_mark_update(node);
|
||||
}
|
||||
|
||||
static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float transform_radius)
|
||||
static void transform_radius_elastic(Sculpt *sd, Object *ob, const float transform_radius)
|
||||
{
|
||||
using namespace blender;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
BLI_assert(ss->filter_cache->transform_displacement_mode ==
|
||||
SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL);
|
||||
|
@ -254,8 +244,7 @@ static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float
|
|||
const ePaintSymmetryFlags symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
|
||||
float transform_mats[8][4][4];
|
||||
sculpt_transform_matrices_init(
|
||||
ss, symm, ss->filter_cache->transform_displacement_mode, transform_mats);
|
||||
transform_matrices_init(ss, symm, ss->filter_cache->transform_displacement_mode, transform_mats);
|
||||
|
||||
/* Elastic transform needs to apply all transform matrices to all vertices and then combine the
|
||||
* displacement proxies as all vertices are modified by all symmetry passes. */
|
||||
|
@ -272,11 +261,11 @@ static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float
|
|||
threading::parallel_for(
|
||||
ss->filter_cache->nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
sculpt_elastic_transform_task(ob,
|
||||
transform_radius,
|
||||
elastic_transform_mat,
|
||||
elastic_transform_pivot,
|
||||
ss->filter_cache->nodes[i]);
|
||||
elastic_transform_node(ob,
|
||||
transform_radius,
|
||||
elastic_transform_mat,
|
||||
elastic_transform_pivot,
|
||||
ss->filter_cache->nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -284,7 +273,7 @@ static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float
|
|||
SCULPT_combine_transform_proxies(sd, ob);
|
||||
}
|
||||
|
||||
void ED_sculpt_update_modal_transform(bContext *C, Object *ob)
|
||||
void update_modal_transform(bContext *C, Object *ob)
|
||||
{
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
@ -313,7 +302,7 @@ void ED_sculpt_update_modal_transform(bContext *C, Object *ob)
|
|||
&vc, ss->init_pivot_pos, BKE_brush_size_get(scene, brush));
|
||||
}
|
||||
|
||||
sculpt_transform_radius_elastic(sd, ob, transform_radius);
|
||||
transform_radius_elastic(sd, ob, transform_radius);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -329,9 +318,8 @@ void ED_sculpt_update_modal_transform(bContext *C, Object *ob)
|
|||
SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
|
||||
}
|
||||
|
||||
void ED_sculpt_end_transform(bContext *C, Object *ob)
|
||||
void end_transform(bContext *C, Object *ob)
|
||||
{
|
||||
using namespace blender::ed::sculpt_paint;
|
||||
SculptSession *ss = ob->sculpt;
|
||||
if (ss->filter_cache) {
|
||||
filter::cache_free(ss);
|
||||
|
@ -339,36 +327,36 @@ void ED_sculpt_end_transform(bContext *C, Object *ob)
|
|||
SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
|
||||
}
|
||||
|
||||
enum eSculptPivotPositionModes {
|
||||
SCULPT_PIVOT_POSITION_ORIGIN = 0,
|
||||
SCULPT_PIVOT_POSITION_UNMASKED = 1,
|
||||
SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
|
||||
SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
|
||||
SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
|
||||
enum class PivotPositionMode {
|
||||
Origin = 0,
|
||||
Unmasked = 1,
|
||||
MaskBorder = 2,
|
||||
ActiveVert = 3,
|
||||
CursorSurface = 4,
|
||||
};
|
||||
|
||||
static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
|
||||
{SCULPT_PIVOT_POSITION_ORIGIN,
|
||||
{int(PivotPositionMode::Origin),
|
||||
"ORIGIN",
|
||||
0,
|
||||
"Origin",
|
||||
"Sets the pivot to the origin of the sculpt"},
|
||||
{SCULPT_PIVOT_POSITION_UNMASKED,
|
||||
{int(PivotPositionMode::Unmasked),
|
||||
"UNMASKED",
|
||||
0,
|
||||
"Unmasked",
|
||||
"Sets the pivot position to the average position of the unmasked vertices"},
|
||||
{SCULPT_PIVOT_POSITION_MASK_BORDER,
|
||||
{int(PivotPositionMode::MaskBorder),
|
||||
"BORDER",
|
||||
0,
|
||||
"Mask Border",
|
||||
"Sets the pivot position to the center of the border of the mask"},
|
||||
{SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
|
||||
{int(PivotPositionMode::ActiveVert),
|
||||
"ACTIVE",
|
||||
0,
|
||||
"Active Vertex",
|
||||
"Sets the pivot position to the active vertex position"},
|
||||
{SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
|
||||
{int(PivotPositionMode::CursorSurface),
|
||||
"SURFACE",
|
||||
0,
|
||||
"Surface",
|
||||
|
@ -376,7 +364,7 @@ static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
|
|||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
|
||||
static int set_pivot_position_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
@ -384,7 +372,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
|
|||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
|
||||
|
||||
int mode = RNA_enum_get(op->ptr, "mode");
|
||||
const PivotPositionMode mode = PivotPositionMode(RNA_enum_get(op->ptr, "mode"));
|
||||
|
||||
const View3D *v3d = CTX_wm_view3d(C);
|
||||
const Base *base = CTX_data_active_base(C);
|
||||
|
@ -395,15 +383,15 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
|
|||
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
|
||||
|
||||
/* Pivot to center. */
|
||||
if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
|
||||
if (mode == PivotPositionMode::Origin) {
|
||||
zero_v3(ss->pivot_pos);
|
||||
}
|
||||
/* Pivot to active vertex. */
|
||||
else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
|
||||
else if (mode == PivotPositionMode::ActiveVert) {
|
||||
copy_v3_v3(ss->pivot_pos, SCULPT_active_vertex_co_get(ss));
|
||||
}
|
||||
/* Pivot to ray-cast surface. */
|
||||
else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
|
||||
else if (mode == PivotPositionMode::CursorSurface) {
|
||||
float stroke_location[3];
|
||||
const float mval[2] = {
|
||||
RNA_float_get(op->ptr, "mouse_x"),
|
||||
|
@ -414,14 +402,14 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
}
|
||||
else {
|
||||
blender::Vector<PBVHNode *> nodes = blender::bke::pbvh::search_gather(ss->pbvh, {});
|
||||
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(ss->pbvh, {});
|
||||
|
||||
float avg[3];
|
||||
int total = 0;
|
||||
zero_v3(avg);
|
||||
|
||||
/* Pivot to unmasked. */
|
||||
if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
|
||||
if (mode == PivotPositionMode::Unmasked) {
|
||||
for (PBVHNode *node : nodes) {
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
|
@ -437,7 +425,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
}
|
||||
/* Pivot to mask border. */
|
||||
else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
|
||||
else if (mode == PivotPositionMode::MaskBorder) {
|
||||
const float threshold = 0.2f;
|
||||
|
||||
for (PBVHNode *node : nodes) {
|
||||
|
@ -473,30 +461,28 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
static int set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
RNA_float_set(op->ptr, "mouse_x", event->mval[0]);
|
||||
RNA_float_set(op->ptr, "mouse_y", event->mval[1]);
|
||||
return sculpt_set_pivot_position_exec(C, op);
|
||||
return set_pivot_position_exec(C, op);
|
||||
}
|
||||
|
||||
void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers. */
|
||||
ot->name = "Set Pivot Position";
|
||||
ot->idname = "SCULPT_OT_set_pivot_position";
|
||||
ot->description = "Sets the sculpt transform pivot position";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->invoke = sculpt_set_pivot_position_invoke;
|
||||
ot->exec = sculpt_set_pivot_position_exec;
|
||||
ot->invoke = set_pivot_position_invoke;
|
||||
ot->exec = set_pivot_position_exec;
|
||||
ot->poll = SCULPT_mode_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
|
||||
RNA_def_enum(ot->srna,
|
||||
"mode",
|
||||
prop_sculpt_pivot_position_types,
|
||||
SCULPT_PIVOT_POSITION_UNMASKED,
|
||||
int(PivotPositionMode::Unmasked),
|
||||
"Mode",
|
||||
"");
|
||||
|
||||
|
@ -519,3 +505,5 @@ void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
|
|||
0.0f,
|
||||
10000.0f);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
||||
|
|
|
@ -454,7 +454,7 @@ static void gesture_begin(bContext &C, gesture::GestureData &gesture_data)
|
|||
generate_geometry(gesture_data);
|
||||
SCULPT_topology_islands_invalidate(ss);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, gesture_data.vc.obact, false);
|
||||
undo::push_node(gesture_data.vc.obact, nullptr, undo::Type::Geometry);
|
||||
undo::push_node(*gesture_data.vc.obact, nullptr, undo::Type::Geometry);
|
||||
}
|
||||
|
||||
static int bm_face_isect_pair(BMFace *f, void * /*user_data*/)
|
||||
|
@ -591,7 +591,7 @@ static void gesture_end(bContext & /*C*/, gesture::GestureData &gesture_data)
|
|||
|
||||
free_geometry(gesture_data);
|
||||
|
||||
undo::push_node(gesture_data.vc.obact, nullptr, undo::Type::Geometry);
|
||||
undo::push_node(*gesture_data.vc.obact, nullptr, undo::Type::Geometry);
|
||||
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
|
||||
DEG_id_tag_update(&gesture_data.vc.obact->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ struct SculptUndoStep {
|
|||
};
|
||||
|
||||
static UndoSculpt *get_nodes();
|
||||
static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr);
|
||||
static void sculpt_save_active_attribute(Object &object, SculptAttrRef *attr);
|
||||
static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p);
|
||||
|
||||
#ifdef SCULPT_UNDO_DEBUG
|
||||
|
@ -193,7 +193,7 @@ static void print_sculpt_node(Object *ob, Node *node)
|
|||
printf(" %s:%s {applied=%d}\n", undo_type_to_str(node->type), node->idname, node->applied);
|
||||
|
||||
if (node->bm_entry) {
|
||||
BM_log_print_entry(ob->sculpt ? ob->sculpt->bm : nullptr, node->bm_entry);
|
||||
BM_log_print_entry(object.sculpt ? object.sculpt->bm : nullptr, node->bm_entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ struct PartialUpdateData {
|
|||
|
||||
static void update_modified_node_mesh(PBVHNode &node, PartialUpdateData &data)
|
||||
{
|
||||
const Span<int> verts = BKE_pbvh_node_get_vert_indices(&node);
|
||||
const Span<int> verts = bke::pbvh::node_verts(node);
|
||||
if (!data.modified_position_verts.is_empty()) {
|
||||
for (const int vert : verts) {
|
||||
if (data.modified_position_verts[vert]) {
|
||||
|
@ -352,7 +352,7 @@ static void update_modified_node_mesh(PBVHNode &node, PartialUpdateData &data)
|
|||
|
||||
static void update_modified_node_grids(PBVHNode &node, PartialUpdateData &data)
|
||||
{
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(node);
|
||||
const Span<int> grid_indices = bke::pbvh::node_grid_indices(node);
|
||||
if (std::any_of(grid_indices.begin(), grid_indices.end(), [&](const int grid) {
|
||||
return data.modified_grids[grid];
|
||||
}))
|
||||
|
@ -413,10 +413,13 @@ static bool restore_deformed(
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool restore_coords(
|
||||
bContext *C, Object *ob, Depsgraph *depsgraph, Node &unode, MutableSpan<bool> modified_verts)
|
||||
static bool restore_coords(bContext *C,
|
||||
Object &object,
|
||||
Depsgraph *depsgraph,
|
||||
Node &unode,
|
||||
MutableSpan<bool> modified_verts)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptSession *ss = object.sculpt;
|
||||
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
|
||||
|
||||
if (unode.mesh_verts_num) {
|
||||
|
@ -425,14 +428,14 @@ static bool restore_coords(
|
|||
if (ss->shapekey_active && !STREQ(ss->shapekey_active->name, unode.shapeName)) {
|
||||
/* Shape key has been changed before calling undo operator. */
|
||||
|
||||
Key *key = BKE_key_from_object(ob);
|
||||
Key *key = BKE_key_from_object(&object);
|
||||
KeyBlock *kb = key ? BKE_keyblock_find_name(key, unode.shapeName) : nullptr;
|
||||
|
||||
if (kb) {
|
||||
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
|
||||
object.shapenr = BLI_findindex(&key->block, kb) + 1;
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, &object, false);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_DATA, &object);
|
||||
}
|
||||
else {
|
||||
/* Key has been removed -- skip this undo node. */
|
||||
|
@ -445,7 +448,7 @@ static bool restore_coords(
|
|||
MutableSpan<float3> positions = ss->vert_positions;
|
||||
|
||||
if (ss->shapekey_active) {
|
||||
float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active);
|
||||
float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(&object, ss->shapekey_active);
|
||||
MutableSpan key_positions(reinterpret_cast<float3 *>(vertCos), ss->shapekey_active->totelem);
|
||||
|
||||
if (!unode.orig_position.is_empty()) {
|
||||
|
@ -467,7 +470,7 @@ static bool restore_coords(
|
|||
}
|
||||
|
||||
/* Propagate new coords to keyblock. */
|
||||
SCULPT_vertcos_to_key(ob, ss->shapekey_active, key_positions);
|
||||
SCULPT_vertcos_to_key(&object, ss->shapekey_active, key_positions);
|
||||
|
||||
/* PBVH uses its own vertex array, so coords should be */
|
||||
/* propagated to PBVH here. */
|
||||
|
@ -518,13 +521,13 @@ static bool restore_coords(
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool restore_hidden(Object *ob, Node &unode, MutableSpan<bool> modified_vertices)
|
||||
static bool restore_hidden(Object &object, Node &unode, MutableSpan<bool> modified_vertices)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptSession *ss = object.sculpt;
|
||||
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
|
||||
|
||||
if (unode.mesh_verts_num) {
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob->data);
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
bke::SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_span<bool>(
|
||||
".hide_vert", bke::AttrDomain::Point);
|
||||
|
@ -586,9 +589,9 @@ static bool restore_hidden_face(Object &object, Node &unode, MutableSpan<bool> m
|
|||
return modified;
|
||||
}
|
||||
|
||||
static bool restore_color(Object *ob, Node &unode, MutableSpan<bool> modified_vertices)
|
||||
static bool restore_color(Object &object, Node &unode, MutableSpan<bool> modified_vertices)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptSession *ss = object.sculpt;
|
||||
|
||||
bool modified = false;
|
||||
|
||||
|
@ -600,7 +603,7 @@ static bool restore_color(Object *ob, Node &unode, MutableSpan<bool> modified_ve
|
|||
modified = true;
|
||||
}
|
||||
|
||||
Mesh *mesh = BKE_object_get_original_mesh(ob);
|
||||
Mesh *mesh = BKE_object_get_original_mesh(&object);
|
||||
|
||||
if (!unode.loop_col.is_empty() && unode.mesh_corners_num == mesh->corners_num) {
|
||||
BKE_pbvh_swap_colors(ss->pbvh, unode.corner_indices, unode.loop_col);
|
||||
|
@ -614,10 +617,10 @@ static bool restore_color(Object *ob, Node &unode, MutableSpan<bool> modified_ve
|
|||
return modified;
|
||||
}
|
||||
|
||||
static bool restore_mask(Object *ob, Node &unode, MutableSpan<bool> modified_vertices)
|
||||
static bool restore_mask(Object &object, Node &unode, MutableSpan<bool> modified_vertices)
|
||||
{
|
||||
Mesh *mesh = BKE_object_get_original_mesh(ob);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Mesh *mesh = BKE_object_get_original_mesh(&object);
|
||||
SculptSession *ss = object.sculpt;
|
||||
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
|
||||
|
||||
if (unode.mesh_verts_num) {
|
||||
|
@ -656,11 +659,13 @@ static bool restore_mask(Object *ob, Node &unode, MutableSpan<bool> modified_ver
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool restore_face_sets(Object *ob, Node &unode, MutableSpan<bool> modified_face_set_faces)
|
||||
static bool restore_face_sets(Object &object,
|
||||
Node &unode,
|
||||
MutableSpan<bool> modified_face_set_faces)
|
||||
{
|
||||
const Span<int> face_indices = unode.face_indices;
|
||||
|
||||
bke::SpanAttributeWriter<int> face_sets = face_set::ensure_face_sets_mesh(*ob);
|
||||
bke::SpanAttributeWriter<int> face_sets = face_set::ensure_face_sets_mesh(object);
|
||||
bool modified = false;
|
||||
for (const int i : face_indices.index_range()) {
|
||||
const int face = face_indices[i];
|
||||
|
@ -675,7 +680,7 @@ static bool restore_face_sets(Object *ob, Node &unode, MutableSpan<bool> modifie
|
|||
return modified;
|
||||
}
|
||||
|
||||
static void bmesh_restore_generic(Node &unode, Object *ob, SculptSession *ss)
|
||||
static void bmesh_restore_generic(Node &unode, Object &object, SculptSession *ss)
|
||||
{
|
||||
if (unode.applied) {
|
||||
BM_log_undo(ss->bm, ss->bm_log);
|
||||
|
@ -693,17 +698,17 @@ static void bmesh_restore_generic(Node &unode, Object *ob, SculptSession *ss)
|
|||
}
|
||||
}
|
||||
else {
|
||||
SCULPT_pbvh_clear(ob);
|
||||
SCULPT_pbvh_clear(&object);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create empty sculpt BMesh and enable logging. */
|
||||
static void bmesh_enable(Object *ob, Node &unode)
|
||||
static void bmesh_enable(Object &object, Node &unode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
||||
SculptSession *ss = object.sculpt;
|
||||
Mesh *mesh = static_cast<Mesh *>(object.data);
|
||||
|
||||
SCULPT_pbvh_clear(ob);
|
||||
SCULPT_pbvh_clear(&object);
|
||||
|
||||
/* Create empty BMesh and enable logging. */
|
||||
BMeshCreateParams bmesh_create_params{};
|
||||
|
@ -718,14 +723,14 @@ static void bmesh_enable(Object *ob, Node &unode)
|
|||
ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode.bm_entry);
|
||||
}
|
||||
|
||||
static void bmesh_restore_begin(bContext *C, Node &unode, Object *ob, SculptSession *ss)
|
||||
static void bmesh_restore_begin(bContext *C, Node &unode, Object &object, SculptSession *ss)
|
||||
{
|
||||
if (unode.applied) {
|
||||
dyntopo::disable(C, &unode);
|
||||
unode.applied = false;
|
||||
}
|
||||
else {
|
||||
bmesh_enable(ob, unode);
|
||||
bmesh_enable(object, unode);
|
||||
|
||||
/* Restore the mesh from the first log entry. */
|
||||
BM_log_redo(ss->bm, ss->bm_log);
|
||||
|
@ -734,10 +739,10 @@ static void bmesh_restore_begin(bContext *C, Node &unode, Object *ob, SculptSess
|
|||
}
|
||||
}
|
||||
|
||||
static void bmesh_restore_end(bContext *C, Node &unode, Object *ob, SculptSession *ss)
|
||||
static void bmesh_restore_end(bContext *C, Node &unode, Object &object, SculptSession *ss)
|
||||
{
|
||||
if (unode.applied) {
|
||||
bmesh_enable(ob, unode);
|
||||
bmesh_enable(object, unode);
|
||||
|
||||
/* Restore the mesh from the last log entry. */
|
||||
BM_log_undo(ss->bm, ss->bm_log);
|
||||
|
@ -751,9 +756,9 @@ static void bmesh_restore_end(bContext *C, Node &unode, Object *ob, SculptSessio
|
|||
}
|
||||
}
|
||||
|
||||
static void store_geometry_data(NodeGeometry *geometry, Object *object)
|
||||
static void store_geometry_data(NodeGeometry *geometry, const Object &object)
|
||||
{
|
||||
Mesh *mesh = static_cast<Mesh *>(object->data);
|
||||
const Mesh *mesh = static_cast<const Mesh *>(object.data);
|
||||
|
||||
BLI_assert(!geometry->is_initialized);
|
||||
geometry->is_initialized = true;
|
||||
|
@ -774,9 +779,9 @@ static void store_geometry_data(NodeGeometry *geometry, Object *object)
|
|||
geometry->faces_num = mesh->faces_num;
|
||||
}
|
||||
|
||||
static void restore_geometry_data(NodeGeometry *geometry, Object *object)
|
||||
static void restore_geometry_data(NodeGeometry *geometry, Object &object)
|
||||
{
|
||||
Mesh *mesh = static_cast<Mesh *>(object->data);
|
||||
Mesh *mesh = static_cast<Mesh *>(object.data);
|
||||
|
||||
BLI_assert(geometry->is_initialized);
|
||||
|
||||
|
@ -809,10 +814,10 @@ static void geometry_free_data(NodeGeometry *geometry)
|
|||
&geometry->face_offsets_sharing_info);
|
||||
}
|
||||
|
||||
static void restore_geometry(Node &unode, Object *object)
|
||||
static void restore_geometry(Node &unode, Object &object)
|
||||
{
|
||||
if (unode.geometry_clear_pbvh) {
|
||||
SCULPT_pbvh_clear(object);
|
||||
SCULPT_pbvh_clear(&object);
|
||||
}
|
||||
|
||||
if (unode.applied) {
|
||||
|
@ -829,19 +834,19 @@ static void restore_geometry(Node &unode, Object *object)
|
|||
*
|
||||
* Returns true if this was a dynamic-topology undo step, otherwise
|
||||
* returns false to indicate the non-dyntopo code should run. */
|
||||
static int bmesh_restore(bContext *C, Node &unode, Object *ob, SculptSession *ss)
|
||||
static int bmesh_restore(bContext *C, Node &unode, Object &object, SculptSession *ss)
|
||||
{
|
||||
switch (unode.type) {
|
||||
case Type::DyntopoBegin:
|
||||
bmesh_restore_begin(C, unode, ob, ss);
|
||||
bmesh_restore_begin(C, unode, object, ss);
|
||||
return true;
|
||||
|
||||
case Type::DyntopoEnd:
|
||||
bmesh_restore_end(C, unode, ob, ss);
|
||||
bmesh_restore_end(C, unode, object, ss);
|
||||
return true;
|
||||
default:
|
||||
if (ss->bm_log) {
|
||||
bmesh_restore_generic(unode, ob, ss);
|
||||
bmesh_restore_generic(unode, object, ss);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -865,14 +870,14 @@ static int bmesh_restore(bContext *C, Node &unode, Object *ob, SculptSession *ss
|
|||
* so if the object's modifier stack references other object it is all fine. */
|
||||
static void refine_subdiv(Depsgraph *depsgraph,
|
||||
SculptSession *ss,
|
||||
Object *object,
|
||||
Object &object,
|
||||
bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
Array<float3> deformed_verts = BKE_multires_create_deformed_base_mesh_vert_coords(
|
||||
depsgraph, object, ss->multires.modifier);
|
||||
depsgraph, &object, ss->multires.modifier);
|
||||
|
||||
bke::subdiv::eval_refine_from_mesh(subdiv,
|
||||
static_cast<const Mesh *>(object->data),
|
||||
static_cast<const Mesh *>(object.data),
|
||||
reinterpret_cast<float(*)[3]>(deformed_verts.data()));
|
||||
}
|
||||
|
||||
|
@ -882,8 +887,8 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
|||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(view_layer);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Object &object = *BKE_view_layer_active_object_get(view_layer);
|
||||
SculptSession *ss = object.sculpt;
|
||||
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
|
||||
|
||||
bool clear_automask_cache = false;
|
||||
|
@ -907,10 +912,10 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
|||
* ensure object is updated after the node is handled. */
|
||||
const Node *first_unode = usculpt.nodes.first().get();
|
||||
if (first_unode->type != Type::Geometry) {
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, &object, false);
|
||||
}
|
||||
|
||||
if (bmesh_restore(C, *usculpt.nodes.first(), ob, ss)) {
|
||||
if (bmesh_restore(C, *usculpt.nodes.first(), object, ss)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -936,7 +941,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
|||
Vector<bool> modified_faces_face_set;
|
||||
Vector<bool> modified_grids;
|
||||
for (std::unique_ptr<Node> &unode : usculpt.nodes) {
|
||||
if (!STREQ(unode->idname, ob->id.name)) {
|
||||
if (!STREQ(unode->idname, object.id.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -959,44 +964,44 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
|||
switch (unode->type) {
|
||||
case Type::Position:
|
||||
modified_verts_position.resize(ss->totvert, false);
|
||||
if (restore_coords(C, ob, depsgraph, *unode, modified_verts_position)) {
|
||||
if (restore_coords(C, object, depsgraph, *unode, modified_verts_position)) {
|
||||
changed_position = true;
|
||||
}
|
||||
break;
|
||||
case Type::HideVert:
|
||||
modified_verts_hide.resize(ss->totvert, false);
|
||||
if (restore_hidden(ob, *unode, modified_verts_hide)) {
|
||||
if (restore_hidden(object, *unode, modified_verts_hide)) {
|
||||
changed_hide_vert = true;
|
||||
}
|
||||
break;
|
||||
case Type::HideFace:
|
||||
modified_faces_hide.resize(ss->totfaces, false);
|
||||
if (restore_hidden_face(*ob, *unode, modified_faces_hide)) {
|
||||
if (restore_hidden_face(object, *unode, modified_faces_hide)) {
|
||||
changed_hide_face = true;
|
||||
}
|
||||
break;
|
||||
case Type::Mask:
|
||||
modified_verts_mask.resize(ss->totvert, false);
|
||||
if (restore_mask(ob, *unode, modified_verts_mask)) {
|
||||
if (restore_mask(object, *unode, modified_verts_mask)) {
|
||||
changed_mask = true;
|
||||
}
|
||||
break;
|
||||
case Type::FaceSet:
|
||||
modified_faces_face_set.resize(ss->totfaces, false);
|
||||
if (restore_face_sets(ob, *unode, modified_faces_face_set)) {
|
||||
if (restore_face_sets(object, *unode, modified_faces_face_set)) {
|
||||
changed_face_sets = true;
|
||||
}
|
||||
break;
|
||||
case Type::Color:
|
||||
modified_verts_color.resize(ss->totvert, false);
|
||||
if (restore_color(ob, *unode, modified_verts_color)) {
|
||||
if (restore_color(object, *unode, modified_verts_color)) {
|
||||
changed_color = true;
|
||||
}
|
||||
break;
|
||||
case Type::Geometry:
|
||||
restore_geometry(*unode, ob);
|
||||
restore_geometry(*unode, object);
|
||||
changed_all_geometry = true;
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, false);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, &object, false);
|
||||
break;
|
||||
|
||||
case Type::DyntopoBegin:
|
||||
|
@ -1009,7 +1014,7 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
|||
|
||||
if (use_multires_undo) {
|
||||
for (std::unique_ptr<Node> &unode : usculpt.nodes) {
|
||||
if (!STREQ(unode->idname, ob->id.name)) {
|
||||
if (!STREQ(unode->idname, object.id.name)) {
|
||||
continue;
|
||||
}
|
||||
modified_grids.resize(unode->mesh_grids_num, false);
|
||||
|
@ -1018,10 +1023,10 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
|||
}
|
||||
|
||||
if (subdiv_ccg != nullptr && changed_all_geometry) {
|
||||
refine_subdiv(depsgraph, ss, ob, subdiv_ccg->subdiv);
|
||||
refine_subdiv(depsgraph, ss, object, subdiv_ccg->subdiv);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
|
||||
DEG_id_tag_update(&object.id, ID_RECALC_SHADING);
|
||||
|
||||
if (!changed_position && !changed_hide_vert && !changed_hide_face && !changed_mask &&
|
||||
!changed_face_sets && !changed_color)
|
||||
|
@ -1060,37 +1065,37 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
|||
bke::pbvh::update_mask(*ss->pbvh);
|
||||
}
|
||||
if (changed_hide_face) {
|
||||
hide::sync_all_from_faces(*ob);
|
||||
hide::sync_all_from_faces(object);
|
||||
bke::pbvh::update_visibility(*ss->pbvh);
|
||||
}
|
||||
if (changed_hide_vert) {
|
||||
if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_GRIDS)) {
|
||||
Mesh &mesh = *static_cast<Mesh *>(ob->data);
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
BKE_pbvh_sync_visibility_from_verts(ss->pbvh, &mesh);
|
||||
}
|
||||
bke::pbvh::update_visibility(*ss->pbvh);
|
||||
}
|
||||
|
||||
if (BKE_sculpt_multires_active(scene, ob)) {
|
||||
if (BKE_sculpt_multires_active(scene, &object)) {
|
||||
if (changed_hide_vert) {
|
||||
multires_mark_as_modified(depsgraph, ob, MULTIRES_HIDDEN_MODIFIED);
|
||||
multires_mark_as_modified(depsgraph, &object, MULTIRES_HIDDEN_MODIFIED);
|
||||
}
|
||||
else if (changed_position) {
|
||||
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
|
||||
multires_mark_as_modified(depsgraph, &object, MULTIRES_COORDS_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
const bool tag_update = ID_REAL_USERS(ob->data) > 1 ||
|
||||
!BKE_sculptsession_use_pbvh_draw(ob, rv3d) || ss->shapekey_active ||
|
||||
const bool tag_update = ID_REAL_USERS(object.data) > 1 ||
|
||||
!BKE_sculptsession_use_pbvh_draw(&object, rv3d) || ss->shapekey_active ||
|
||||
ss->deform_modifiers_active;
|
||||
|
||||
if (tag_update) {
|
||||
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
||||
Mesh *mesh = static_cast<Mesh *>(object.data);
|
||||
if (changed_position) {
|
||||
mesh->tag_positions_changed();
|
||||
BKE_sculptsession_free_deformMats(ss);
|
||||
}
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
DEG_id_tag_update(&object.id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1107,7 +1112,7 @@ static void free_list(UndoSculpt &usculpt)
|
|||
usculpt.nodes.~Vector();
|
||||
}
|
||||
|
||||
Node *get_node(PBVHNode *node, Type type)
|
||||
Node *get_node(const PBVHNode *node, const Type type)
|
||||
{
|
||||
UndoSculpt *usculpt = get_nodes();
|
||||
|
||||
|
@ -1124,9 +1129,9 @@ Node *get_node(PBVHNode *node, Type type)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static size_t alloc_and_store_hidden(SculptSession *ss, Node *unode)
|
||||
static size_t alloc_and_store_hidden(const SculptSession *ss, Node *unode)
|
||||
{
|
||||
PBVHNode *node = static_cast<PBVHNode *>(unode->node);
|
||||
const PBVHNode *node = static_cast<const PBVHNode *>(unode->node);
|
||||
if (!ss->subdiv_ccg) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1135,7 +1140,7 @@ static size_t alloc_and_store_hidden(SculptSession *ss, Node *unode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const Span<int> grid_indices = BKE_pbvh_node_get_grid_indices(*node);
|
||||
const Span<int> grid_indices = bke::pbvh::node_grid_indices(*node);
|
||||
unode->grid_hidden = BitGroupVector<>(grid_indices.size(), grid_hidden.group_size());
|
||||
for (const int i : grid_indices.index_range()) {
|
||||
unode->grid_hidden[i].copy_from(grid_hidden[grid_indices[i]]);
|
||||
|
@ -1146,7 +1151,7 @@ static size_t alloc_and_store_hidden(SculptSession *ss, Node *unode)
|
|||
|
||||
/* Allocate node and initialize its default fields specific for the given undo type.
|
||||
* Will also add the node to the list in the undo step. */
|
||||
static Node *alloc_node_type(Object *object, Type type)
|
||||
static Node *alloc_node_type(const Object &object, const Type type)
|
||||
{
|
||||
UndoSculpt *usculpt = get_nodes();
|
||||
std::unique_ptr<Node> unode = std::make_unique<Node>();
|
||||
|
@ -1154,7 +1159,7 @@ static Node *alloc_node_type(Object *object, Type type)
|
|||
usculpt->undo_size += sizeof(Node);
|
||||
|
||||
Node *node_ptr = usculpt->nodes.last().get();
|
||||
STRNCPY(node_ptr->idname, object->id.name);
|
||||
STRNCPY(node_ptr->idname, object.id.name);
|
||||
node_ptr->type = type;
|
||||
|
||||
return node_ptr;
|
||||
|
@ -1163,7 +1168,7 @@ static Node *alloc_node_type(Object *object, Type type)
|
|||
/* Will return first existing undo node of the given type.
|
||||
* If such node does not exist will allocate node of this type, register it in the undo step and
|
||||
* return it. */
|
||||
static Node *find_or_alloc_node_type(Object *object, Type type)
|
||||
static Node *find_or_alloc_node_type(const Object &object, const Type type)
|
||||
{
|
||||
UndoSculpt *usculpt = get_nodes();
|
||||
|
||||
|
@ -1176,12 +1181,12 @@ static Node *find_or_alloc_node_type(Object *object, Type type)
|
|||
return alloc_node_type(object, type);
|
||||
}
|
||||
|
||||
static Node *alloc_node(Object *ob, PBVHNode *node, Type type)
|
||||
static Node *alloc_node(const Object &object, const PBVHNode *node, const Type type)
|
||||
{
|
||||
UndoSculpt *usculpt = get_nodes();
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const SculptSession *ss = object.sculpt;
|
||||
|
||||
Node *unode = alloc_node_type(ob, type);
|
||||
Node *unode = alloc_node_type(object, type);
|
||||
unode->node = node;
|
||||
|
||||
int verts_num;
|
||||
|
@ -1189,7 +1194,7 @@ static Node *alloc_node(Object *ob, PBVHNode *node, Type type)
|
|||
unode->mesh_grids_num = ss->subdiv_ccg->grids.size();
|
||||
unode->grid_size = ss->subdiv_ccg->grid_size;
|
||||
|
||||
unode->grids = BKE_pbvh_node_get_grid_indices(*node);
|
||||
unode->grids = bke::pbvh::node_grid_indices(*node);
|
||||
usculpt->undo_size += unode->grids.as_span().size_in_bytes();
|
||||
|
||||
const int grid_area = unode->grid_size * unode->grid_size;
|
||||
|
@ -1198,8 +1203,8 @@ static Node *alloc_node(Object *ob, PBVHNode *node, Type type)
|
|||
else {
|
||||
unode->mesh_verts_num = ss->totvert;
|
||||
|
||||
unode->vert_indices = BKE_pbvh_node_get_vert_indices(node);
|
||||
unode->unique_verts_num = BKE_pbvh_node_get_unique_vert_indices(node).size();
|
||||
unode->vert_indices = bke::pbvh::node_verts(*node);
|
||||
unode->unique_verts_num = bke::pbvh::node_unique_verts(*node).size();
|
||||
|
||||
verts_num = unode->vert_indices.size();
|
||||
|
||||
|
@ -1210,8 +1215,8 @@ static Node *alloc_node(Object *ob, PBVHNode *node, Type type)
|
|||
const bool need_faces = ELEM(type, Type::FaceSet, Type::HideFace);
|
||||
|
||||
if (need_loops) {
|
||||
unode->corner_indices = BKE_pbvh_node_get_corner_indices(node);
|
||||
unode->mesh_corners_num = static_cast<Mesh *>(ob->data)->corners_num;
|
||||
unode->corner_indices = bke::pbvh::node_corners(*node);
|
||||
unode->mesh_corners_num = static_cast<Mesh *>(object.data)->corners_num;
|
||||
|
||||
usculpt->undo_size += unode->corner_indices.as_span().size_in_bytes();
|
||||
}
|
||||
|
@ -1292,9 +1297,9 @@ static Node *alloc_node(Object *ob, PBVHNode *node, Type type)
|
|||
return unode;
|
||||
}
|
||||
|
||||
static void store_coords(Object *ob, Node *unode)
|
||||
static void store_coords(const Object &object, Node *unode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptSession *ss = object.sculpt;
|
||||
|
||||
if (!unode->grids.is_empty()) {
|
||||
const SubdivCCG &subdiv_ccg = *ss->subdiv_ccg;
|
||||
|
@ -1336,13 +1341,13 @@ static void store_coords(Object *ob, Node *unode)
|
|||
}
|
||||
}
|
||||
|
||||
static void store_hidden(Object *ob, Node *unode)
|
||||
static void store_hidden(const Object &object, Node *unode)
|
||||
{
|
||||
if (!unode->grids.is_empty()) {
|
||||
/* Already stored during allocation. */
|
||||
}
|
||||
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert",
|
||||
bke::AttrDomain::Point);
|
||||
|
@ -1350,14 +1355,14 @@ static void store_hidden(Object *ob, Node *unode)
|
|||
return;
|
||||
}
|
||||
|
||||
PBVHNode *node = static_cast<PBVHNode *>(unode->node);
|
||||
const Span<int> verts = BKE_pbvh_node_get_vert_indices(node);
|
||||
const PBVHNode *node = static_cast<const PBVHNode *>(unode->node);
|
||||
const Span<int> verts = bke::pbvh::node_verts(*node);
|
||||
for (const int i : verts.index_range()) {
|
||||
unode->vert_hidden[i].set(hide_vert[verts[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
static void store_face_hidden(Object &object, Node &unode)
|
||||
static void store_face_hidden(const Object &object, Node &unode)
|
||||
{
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
|
@ -1372,9 +1377,9 @@ static void store_face_hidden(Object &object, Node &unode)
|
|||
}
|
||||
}
|
||||
|
||||
static void store_mask(Object *ob, Node *unode)
|
||||
static void store_mask(const Object &object, Node *unode)
|
||||
{
|
||||
const SculptSession *ss = ob->sculpt;
|
||||
const SculptSession *ss = object.sculpt;
|
||||
|
||||
if (!unode->grids.is_empty()) {
|
||||
const SubdivCCG &subdiv_ccg = *ss->subdiv_ccg;
|
||||
|
@ -1395,7 +1400,7 @@ static void store_mask(Object *ob, Node *unode)
|
|||
}
|
||||
}
|
||||
else {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob->data);
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
if (const VArray mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point)) {
|
||||
array_utils::gather(mask, unode->vert_indices.as_span(), unode->mask.as_mutable_span());
|
||||
|
@ -1406,9 +1411,9 @@ static void store_mask(Object *ob, Node *unode)
|
|||
}
|
||||
}
|
||||
|
||||
static void store_color(Object *ob, Node *unode)
|
||||
static void store_color(const Object &object, Node *unode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptSession *ss = object.sculpt;
|
||||
|
||||
BLI_assert(BKE_pbvh_type(ss->pbvh) == PBVH_FACES);
|
||||
|
||||
|
@ -1433,7 +1438,7 @@ static NodeGeometry *geometry_get(Node *unode)
|
|||
return &unode->geometry_modified;
|
||||
}
|
||||
|
||||
static Node *geometry_push(Object *object, Type type)
|
||||
static Node *geometry_push(const Object &object, const Type type)
|
||||
{
|
||||
Node *unode = find_or_alloc_node_type(object, type);
|
||||
unode->applied = false;
|
||||
|
@ -1453,10 +1458,10 @@ static void store_face_sets(const Mesh &mesh, Node &unode)
|
|||
unode.face_sets.as_mutable_span());
|
||||
}
|
||||
|
||||
static Node *bmesh_push(Object *ob, PBVHNode *node, Type type)
|
||||
static Node *bmesh_push(const Object &object, const PBVHNode *node, Type type)
|
||||
{
|
||||
UndoSculpt *usculpt = get_nodes();
|
||||
SculptSession *ss = ob->sculpt;
|
||||
const SculptSession *ss = object.sculpt;
|
||||
|
||||
Node *unode = usculpt->nodes.is_empty() ? nullptr : usculpt->nodes.first().get();
|
||||
|
||||
|
@ -1464,7 +1469,7 @@ static Node *bmesh_push(Object *ob, PBVHNode *node, Type type)
|
|||
usculpt->nodes.append(std::make_unique<Node>());
|
||||
unode = usculpt->nodes.last().get();
|
||||
|
||||
STRNCPY(unode->idname, ob->id.name);
|
||||
STRNCPY(unode->idname, object.id.name);
|
||||
unode->type = type;
|
||||
unode->applied = true;
|
||||
|
||||
|
@ -1479,7 +1484,7 @@ static Node *bmesh_push(Object *ob, PBVHNode *node, Type type)
|
|||
* (converting faces to triangles) that the BMLog can't
|
||||
* fully restore from. */
|
||||
NodeGeometry *geometry = &unode->geometry_bmesh_enter;
|
||||
store_geometry_data(geometry, ob);
|
||||
store_geometry_data(geometry, object);
|
||||
|
||||
unode->bm_entry = BM_log_entry_add(ss->bm_log);
|
||||
BM_log_all_added(ss->bm, ss->bm_log);
|
||||
|
@ -1493,29 +1498,32 @@ static Node *bmesh_push(Object *ob, PBVHNode *node, Type type)
|
|||
const int cd_vert_mask_offset = CustomData_get_offset_named(
|
||||
&ss->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
||||
|
||||
/* The vertices and node aren't changed, though pointers to them are stored in the log. */
|
||||
PBVHNode *node_mut = const_cast<PBVHNode *>(node);
|
||||
|
||||
switch (type) {
|
||||
case Type::Position:
|
||||
case Type::Mask:
|
||||
/* Before any vertex values get modified, ensure their
|
||||
* original positions are logged. */
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
|
||||
BM_log_vert_before_modified(ss->bm_log, vert, cd_vert_mask_offset);
|
||||
}
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
|
||||
BM_log_vert_before_modified(ss->bm_log, vert, cd_vert_mask_offset);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type::HideFace:
|
||||
case Type::HideVert: {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_unique_verts(node_mut)) {
|
||||
BM_log_vert_before_modified(ss->bm_log, vert, cd_vert_mask_offset);
|
||||
}
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node)) {
|
||||
for (BMVert *vert : BKE_pbvh_bmesh_node_other_verts(node_mut)) {
|
||||
BM_log_vert_before_modified(ss->bm_log, vert, cd_vert_mask_offset);
|
||||
}
|
||||
|
||||
for (BMFace *f : BKE_pbvh_bmesh_node_faces(node)) {
|
||||
for (BMFace *f : BKE_pbvh_bmesh_node_faces(node_mut)) {
|
||||
BM_log_face_modified(ss->bm_log, f);
|
||||
}
|
||||
break;
|
||||
|
@ -1534,9 +1542,9 @@ static Node *bmesh_push(Object *ob, PBVHNode *node, Type type)
|
|||
return unode;
|
||||
}
|
||||
|
||||
Node *push_node(Object *ob, PBVHNode *node, Type type)
|
||||
Node *push_node(const Object &object, const PBVHNode *node, Type type)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptSession *ss = object.sculpt;
|
||||
|
||||
Node *unode;
|
||||
|
||||
|
@ -1549,13 +1557,13 @@ Node *push_node(Object *ob, PBVHNode *node, Type type)
|
|||
if (ss->bm || ELEM(type, Type::DyntopoBegin, Type::DyntopoEnd)) {
|
||||
/* Dynamic topology stores only one undo node per stroke,
|
||||
* regardless of the number of PBVH nodes modified. */
|
||||
unode = bmesh_push(ob, node, type);
|
||||
unode = bmesh_push(object, node, type);
|
||||
BLI_thread_unlock(LOCK_CUSTOM1);
|
||||
// return unode;
|
||||
return;
|
||||
}
|
||||
if (type == Type::Geometry) {
|
||||
unode = geometry_push(ob, type);
|
||||
unode = geometry_push(object, type);
|
||||
BLI_thread_unlock(LOCK_CUSTOM1);
|
||||
// return unode;
|
||||
return;
|
||||
|
@ -1566,26 +1574,26 @@ Node *push_node(Object *ob, PBVHNode *node, Type type)
|
|||
return;
|
||||
}
|
||||
|
||||
unode = alloc_node(ob, node, type);
|
||||
unode = alloc_node(object, node, type);
|
||||
|
||||
/* NOTE: If this ever becomes a bottleneck, make a lock inside of the node.
|
||||
* so we release global lock sooner, but keep data locked for until it is
|
||||
* fully initialized. */
|
||||
switch (type) {
|
||||
case Type::Position:
|
||||
store_coords(ob, unode);
|
||||
store_coords(object, unode);
|
||||
break;
|
||||
case Type::HideVert:
|
||||
store_hidden(ob, unode);
|
||||
store_hidden(object, unode);
|
||||
break;
|
||||
case Type::HideFace:
|
||||
store_face_hidden(*ob, *unode);
|
||||
store_face_hidden(object, *unode);
|
||||
break;
|
||||
case Type::Mask:
|
||||
store_mask(ob, unode);
|
||||
store_mask(object, unode);
|
||||
break;
|
||||
case Type::Color:
|
||||
store_color(ob, unode);
|
||||
store_color(object, unode);
|
||||
break;
|
||||
case Type::DyntopoBegin:
|
||||
case Type::DyntopoEnd:
|
||||
|
@ -1594,7 +1602,7 @@ Node *push_node(Object *ob, PBVHNode *node, Type type)
|
|||
case Type::Geometry:
|
||||
break;
|
||||
case Type::FaceSet:
|
||||
store_face_sets(*static_cast<const Mesh *>(ob->data), *unode);
|
||||
store_face_sets(*static_cast<const Mesh *>(object.data), *unode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1616,9 +1624,9 @@ Node *push_node(Object *ob, PBVHNode *node, Type type)
|
|||
return unode;
|
||||
}
|
||||
|
||||
static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr)
|
||||
static void sculpt_save_active_attribute(Object &object, SculptAttrRef *attr)
|
||||
{
|
||||
Mesh *mesh = BKE_object_get_original_mesh(ob);
|
||||
Mesh *mesh = BKE_object_get_original_mesh(&object);
|
||||
attr->was_set = true;
|
||||
attr->domain = NO_ACTIVE_LAYER;
|
||||
attr->name[0] = 0;
|
||||
|
@ -1664,14 +1672,14 @@ void push_begin_ex(Object *ob, const char *name)
|
|||
ustack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
|
||||
|
||||
if (!us->active_color_start.was_set) {
|
||||
sculpt_save_active_attribute(ob, &us->active_color_start);
|
||||
sculpt_save_active_attribute(*ob, &us->active_color_start);
|
||||
}
|
||||
|
||||
/* Set end attribute in case push_end is not called,
|
||||
* so we don't end up with corrupted state.
|
||||
*/
|
||||
if (!us->active_color_end.was_set) {
|
||||
sculpt_save_active_attribute(ob, &us->active_color_end);
|
||||
sculpt_save_active_attribute(*ob, &us->active_color_end);
|
||||
us->active_color_end.was_set = false;
|
||||
}
|
||||
}
|
||||
|
@ -1706,7 +1714,7 @@ void push_end_ex(Object *ob, const bool use_nested_undo)
|
|||
SculptUndoStep *us = (SculptUndoStep *)BKE_undosys_stack_init_or_active_with_type(
|
||||
ustack, BKE_UNDOSYS_TYPE_SCULPT);
|
||||
|
||||
sculpt_save_active_attribute(ob, &us->active_color_end);
|
||||
sculpt_save_active_attribute(*ob, &us->active_color_end);
|
||||
print_nodes(ob, nullptr);
|
||||
}
|
||||
|
||||
|
@ -1724,7 +1732,7 @@ static void set_active_layer(bContext *C, SculptAttrRef *attr)
|
|||
Mesh *mesh = BKE_object_get_original_mesh(ob);
|
||||
|
||||
SculptAttrRef existing;
|
||||
sculpt_save_active_attribute(ob, &existing);
|
||||
sculpt_save_active_attribute(*ob, &existing);
|
||||
|
||||
CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, attr->name, attr->type, attr->domain);
|
||||
|
||||
|
@ -1930,18 +1938,18 @@ static void sculpt_undosys_step_free(UndoStep *us_p)
|
|||
void geometry_begin(Object *ob, const wmOperator *op)
|
||||
{
|
||||
push_begin(ob, op);
|
||||
push_node(ob, nullptr, Type::Geometry);
|
||||
push_node(*ob, nullptr, Type::Geometry);
|
||||
}
|
||||
|
||||
void geometry_begin_ex(Object *ob, const char *name)
|
||||
{
|
||||
push_begin_ex(ob, name);
|
||||
push_node(ob, nullptr, Type::Geometry);
|
||||
push_node(*ob, nullptr, Type::Geometry);
|
||||
}
|
||||
|
||||
void geometry_end(Object *ob)
|
||||
{
|
||||
push_node(ob, nullptr, Type::Geometry);
|
||||
push_node(*ob, nullptr, Type::Geometry);
|
||||
push_end(ob);
|
||||
}
|
||||
|
||||
|
@ -2032,7 +2040,7 @@ static void push_all_grids(Object *object)
|
|||
|
||||
Vector<PBVHNode *> nodes = bke::pbvh::search_gather(ss->pbvh, {});
|
||||
for (PBVHNode *node : nodes) {
|
||||
Node *unode = push_node(object, node, Type::Position);
|
||||
Node *unode = push_node(*object, node, Type::Position);
|
||||
unode->node = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -2047,7 +2055,7 @@ void push_multires_mesh_begin(bContext *C, const char *str)
|
|||
|
||||
push_begin_ex(object, str);
|
||||
|
||||
Node *geometry_unode = push_node(object, nullptr, Type::Geometry);
|
||||
Node *geometry_unode = push_node(*object, nullptr, Type::Geometry);
|
||||
geometry_unode->geometry_clear_pbvh = false;
|
||||
|
||||
push_all_grids(object);
|
||||
|
@ -2062,7 +2070,7 @@ void push_multires_mesh_end(bContext *C, const char *str)
|
|||
|
||||
Object *object = CTX_data_active_object(C);
|
||||
|
||||
Node *geometry_unode = push_node(object, nullptr, Type::Geometry);
|
||||
Node *geometry_unode = push_node(*object, nullptr, Type::Geometry);
|
||||
geometry_unode->geometry_clear_pbvh = false;
|
||||
|
||||
push_end(object);
|
||||
|
|
|
@ -65,7 +65,8 @@ static blender::IndexRange get_bounding_bezt_index_range(FCurve *fcu,
|
|||
last = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, max, fcu->totvert, &replace);
|
||||
last = replace ? last + 1 : last;
|
||||
last = clamp_i(last, 0, fcu->totvert - 1);
|
||||
/* Iterating over index range is exlusive of the last index. But we need `last` to be visited. */
|
||||
/* Iterating over index range is exclusive of the last index.
|
||||
* But we need `last` to be visited. */
|
||||
return blender::IndexRange(first, (last - first) + 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ struct Editing;
|
|||
struct ListBase;
|
||||
|
||||
#define DEFAULT_IMG_STRIP_LENGTH 25 /* XXX arbitrary but ok for now. */
|
||||
#define OVERLAP_ALPHA 180
|
||||
|
||||
namespace blender::ed::seq {
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "BIF_glutil.hh"
|
||||
|
||||
#include "SEQ_channels.hh"
|
||||
#include "SEQ_relations.hh"
|
||||
#include "SEQ_render.hh"
|
||||
#include "SEQ_sequencer.hh"
|
||||
|
@ -464,6 +465,9 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
|||
return;
|
||||
}
|
||||
|
||||
Editing *ed = SEQ_editing_get(scene);
|
||||
ListBase *channels = ed ? SEQ_channels_displayed_get(ed) : nullptr;
|
||||
|
||||
const float thumb_height = y2 - y1;
|
||||
seq_get_thumb_image_dimensions(
|
||||
seq, pixelx, pixely, &thumb_width, thumb_height, &image_width, &image_height);
|
||||
|
@ -479,7 +483,6 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
|||
}
|
||||
|
||||
float timeline_frame = SEQ_render_thumbnail_first_frame_get(scene, seq, thumb_width, &v2d->cur);
|
||||
float thumb_x_end;
|
||||
|
||||
GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq);
|
||||
/* Cleanup thumbnail list outside of rendered range, which is cleaned up one by one to prevent
|
||||
|
@ -490,7 +493,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
|||
|
||||
/* Start drawing. */
|
||||
while (timeline_frame < upper_thumb_bound) {
|
||||
thumb_x_end = timeline_frame + thumb_width;
|
||||
float thumb_x_end = timeline_frame + thumb_width;
|
||||
clipped = false;
|
||||
|
||||
/* Checks to make sure that thumbs are loaded only when in view and within the confines of the
|
||||
|
@ -510,20 +513,17 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
|||
if (thumb_x_end > (upper_thumb_bound)) {
|
||||
thumb_x_end = upper_thumb_bound;
|
||||
clipped = true;
|
||||
if (thumb_x_end - timeline_frame < 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float zoom_x = thumb_width / image_width;
|
||||
float zoom_y = thumb_height / image_height;
|
||||
|
||||
float cropx_min = (cut_off / pixelx) / (zoom_y / pixely);
|
||||
float cropx_max = ((thumb_x_end - timeline_frame) / pixelx) / (zoom_y / pixely);
|
||||
if (cropx_max == (thumb_x_end - timeline_frame)) {
|
||||
cropx_max = cropx_max + 1;
|
||||
int cropx_min = int((cut_off / pixelx) / (zoom_y / pixely));
|
||||
int cropx_max = int(((thumb_x_end - timeline_frame) / pixelx) / (zoom_y / pixely));
|
||||
if (cropx_max < 1) {
|
||||
break;
|
||||
}
|
||||
BLI_rcti_init(&crop, int(cropx_min), int(cropx_max), 0, int(image_height) - 1);
|
||||
BLI_rcti_init(&crop, cropx_min, cropx_max - 1, 0, int(image_height) - 1);
|
||||
|
||||
/* Get the image. */
|
||||
ImBuf *ibuf = SEQ_get_thumbnail(&context, seq, timeline_frame, &crop, clipped);
|
||||
|
@ -548,19 +548,21 @@ void draw_seq_strip_thumbnail(View2D *v2d,
|
|||
break;
|
||||
}
|
||||
|
||||
/* Transparency on overlap. */
|
||||
if (seq->flag & SEQ_OVERLAP) {
|
||||
/* Transparency on mute. */
|
||||
bool muted = channels ? SEQ_render_is_muted(channels, seq) : false;
|
||||
if (muted) {
|
||||
const uchar alpha = 120;
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
if (ibuf->byte_buffer.data) {
|
||||
uchar *buf = ibuf->byte_buffer.data;
|
||||
for (int pixel = ibuf->x * ibuf->y; pixel--; buf += 4) {
|
||||
buf[3] = OVERLAP_ALPHA;
|
||||
buf[3] = alpha;
|
||||
}
|
||||
}
|
||||
else if (ibuf->float_buffer.data) {
|
||||
float *buf = ibuf->float_buffer.data;
|
||||
for (int pixel = ibuf->x * ibuf->y; pixel--; buf += ibuf->channels) {
|
||||
buf[3] = (OVERLAP_ALPHA / 255.0f);
|
||||
buf[3] = (alpha / 255.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
||||
* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include "SEQ_transform.hh"
|
||||
#include "SEQ_utils.hh"
|
||||
|
||||
#include "UI_interface_icons.hh"
|
||||
#include "UI_resources.hh"
|
||||
#include "UI_view2d.hh"
|
||||
|
||||
|
@ -67,6 +69,8 @@
|
|||
#define SEQ_HANDLE_SIZE 8.0f
|
||||
#define MUTE_ALPHA 120
|
||||
|
||||
constexpr float MISSING_ICON_SIZE = 16.0f;
|
||||
|
||||
struct StripDrawContext {
|
||||
Sequence *seq;
|
||||
/* Strip boundary in timeline space. Content start/end is clamped by left/right handle. */
|
||||
|
@ -82,6 +86,7 @@ struct StripDrawContext {
|
|||
bool is_active_strip;
|
||||
bool is_single_image; /* Strip has single frame of content. */
|
||||
bool show_strip_color_tag;
|
||||
bool missing_data_block;
|
||||
};
|
||||
|
||||
struct TimelineDrawContext {
|
||||
|
@ -99,7 +104,7 @@ struct TimelineDrawContext {
|
|||
SeqQuadsBatch *quads;
|
||||
};
|
||||
|
||||
static TimelineDrawContext timeline_draw_context_get(const bContext *C)
|
||||
static TimelineDrawContext timeline_draw_context_get(const bContext *C, SeqQuadsBatch *quads_batch)
|
||||
{
|
||||
TimelineDrawContext ctx;
|
||||
|
||||
|
@ -118,6 +123,8 @@ static TimelineDrawContext timeline_draw_context_get(const bContext *C)
|
|||
ctx.pixely = BLI_rctf_size_y(&ctx.v2d->cur) / BLI_rcti_size_y(&ctx.v2d->mask);
|
||||
ctx.pixelx = BLI_rctf_size_x(&ctx.v2d->cur) / BLI_rcti_size_x(&ctx.v2d->mask);
|
||||
|
||||
ctx.quads = quads_batch;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
@ -175,6 +182,25 @@ static void strip_draw_context_set_strip_content_visibility(TimelineDrawContext
|
|||
threshold;
|
||||
}
|
||||
|
||||
static bool meta_strip_has_missing_data(const Sequence *seq)
|
||||
{
|
||||
if (seq->type != SEQ_TYPE_META) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ListBase *seqbase = &seq->seqbase;
|
||||
if (!seqbase || BLI_listbase_is_empty(seqbase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (const Sequence *, sub, seqbase) {
|
||||
if (!SEQ_sequence_has_source(sub)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Sequence *seq)
|
||||
{
|
||||
StripDrawContext strip_ctx;
|
||||
|
@ -209,6 +235,7 @@ static StripDrawContext strip_draw_context_get(TimelineDrawContext *ctx, Sequenc
|
|||
strip_ctx.handle_width = sequence_handle_size_get_clamped(ctx->scene, seq, ctx->pixelx);
|
||||
strip_ctx.show_strip_color_tag = (ctx->sseq->timeline_overlay.flag &
|
||||
SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG);
|
||||
strip_ctx.missing_data_block = !SEQ_sequence_has_source(seq) || meta_strip_has_missing_data(seq);
|
||||
|
||||
if (strip_ctx.can_draw_text_overlay) {
|
||||
strip_ctx.strip_content_top = strip_ctx.top - min_ff(0.40f, 20 * UI_SCALE_FAC * ctx->pixely);
|
||||
|
@ -568,14 +595,14 @@ static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDraw
|
|||
return;
|
||||
}
|
||||
|
||||
Scene *scene = timeline_ctx->scene;
|
||||
const Scene *scene = timeline_ctx->scene;
|
||||
|
||||
uchar col[4];
|
||||
|
||||
int chan_min = MAXSEQ;
|
||||
int chan_max = 0;
|
||||
int chan_range = 0;
|
||||
float draw_range = strip_ctx->top - strip_ctx->bottom;
|
||||
float draw_range = strip_ctx->strip_content_top - strip_ctx->bottom;
|
||||
float draw_height;
|
||||
|
||||
Editing *ed = SEQ_editing_get(scene);
|
||||
|
@ -633,6 +660,12 @@ static void drawmeta_contents(TimelineDrawContext *timeline_ctx, const StripDraw
|
|||
col[3] = 196;
|
||||
}
|
||||
|
||||
if (!SEQ_sequence_has_source(seq)) {
|
||||
col[0] = 112;
|
||||
col[1] = 0;
|
||||
col[2] = 0;
|
||||
}
|
||||
|
||||
/* Clamp within parent sequence strip bounds. */
|
||||
if (x1_chan < strip_ctx->left_handle) {
|
||||
x1_chan = strip_ctx->left_handle;
|
||||
|
@ -665,7 +698,7 @@ static void draw_seq_handle(TimelineDrawContext *timeline_ctx,
|
|||
const StripDrawContext *strip_ctx,
|
||||
const short direction)
|
||||
{
|
||||
Sequence *seq = strip_ctx->seq;
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
if (SEQ_transform_is_locked(timeline_ctx->channels, seq)) {
|
||||
return;
|
||||
}
|
||||
|
@ -743,17 +776,16 @@ static void draw_seq_handle(TimelineDrawContext *timeline_ctx,
|
|||
}
|
||||
}
|
||||
|
||||
/* Strip border, and outline for selected/active strips. */
|
||||
static void draw_seq_outline(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
|
||||
{
|
||||
Sequence *seq = strip_ctx->seq;
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
const bool selected = seq->flag & SELECT;
|
||||
|
||||
/* Get the color for the outline. */
|
||||
/* Outline color. */
|
||||
uchar col[4];
|
||||
if (strip_ctx->is_active_strip && (seq->flag & SELECT)) {
|
||||
UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, col);
|
||||
}
|
||||
else if (seq->flag & SELECT) {
|
||||
UI_GetThemeColor3ubv(TH_SEQ_SELECTED, col);
|
||||
if (selected) {
|
||||
UI_GetThemeColor3ubv(strip_ctx->is_active_strip ? TH_SEQ_ACTIVE : TH_SEQ_SELECTED, col);
|
||||
}
|
||||
else {
|
||||
/* Color for unselected strips is a bit darker than the background. */
|
||||
|
@ -763,12 +795,9 @@ static void draw_seq_outline(TimelineDrawContext *timeline_ctx, const StripDrawC
|
|||
|
||||
/* Outline while translating strips:
|
||||
* - Slightly lighter.
|
||||
* - Red when overlapping with other strips.
|
||||
*/
|
||||
* - Red when overlapping with other strips. */
|
||||
const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(timeline_ctx->scene);
|
||||
if ((G.moving & G_TRANSFORM_SEQ) && (seq->flag & SELECT) &&
|
||||
overlap_mode != SEQ_OVERLAP_OVERWRITE)
|
||||
{
|
||||
if ((G.moving & G_TRANSFORM_SEQ) && selected && overlap_mode != SEQ_OVERLAP_OVERWRITE) {
|
||||
if (seq->flag & SEQ_OVERLAP) {
|
||||
col[0] = 255;
|
||||
col[1] = col[2] = 33;
|
||||
|
@ -778,44 +807,35 @@ static void draw_seq_outline(TimelineDrawContext *timeline_ctx, const StripDrawC
|
|||
}
|
||||
}
|
||||
|
||||
/* 2px wide outline for selected strips: draw as four quads. */
|
||||
if (seq->flag & SELECT) {
|
||||
float delta_x = timeline_ctx->pixelx;
|
||||
float delta_y = timeline_ctx->pixely * 2;
|
||||
/* Selected outline: 2px wide outline, plus 1px wide background inset. */
|
||||
const float x0 = strip_ctx->left_handle;
|
||||
const float x1 = strip_ctx->right_handle;
|
||||
const float y0 = strip_ctx->bottom;
|
||||
const float y1 = strip_ctx->top;
|
||||
if (selected) {
|
||||
const float dx = timeline_ctx->pixelx;
|
||||
const float dy = timeline_ctx->pixely;
|
||||
|
||||
/* Left */
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle - delta_x,
|
||||
strip_ctx->bottom,
|
||||
strip_ctx->left_handle + delta_x,
|
||||
strip_ctx->top,
|
||||
col);
|
||||
/* Bottom */
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle - delta_x,
|
||||
strip_ctx->bottom,
|
||||
strip_ctx->right_handle + delta_x,
|
||||
strip_ctx->bottom + delta_y,
|
||||
col);
|
||||
/* Right */
|
||||
timeline_ctx->quads->add_quad(strip_ctx->right_handle - delta_x,
|
||||
strip_ctx->bottom,
|
||||
strip_ctx->right_handle + delta_x,
|
||||
strip_ctx->top,
|
||||
col);
|
||||
/* Top */
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle - delta_x,
|
||||
strip_ctx->top - delta_y,
|
||||
strip_ctx->right_handle + delta_x,
|
||||
strip_ctx->top,
|
||||
col);
|
||||
/* Left, right, bottom, top. */
|
||||
timeline_ctx->quads->add_quad(x0 - dx, y0, x0 + dx, y1, col);
|
||||
timeline_ctx->quads->add_quad(x1 - dx, y0, x1 + dx, y1, col);
|
||||
timeline_ctx->quads->add_quad(x0, y0, x1, y0 + dy * 2, col);
|
||||
timeline_ctx->quads->add_quad(x0, y1 - dy * 2, x1, y1, col);
|
||||
|
||||
/* Inset. */
|
||||
UI_GetThemeColor3ubv(TH_BACK, col);
|
||||
timeline_ctx->quads->add_quad(x0 + dx, y0 + dy * 2, x0 + dx * 2, y1 - dy * 2, col);
|
||||
timeline_ctx->quads->add_quad(x1 - dx * 2, y0 + dy * 2, x1 - dx, y1 - dy * 2, col);
|
||||
timeline_ctx->quads->add_quad(x0 + dx, y0 + dy * 2, x1 - dx, y0 + dy * 3, col);
|
||||
timeline_ctx->quads->add_quad(x0 + dx, y1 - dy * 3, x1 - dx, y1 - dy * 2, col);
|
||||
}
|
||||
else {
|
||||
/* 1px wide outline for unselected strips. */
|
||||
timeline_ctx->quads->add_wire_quad(
|
||||
strip_ctx->left_handle, strip_ctx->bottom, strip_ctx->right_handle, strip_ctx->top, col);
|
||||
/* Thin wireframe outline for unselected strips. */
|
||||
timeline_ctx->quads->add_wire_quad(x0, y0, x1, y1, col);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *draw_seq_text_get_name(Sequence *seq)
|
||||
static const char *draw_seq_text_get_name(const Sequence *seq)
|
||||
{
|
||||
const char *name = seq->name + 2;
|
||||
if (name[0] == '\0') {
|
||||
|
@ -824,7 +844,7 @@ static const char *draw_seq_text_get_name(Sequence *seq)
|
|||
return name;
|
||||
}
|
||||
|
||||
static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t source_maxncpy)
|
||||
static void draw_seq_text_get_source(const Sequence *seq, char *r_source, size_t source_maxncpy)
|
||||
{
|
||||
*r_source = '\0';
|
||||
|
||||
|
@ -886,7 +906,7 @@ static size_t draw_seq_text_get_overlay_string(TimelineDrawContext *timeline_ctx
|
|||
char *r_overlay_string,
|
||||
size_t overlay_string_len)
|
||||
{
|
||||
Sequence *seq = strip_ctx->seq;
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
|
||||
const char *text_sep = " | ";
|
||||
const char *text_array[5];
|
||||
|
@ -921,6 +941,95 @@ static size_t draw_seq_text_get_overlay_string(TimelineDrawContext *timeline_ctx
|
|||
return BLI_string_join_array(r_overlay_string, overlay_string_len, text_array, i);
|
||||
}
|
||||
|
||||
static void get_strip_text_color(const TimelineDrawContext *ctx,
|
||||
const StripDrawContext *strip,
|
||||
uchar r_col[4])
|
||||
{
|
||||
/* Text: 75% opacity, fully opaque when selected/active. */
|
||||
const Sequence *seq = strip->seq;
|
||||
const bool active_or_selected = (seq->flag & SELECT) || strip->is_active_strip;
|
||||
if (active_or_selected) {
|
||||
UI_GetThemeColor3ubv(TH_SEQ_ACTIVE, r_col);
|
||||
r_col[3] = 255;
|
||||
}
|
||||
else {
|
||||
r_col[0] = r_col[1] = r_col[2] = 224;
|
||||
r_col[3] = 192;
|
||||
}
|
||||
|
||||
/* Muted strips: gray color, reduce opacity. */
|
||||
if (SEQ_render_is_muted(ctx->channels, seq)) {
|
||||
r_col[0] = r_col[1] = r_col[2] = 192;
|
||||
r_col[3] *= 0.66f;
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_icon_centered(TimelineDrawContext &ctx,
|
||||
const rctf &rect,
|
||||
int icon_id,
|
||||
const uchar color[4])
|
||||
{
|
||||
const float icon_size_x = MISSING_ICON_SIZE * ctx.pixelx * UI_SCALE_FAC;
|
||||
const float icon_size_y = MISSING_ICON_SIZE * ctx.pixely * UI_SCALE_FAC;
|
||||
if (BLI_rctf_size_x(&rect) * 1.1f < icon_size_x || BLI_rctf_size_y(&rect) * 1.1f < icon_size_y) {
|
||||
return;
|
||||
}
|
||||
|
||||
UI_icon_draw_mono_rect(BLI_rctf_cent_x(&rect) - icon_size_x * 0.5f,
|
||||
BLI_rctf_cent_y(&rect) - icon_size_y * 0.5f,
|
||||
icon_size_x,
|
||||
icon_size_y,
|
||||
icon_id,
|
||||
color);
|
||||
}
|
||||
|
||||
static void draw_strip_icons(TimelineDrawContext *timeline_ctx,
|
||||
const blender::Vector<StripDrawContext> &strips)
|
||||
{
|
||||
timeline_ctx->quads->draw();
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
UI_icon_draw_cache_begin();
|
||||
|
||||
const float icon_size_x = MISSING_ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
|
||||
|
||||
for (const StripDrawContext &strip : strips) {
|
||||
if (!strip.missing_data_block) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Draw icon in the title bar area. */
|
||||
if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) != 0 && !strip.strip_is_too_small &&
|
||||
strip.can_draw_text_overlay)
|
||||
{
|
||||
uchar col[4];
|
||||
get_strip_text_color(timeline_ctx, &strip, col);
|
||||
|
||||
float icon_indent = 2.0f * strip.handle_width - 4 * timeline_ctx->pixelx * UI_SCALE_FAC;
|
||||
rctf rect;
|
||||
rect.xmin = max_ff(strip.left_handle, timeline_ctx->v2d->cur.xmin) + icon_indent;
|
||||
rect.xmax = min_ff(strip.right_handle - strip.handle_width, rect.xmin + icon_size_x);
|
||||
rect.ymin = strip.strip_content_top;
|
||||
rect.ymax = strip.top;
|
||||
draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
|
||||
}
|
||||
|
||||
/* Draw icon in center of content. */
|
||||
if (strip.can_draw_strip_content && strip.seq->type != SEQ_TYPE_META) {
|
||||
rctf rect;
|
||||
rect.xmin = strip.left_handle + strip.handle_width;
|
||||
rect.xmax = strip.right_handle - strip.handle_width;
|
||||
rect.ymin = strip.bottom;
|
||||
rect.ymax = strip.strip_content_top;
|
||||
uchar col[4] = {112, 0, 0, 255};
|
||||
draw_icon_centered(*timeline_ctx, rect, ICON_LIBRARY_DATA_BROKEN, col);
|
||||
}
|
||||
}
|
||||
|
||||
UI_icon_draw_cache_end();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
/* Draw info text on a sequence strip. */
|
||||
static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
|
@ -943,30 +1052,23 @@ static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx,
|
|||
return;
|
||||
}
|
||||
|
||||
/* White text for the active strip. */
|
||||
uchar col[4];
|
||||
col[0] = col[1] = col[2] = strip_ctx->is_active_strip ? 255 : 10;
|
||||
col[3] = 255;
|
||||
|
||||
/* Make the text duller when the strip is muted. */
|
||||
if (SEQ_render_is_muted(timeline_ctx->channels, strip_ctx->seq)) {
|
||||
if (strip_ctx->is_active_strip) {
|
||||
UI_GetColorPtrShade3ubv(col, col, -70);
|
||||
}
|
||||
else {
|
||||
UI_GetColorPtrShade3ubv(col, col, 15);
|
||||
}
|
||||
}
|
||||
get_strip_text_color(timeline_ctx, strip_ctx, col);
|
||||
|
||||
float text_margin = 2.0f * strip_ctx->handle_width;
|
||||
rctf rect;
|
||||
rect.xmin = strip_ctx->left_handle + 2.0f * strip_ctx->handle_width;
|
||||
rect.xmax = strip_ctx->right_handle - 2.0f * strip_ctx->handle_width;
|
||||
rect.xmin = strip_ctx->left_handle + text_margin;
|
||||
rect.xmax = strip_ctx->right_handle - text_margin;
|
||||
rect.ymax = strip_ctx->top;
|
||||
/* Depending on the vertical space, draw text on top or in the center of strip. */
|
||||
rect.ymin = !strip_ctx->can_draw_strip_content ? strip_ctx->bottom :
|
||||
strip_ctx->strip_content_top;
|
||||
CLAMP(rect.xmin, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax);
|
||||
rect.xmin = max_ff(rect.xmin, timeline_ctx->v2d->cur.xmin + text_margin);
|
||||
if (strip_ctx->missing_data_block) {
|
||||
rect.xmin += MISSING_ICON_SIZE * timeline_ctx->pixelx * UI_SCALE_FAC;
|
||||
}
|
||||
rect.xmin = min_ff(rect.xmin, timeline_ctx->v2d->cur.xmax);
|
||||
|
||||
CLAMP(rect.xmax, timeline_ctx->v2d->cur.xmin + text_margin, timeline_ctx->v2d->cur.xmax);
|
||||
|
||||
UI_view2d_text_cache_add_rectf(
|
||||
|
@ -976,7 +1078,7 @@ static void draw_seq_text_overlay(TimelineDrawContext *timeline_ctx,
|
|||
static void draw_strip_offsets(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
Sequence *seq = strip_ctx->seq;
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -989,8 +1091,8 @@ static void draw_strip_offsets(TimelineDrawContext *timeline_ctx,
|
|||
return;
|
||||
}
|
||||
|
||||
Scene *scene = timeline_ctx->scene;
|
||||
ListBase *channels = timeline_ctx->channels;
|
||||
const Scene *scene = timeline_ctx->scene;
|
||||
const ListBase *channels = timeline_ctx->channels;
|
||||
|
||||
uchar col[4], blend_col[4];
|
||||
color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col);
|
||||
|
@ -1030,23 +1132,19 @@ static void draw_strip_offsets(TimelineDrawContext *timeline_ctx,
|
|||
}
|
||||
}
|
||||
|
||||
static uchar mute_overlap_alpha_factor_get(const ListBase *channels, const Sequence *seq)
|
||||
static uchar mute_alpha_factor_get(const ListBase *channels, const Sequence *seq)
|
||||
{
|
||||
/* Draw muted strips semi-transparent. */
|
||||
if (SEQ_render_is_muted(channels, seq)) {
|
||||
return MUTE_ALPHA;
|
||||
}
|
||||
/* Draw background semi-transparent when overlapping strips. */
|
||||
if (seq->flag & SEQ_OVERLAP) {
|
||||
return OVERLAP_ALPHA;
|
||||
}
|
||||
return 255;
|
||||
}
|
||||
|
||||
static void draw_strip_color_band(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
Sequence *seq = strip_ctx->seq;
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
if ((timeline_ctx->sseq->flag & SEQ_SHOW_OVERLAY) == 0 || (seq->type != SEQ_TYPE_COLOR)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1054,7 +1152,7 @@ static void draw_strip_color_band(TimelineDrawContext *timeline_ctx,
|
|||
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
|
||||
uchar col[4];
|
||||
rgb_float_to_uchar(col, colvars->col);
|
||||
col[3] = mute_overlap_alpha_factor_get(timeline_ctx->channels, seq);
|
||||
col[3] = mute_alpha_factor_get(timeline_ctx->channels, seq);
|
||||
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->bottom,
|
||||
|
@ -1074,12 +1172,17 @@ static void draw_strip_color_band(TimelineDrawContext *timeline_ctx,
|
|||
static void draw_strip_background(TimelineDrawContext *timeline_ctx,
|
||||
const StripDrawContext *strip_ctx)
|
||||
{
|
||||
Scene *scene = timeline_ctx->scene;
|
||||
Sequence *seq = strip_ctx->seq;
|
||||
const Scene *scene = timeline_ctx->scene;
|
||||
const Sequence *seq = strip_ctx->seq;
|
||||
|
||||
uchar col[4];
|
||||
color3ubv_from_seq(scene, seq, strip_ctx->show_strip_color_tag, col);
|
||||
col[3] = mute_overlap_alpha_factor_get(timeline_ctx->channels, seq);
|
||||
col[3] = mute_alpha_factor_get(timeline_ctx->channels, seq);
|
||||
/* Muted strips: turn almost gray. */
|
||||
if (col[3] == MUTE_ALPHA) {
|
||||
uchar muted_color[3] = {128, 128, 128};
|
||||
UI_GetColorPtrBlendShade3ubv(col, muted_color, col, 0.8f, 0);
|
||||
}
|
||||
|
||||
/* Draw the main strip body. */
|
||||
float x1 = strip_ctx->is_single_image ? strip_ctx->left_handle : strip_ctx->content_start;
|
||||
|
@ -1130,7 +1233,7 @@ static void draw_seq_transition_strip_half(TimelineDrawContext *timeline_ctx,
|
|||
}
|
||||
}
|
||||
|
||||
col[3] = mute_overlap_alpha_factor_get(timeline_ctx->channels, strip_ctx->seq);
|
||||
col[3] = mute_alpha_factor_get(timeline_ctx->channels, strip_ctx->seq);
|
||||
|
||||
float tri[3][2];
|
||||
|
||||
|
@ -1177,12 +1280,12 @@ static void draw_seq_locked(TimelineDrawContext *timeline_ctx,
|
|||
immUniform1i("size1", 8);
|
||||
immUniform1i("size2", 4);
|
||||
|
||||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
if (!SEQ_transform_is_locked(timeline_ctx->channels, strip_ctx.seq)) {
|
||||
for (const StripDrawContext &strip : strips) {
|
||||
if (!SEQ_transform_is_locked(timeline_ctx->channels, strip.seq)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
immRectf(pos, strip_ctx.left_handle, strip_ctx.bottom, strip_ctx.right_handle, strip_ctx.top);
|
||||
immRectf(pos, strip.left_handle, strip.bottom, strip.right_handle, strip.strip_content_top);
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
|
@ -1192,15 +1295,27 @@ static void draw_seq_locked(TimelineDrawContext *timeline_ctx,
|
|||
|
||||
static void draw_seq_invalid(TimelineDrawContext *timeline_ctx, const StripDrawContext *strip_ctx)
|
||||
{
|
||||
if (SEQ_sequence_has_source(strip_ctx->seq)) {
|
||||
if (!strip_ctx->missing_data_block) {
|
||||
return;
|
||||
}
|
||||
uchar color[4] = {255, 0, 0, 230};
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->top,
|
||||
strip_ctx->right_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
color);
|
||||
/* Do not tint title area for muted strips; we want to see gray for them. */
|
||||
if (!SEQ_render_is_muted(timeline_ctx->channels, strip_ctx->seq)) {
|
||||
uchar col_top[4] = {112, 0, 0, 230};
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->top,
|
||||
strip_ctx->right_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
col_top);
|
||||
}
|
||||
/* Do not tint content area for meta strips; we want to display children. */
|
||||
if (strip_ctx->seq->type != SEQ_TYPE_META) {
|
||||
uchar col_main[4] = {64, 0, 0, 230};
|
||||
timeline_ctx->quads->add_quad(strip_ctx->left_handle,
|
||||
strip_ctx->strip_content_top,
|
||||
strip_ctx->right_handle,
|
||||
strip_ctx->bottom,
|
||||
col_main);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1420,6 +1535,8 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
|
|||
return;
|
||||
}
|
||||
|
||||
UI_view2d_view_ortho(timeline_ctx->v2d);
|
||||
|
||||
/* Draw parts of strips below thumbnails. */
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
|
@ -1449,6 +1566,7 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
|
|||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
draw_seq_fcurve_overlay(timeline_ctx, &strip_ctx);
|
||||
draw_seq_waveform_overlay(timeline_ctx, &strip_ctx);
|
||||
draw_seq_invalid(timeline_ctx, &strip_ctx);
|
||||
}
|
||||
timeline_ctx->quads->draw();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
@ -1459,15 +1577,27 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx,
|
|||
/* Draw the rest. */
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
for (const StripDrawContext &strip_ctx : strips) {
|
||||
draw_seq_invalid(timeline_ctx, &strip_ctx);
|
||||
draw_effect_inputs_highlight(timeline_ctx, &strip_ctx);
|
||||
draw_multicam_highlight(timeline_ctx, &strip_ctx);
|
||||
draw_seq_solo_highlight(timeline_ctx, &strip_ctx);
|
||||
draw_seq_handle(timeline_ctx, &strip_ctx, SEQ_LEFTHANDLE);
|
||||
draw_seq_handle(timeline_ctx, &strip_ctx, SEQ_RIGHTHANDLE);
|
||||
draw_seq_outline(timeline_ctx, &strip_ctx);
|
||||
draw_seq_text_overlay(timeline_ctx, &strip_ctx);
|
||||
}
|
||||
|
||||
/* Draw icons separately (different shader). */
|
||||
draw_strip_icons(timeline_ctx, strips);
|
||||
|
||||
timeline_ctx->quads->draw();
|
||||
|
||||
/* Draw text labels with a drop shadow. */
|
||||
const int font_id = BLF_default();
|
||||
BLF_enable(font_id, BLF_SHADOW);
|
||||
BLF_shadow(font_id, 3, blender::float4{0.0f, 0.0f, 0.0f, 1.0f});
|
||||
BLF_shadow_offset(font_id, 1, -1);
|
||||
UI_view2d_text_cache_draw(timeline_ctx->region);
|
||||
BLF_disable(font_id, BLF_SHADOW);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
|
@ -1481,18 +1611,6 @@ static void draw_seq_strips(TimelineDrawContext *timeline_ctx)
|
|||
visible_strips_ordered_get(timeline_ctx, unselected, selected);
|
||||
draw_seq_strips(timeline_ctx, unselected);
|
||||
draw_seq_strips(timeline_ctx, selected);
|
||||
|
||||
/* Draw text overlay parts in the opposite order: first selected set, then
|
||||
* unselected (UI_view2d_text_cache_add_rectf adds new text in front of
|
||||
* other entries!). This is to make sure selected strip labels are on top
|
||||
* of others while they are being dragged over. */
|
||||
for (const StripDrawContext &strip_ctx : selected) {
|
||||
draw_seq_text_overlay(timeline_ctx, &strip_ctx);
|
||||
}
|
||||
for (const StripDrawContext &strip_ctx : unselected) {
|
||||
draw_seq_text_overlay(timeline_ctx, &strip_ctx);
|
||||
}
|
||||
UI_view2d_text_cache_draw(timeline_ctx->region);
|
||||
}
|
||||
|
||||
static void draw_timeline_sfra_efra(TimelineDrawContext *ctx)
|
||||
|
@ -1568,7 +1686,7 @@ static void draw_timeline_sfra_efra(TimelineDrawContext *ctx)
|
|||
}
|
||||
|
||||
struct CacheDrawData {
|
||||
View2D *v2d;
|
||||
const View2D *v2d;
|
||||
float stripe_ofs_y;
|
||||
float stripe_ht;
|
||||
int cache_flag;
|
||||
|
@ -1649,8 +1767,8 @@ static void draw_cache_stripe(const Scene *scene,
|
|||
static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
|
||||
{
|
||||
using blender::uchar4;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
|
||||
const uchar4 bg_final{255, 102, 51, 25};
|
||||
const uchar4 bg_raw{255, 25, 5, 25};
|
||||
|
@ -1692,7 +1810,7 @@ static void draw_cache_background(const bContext *C, CacheDrawData *draw_data)
|
|||
static void draw_cache_view(const bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View2D *v2d = UI_view2d_fromcontext(C);
|
||||
const View2D *v2d = UI_view2d_fromcontext(C);
|
||||
|
||||
if ((scene->ed->cache_flag & SEQ_CACHE_VIEW_ENABLE) == 0) {
|
||||
return;
|
||||
|
@ -1816,8 +1934,7 @@ static void draw_timeline_post_view_callbacks(TimelineDrawContext *ctx)
|
|||
void draw_timeline_seq(const bContext *C, ARegion *region)
|
||||
{
|
||||
SeqQuadsBatch quads_batch;
|
||||
TimelineDrawContext ctx = timeline_draw_context_get(C);
|
||||
ctx.quads = &quads_batch;
|
||||
TimelineDrawContext ctx = timeline_draw_context_get(C, &quads_batch);
|
||||
|
||||
draw_timeline_pre_view_callbacks(&ctx);
|
||||
UI_ThemeClearColor(TH_BACK);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
static void createTransSculpt(bContext *C, TransInfo *t)
|
||||
{
|
||||
using namespace blender::ed;
|
||||
TransData *td;
|
||||
|
||||
Scene *scene = t->scene;
|
||||
|
@ -95,7 +96,7 @@ static void createTransSculpt(bContext *C, TransInfo *t)
|
|||
copy_m3_m4(td->axismtx, ob->object_to_world().ptr());
|
||||
|
||||
BLI_assert(!(t->options & CTX_PAINT_CURVE));
|
||||
ED_sculpt_init_transform(C, ob, t->mval, t->undo_name);
|
||||
sculpt_paint::init_transform(C, ob, t->mval, t->undo_name);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -106,23 +107,25 @@ static void createTransSculpt(bContext *C, TransInfo *t)
|
|||
|
||||
static void recalcData_sculpt(TransInfo *t)
|
||||
{
|
||||
using namespace blender::ed;
|
||||
BKE_view_layer_synced_ensure(t->scene, t->view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(t->view_layer);
|
||||
ED_sculpt_update_modal_transform(t->context, ob);
|
||||
sculpt_paint::update_modal_transform(t->context, ob);
|
||||
}
|
||||
|
||||
static void special_aftertrans_update__sculpt(bContext *C, TransInfo *t)
|
||||
{
|
||||
using namespace blender::ed;
|
||||
Scene *scene = t->scene;
|
||||
if (!BKE_id_is_editable(CTX_data_main(C), &scene->id)) {
|
||||
/* `ED_sculpt_init_transform` was not called in this case. */
|
||||
/* `sculpt_paint::init_transform` was not called in this case. */
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_view_layer_synced_ensure(t->scene, t->view_layer);
|
||||
Object *ob = BKE_view_layer_active_object_get(t->view_layer);
|
||||
BLI_assert(!(t->options & CTX_PAINT_CURVE));
|
||||
ED_sculpt_end_transform(C, ob);
|
||||
sculpt_paint::end_transform(C, ob);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -1664,7 +1664,7 @@ void MTLContext::ensure_texture_bindings(
|
|||
/* Texture type for bound texture (e.g. Texture2DArray) does not match what was
|
||||
* expected in the shader interface. This is a problem and we will need to bind
|
||||
* a dummy texture to ensure correct API usage. */
|
||||
MTL_LOG_WARNING(
|
||||
MTL_LOG_ERROR(
|
||||
"(Shader '%s') Texture (%s) %p bound to slot %d is incompatible -- Wrong "
|
||||
"texture target type. (Expecting type %d, actual type %d) (binding "
|
||||
"name:'%s')(texture name:'%s')",
|
||||
|
@ -1679,7 +1679,7 @@ void MTLContext::ensure_texture_bindings(
|
|||
}
|
||||
}
|
||||
else {
|
||||
MTL_LOG_WARNING(
|
||||
MTL_LOG_ERROR(
|
||||
"Shader '%s' expected texture (%s) to be bound to location %d (texture[[%d]]) -- No "
|
||||
"texture was "
|
||||
"bound. (name:'%s')",
|
||||
|
@ -1715,7 +1715,7 @@ void MTLContext::ensure_texture_bindings(
|
|||
}
|
||||
}
|
||||
else {
|
||||
MTL_LOG_WARNING(
|
||||
MTL_LOG_ERROR(
|
||||
"Shader %p expected texture (%s) to be bound to slot %d -- Slot exceeds the "
|
||||
"hardware/API limit of '%d'. (name:'%s')",
|
||||
this->pipeline_state.active_shader,
|
||||
|
@ -1915,7 +1915,7 @@ void MTLContext::ensure_texture_bindings(
|
|||
/* Texture type for bound texture (e.g. Texture2DArray) does not match what was
|
||||
* expected in the shader interface. This is a problem and we will need to bind
|
||||
* a dummy texture to ensure correct API usage. */
|
||||
MTL_LOG_WARNING(
|
||||
MTL_LOG_ERROR(
|
||||
"(Shader '%s') Texture (%s) %p bound to slot %d is incompatible -- Wrong "
|
||||
"texture target type. (Expecting type %d, actual type %d) (binding "
|
||||
"name:'%s')(texture name:'%s')",
|
||||
|
@ -1930,7 +1930,7 @@ void MTLContext::ensure_texture_bindings(
|
|||
}
|
||||
}
|
||||
else {
|
||||
MTL_LOG_WARNING(
|
||||
MTL_LOG_ERROR(
|
||||
"Shader '%s' expected texture (%s) to be bound to location %d (texture[[%d]]) -- No "
|
||||
"texture was "
|
||||
"bound. (name:'%s')",
|
||||
|
@ -1958,7 +1958,7 @@ void MTLContext::ensure_texture_bindings(
|
|||
}
|
||||
}
|
||||
else {
|
||||
MTL_LOG_WARNING(
|
||||
MTL_LOG_ERROR(
|
||||
"Shader %p expected texture (%s) to be bound to slot %d -- Slot exceeds the "
|
||||
"hardware/API limit of '%d'. (name:'%s')",
|
||||
this->pipeline_state.active_shader,
|
||||
|
@ -2387,9 +2387,9 @@ void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit, b
|
|||
if (texture_unit < 0 || texture_unit >= GPU_max_textures() ||
|
||||
texture_unit >= MTL_MAX_TEXTURE_SLOTS)
|
||||
{
|
||||
MTL_LOG_WARNING("Attempting to bind texture '%s' to invalid texture unit %d",
|
||||
mtl_texture->get_name(),
|
||||
texture_unit);
|
||||
MTL_LOG_ERROR("Attempting to bind texture '%s' to invalid texture unit %d",
|
||||
mtl_texture->get_name(),
|
||||
texture_unit);
|
||||
BLI_assert(false);
|
||||
return;
|
||||
}
|
||||
|
@ -2411,7 +2411,7 @@ void MTLContext::sampler_bind(MTLSamplerState sampler_state, uint sampler_unit)
|
|||
if (sampler_unit < 0 || sampler_unit >= GPU_max_textures() ||
|
||||
sampler_unit >= MTL_MAX_SAMPLER_SLOTS)
|
||||
{
|
||||
MTL_LOG_WARNING("Attempting to bind sampler to invalid sampler unit %d", sampler_unit);
|
||||
MTL_LOG_ERROR("Attempting to bind sampler to invalid sampler unit %d", sampler_unit);
|
||||
BLI_assert(false);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,13 @@
|
|||
|
||||
void node_point_info(out vec3 position, out float radius, out float random)
|
||||
{
|
||||
#ifdef POINTCLOUD_SHADER
|
||||
#ifdef MAT_GEOM_POINT_CLOUD
|
||||
/* EEVEE-Next case. */
|
||||
position = point_cloud_interp.position;
|
||||
radius = point_cloud_interp.radius;
|
||||
random = wang_hash_noise(uint(point_cloud_interp_flat.id));
|
||||
#elif defined(POINTCLOUD_SHADER)
|
||||
/* EEVEE-Legacy case. */
|
||||
position = pointPosition;
|
||||
radius = pointRadius;
|
||||
random = wang_hash_noise(uint(pointID));
|
||||
|
|
|
@ -169,7 +169,7 @@ class VKRenderGraph : public NonCopyable {
|
|||
* Submit partial graph to be able to read the expected result of the rendering commands
|
||||
* affecting the given vk_buffer. This method is called from
|
||||
* `GPU_texture/storagebuf/indexbuf/vertbuf/_read`. In vulkan the content of images cannot be
|
||||
* read directly and always needs tobe copied to a transfer buffer.
|
||||
* read directly and always needs to be copied to a transfer buffer.
|
||||
*
|
||||
* After calling this function the mapped memory of the vk_buffer would contain the data of the
|
||||
* buffer.
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* different workflow as its state can be altered externally and needs to be reset.
|
||||
* - Read/Write access masks: To generate correct and performing pipeline barriers the src/dst
|
||||
* access masks needs to be accurate and precise. When creating pipeline barriers the resource
|
||||
* usage upto that point should be known and the resource usage from that point on.
|
||||
* usage up to that point should be known and the resource usage from that point on.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
|
|
@ -61,17 +61,17 @@ class VKDevice;
|
|||
* Some of the information would be boiler plating; or at least from Blender point of view. To
|
||||
* improve lookup performance we use a slimmed down version of the pipeline create info structs.
|
||||
* The idea is that we can limit the required data because we control which data we actually use,
|
||||
* removing te boiler plating and improve hashing performance better than the VkPipelineCache can
|
||||
* removing the boiler plating and improve hashing performance better than the VkPipelineCache can
|
||||
* give us.
|
||||
*
|
||||
* TODO: Extensions like `VK_EXT_graphics_pipeline_library` should fit in this class and ease the
|
||||
* development for graphics pipelines. Geometry in and framebuffer out could be cached separately
|
||||
* development for graphics pipelines. Geometry in and frame-buffer out could be cached separately
|
||||
* to reduce pipeline creation times. Most likely we will add support when we work on graphic
|
||||
* pipelines. Recent drivers all support this extension, but the full coverage is still <20%. A
|
||||
* fallback should made available for older drivers is required.
|
||||
*
|
||||
* TODO: Creation of shader modules needs to be revisited.
|
||||
* VK_EXT_graphics_pipeline_library deprecates the use of shader modules and use the spriv bin
|
||||
* VK_EXT_graphics_pipeline_library deprecates the use of shader modules and use the `spriv` bin
|
||||
* directly. In this extension the pipeline and shader module are the same. The current approach
|
||||
* should also be revisited as the latest drivers all implement pipeline libraries, but there are
|
||||
* some platforms where the driver isn't been updated and doesn't implement this extension. In
|
||||
|
|
|
@ -491,6 +491,7 @@ static proxy_output_ctx *alloc_proxy_output_ffmpeg(
|
|||
|
||||
get_proxy_filepath(rv->anim, rv->proxy_size, filepath, true);
|
||||
if (!BLI_file_ensure_parent_dir_exists(filepath)) {
|
||||
MEM_freeN(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -737,6 +737,23 @@ void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTim
|
|||
creases.finish();
|
||||
}
|
||||
|
||||
void USDMeshReader::read_velocities(Mesh *mesh, const double motionSampleTime)
|
||||
{
|
||||
pxr::VtVec3fArray velocities;
|
||||
mesh_prim_.GetVelocitiesAttr().Get(&velocities, motionSampleTime);
|
||||
|
||||
if (!velocities.empty()) {
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
bke::GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
|
||||
"velocity", bke::AttrDomain::Point, CD_PROP_FLOAT3);
|
||||
|
||||
Span<pxr::GfVec3f> usd_data(velocities.data(), velocities.size());
|
||||
attribute.span.typed<float3>().copy_from(usd_data.cast<float3>());
|
||||
|
||||
attribute.finish();
|
||||
}
|
||||
}
|
||||
|
||||
void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
|
||||
{
|
||||
if (!mesh) {
|
||||
|
@ -868,6 +885,7 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
|
|||
(settings->read_flag & MOD_MESHSEQ_READ_COLOR) ||
|
||||
(settings->read_flag & MOD_MESHSEQ_READ_ATTRIBUTES))
|
||||
{
|
||||
read_velocities(mesh, motionSampleTime);
|
||||
read_custom_data(settings, mesh, motionSampleTime, new_mesh);
|
||||
}
|
||||
}
|
||||
|
@ -913,6 +931,11 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* We handle the non-standard primvar:velocity elsewhere. */
|
||||
if (ELEM(name, "velocity")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ELEM(type,
|
||||
pxr::SdfValueTypeNames->StringArray,
|
||||
pxr::SdfValueTypeNames->QuatfArray,
|
||||
|
|
|
@ -78,6 +78,7 @@ class USDMeshReader : public USDGeomReader {
|
|||
|
||||
void read_mpolys(Mesh *mesh);
|
||||
void read_vertex_creases(Mesh *mesh, double motionSampleTime);
|
||||
void read_velocities(Mesh *mesh, double motionSampleTime);
|
||||
|
||||
void read_mesh_sample(ImportSettings *settings,
|
||||
Mesh *mesh,
|
||||
|
|
|
@ -180,7 +180,7 @@ class USDPrimReader {
|
|||
*
|
||||
* \param merge_with_parent: If true, set the properties of the prim's parent
|
||||
* on the object ID
|
||||
* \param motionSampleTime: The time code for sampling tha USD attributes
|
||||
* \param motionSampleTime: The time code for sampling the USD attributes.
|
||||
*/
|
||||
void set_props(bool merge_with_parent = false,
|
||||
pxr::UsdTimeCode motionSampleTime = pxr::UsdTimeCode::Default());
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "usd_hierarchy_iterator.hh"
|
||||
#include "usd_writer_curves.hh"
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_curve_legacy_convert.hh"
|
||||
#include "BKE_curves.hh"
|
||||
|
@ -28,18 +30,12 @@
|
|||
|
||||
namespace blender::io::usd {
|
||||
|
||||
USDCurvesWriter::USDCurvesWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) {}
|
||||
|
||||
USDCurvesWriter::~USDCurvesWriter() {}
|
||||
|
||||
pxr::UsdGeomCurves USDCurvesWriter::DefineUsdGeomBasisCurves(pxr::VtValue curve_basis,
|
||||
const bool is_cyclic,
|
||||
const bool is_cubic)
|
||||
pxr::UsdGeomBasisCurves USDCurvesWriter::DefineUsdGeomBasisCurves(pxr::VtValue curve_basis,
|
||||
const bool is_cyclic,
|
||||
const bool is_cubic) const
|
||||
{
|
||||
pxr::UsdGeomCurves curves = pxr::UsdGeomBasisCurves::Define(usd_export_context_.stage,
|
||||
usd_export_context_.usd_path);
|
||||
|
||||
pxr::UsdGeomBasisCurves basis_curves = pxr::UsdGeomBasisCurves(curves);
|
||||
pxr::UsdGeomBasisCurves basis_curves = pxr::UsdGeomBasisCurves::Define(
|
||||
usd_export_context_.stage, usd_export_context_.usd_path);
|
||||
/* Not required to set the basis attribute for linear curves
|
||||
* https://graphics.pixar.com/usd/dev/api/class_usd_geom_basis_curves.html#details */
|
||||
if (is_cubic) {
|
||||
|
@ -64,12 +60,12 @@ pxr::UsdGeomCurves USDCurvesWriter::DefineUsdGeomBasisCurves(pxr::VtValue curve_
|
|||
basis_curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->nonperiodic));
|
||||
}
|
||||
|
||||
return curves;
|
||||
return basis_curves;
|
||||
}
|
||||
|
||||
static void populate_curve_widths(const bke::CurvesGeometry &geometry, pxr::VtArray<float> &widths)
|
||||
static void populate_curve_widths(const bke::CurvesGeometry &curves, pxr::VtArray<float> &widths)
|
||||
{
|
||||
const bke::AttributeAccessor curve_attributes = geometry.attributes();
|
||||
const bke::AttributeAccessor curve_attributes = curves.attributes();
|
||||
const bke::AttributeReader<float> radii = curve_attributes.lookup<float>("radius",
|
||||
bke::AttrDomain::Point);
|
||||
|
||||
|
@ -113,7 +109,7 @@ static pxr::TfToken get_curve_width_interpolation(const pxr::VtArray<float> &wid
|
|||
return pxr::TfToken();
|
||||
}
|
||||
|
||||
static void populate_curve_verts(const bke::CurvesGeometry &geometry,
|
||||
static void populate_curve_verts(const bke::CurvesGeometry &curves,
|
||||
const Span<float3> positions,
|
||||
pxr::VtArray<pxr::GfVec3f> &verts,
|
||||
pxr::VtIntArray &control_point_counts,
|
||||
|
@ -121,8 +117,8 @@ static void populate_curve_verts(const bke::CurvesGeometry &geometry,
|
|||
const bool is_cyclic,
|
||||
const bool is_cubic)
|
||||
{
|
||||
const OffsetIndices points_by_curve = geometry.points_by_curve();
|
||||
for (const int i_curve : geometry.curves_range()) {
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
for (const int i_curve : curves.curves_range()) {
|
||||
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
for (const int i_point : points) {
|
||||
|
@ -151,7 +147,7 @@ static void populate_curve_verts(const bke::CurvesGeometry &geometry,
|
|||
}
|
||||
}
|
||||
|
||||
static void populate_curve_props(const bke::CurvesGeometry &geometry,
|
||||
static void populate_curve_props(const bke::CurvesGeometry &curves,
|
||||
pxr::VtArray<pxr::GfVec3f> &verts,
|
||||
pxr::VtIntArray &control_point_counts,
|
||||
pxr::VtArray<float> &widths,
|
||||
|
@ -160,20 +156,20 @@ static void populate_curve_props(const bke::CurvesGeometry &geometry,
|
|||
const bool is_cubic,
|
||||
ReportList *reports)
|
||||
{
|
||||
const int num_curves = geometry.curve_num;
|
||||
const Span<float3> positions = geometry.positions();
|
||||
const int num_curves = curves.curve_num;
|
||||
const Span<float3> positions = curves.positions();
|
||||
|
||||
pxr::VtArray<int> segments(num_curves);
|
||||
|
||||
populate_curve_verts(
|
||||
geometry, positions, verts, control_point_counts, segments, is_cyclic, is_cubic);
|
||||
curves, positions, verts, control_point_counts, segments, is_cyclic, is_cubic);
|
||||
|
||||
populate_curve_widths(geometry, widths);
|
||||
populate_curve_widths(curves, widths);
|
||||
interpolation = get_curve_width_interpolation(
|
||||
widths, segments, control_point_counts, is_cyclic, reports);
|
||||
}
|
||||
|
||||
static void populate_curve_verts_for_bezier(const bke::CurvesGeometry &geometry,
|
||||
static void populate_curve_verts_for_bezier(const bke::CurvesGeometry &curves,
|
||||
const Span<float3> positions,
|
||||
const Span<float3> handles_l,
|
||||
const Span<float3> handles_r,
|
||||
|
@ -183,9 +179,9 @@ static void populate_curve_verts_for_bezier(const bke::CurvesGeometry &geometry,
|
|||
const bool is_cyclic)
|
||||
{
|
||||
const int bezier_vstep = 3;
|
||||
const OffsetIndices points_by_curve = geometry.points_by_curve();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
for (const int i_curve : geometry.curves_range()) {
|
||||
for (const int i_curve : curves.curves_range()) {
|
||||
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
const int start_point_index = points[0];
|
||||
|
@ -236,7 +232,7 @@ static void populate_curve_verts_for_bezier(const bke::CurvesGeometry &geometry,
|
|||
}
|
||||
}
|
||||
|
||||
static void populate_curve_props_for_bezier(const bke::CurvesGeometry &geometry,
|
||||
static void populate_curve_props_for_bezier(const bke::CurvesGeometry &curves,
|
||||
pxr::VtArray<pxr::GfVec3f> &verts,
|
||||
pxr::VtIntArray &control_point_counts,
|
||||
pxr::VtArray<float> &widths,
|
||||
|
@ -244,25 +240,23 @@ static void populate_curve_props_for_bezier(const bke::CurvesGeometry &geometry,
|
|||
const bool is_cyclic,
|
||||
ReportList *reports)
|
||||
{
|
||||
const int num_curves = curves.curve_num;
|
||||
|
||||
const int num_curves = geometry.curve_num;
|
||||
|
||||
const Span<float3> positions = geometry.positions();
|
||||
|
||||
const Span<float3> handles_l = geometry.handle_positions_left();
|
||||
const Span<float3> handles_r = geometry.handle_positions_right();
|
||||
const Span<float3> positions = curves.positions();
|
||||
const Span<float3> handles_l = curves.handle_positions_left();
|
||||
const Span<float3> handles_r = curves.handle_positions_right();
|
||||
|
||||
pxr::VtArray<int> segments(num_curves);
|
||||
|
||||
populate_curve_verts_for_bezier(
|
||||
geometry, positions, handles_l, handles_r, verts, control_point_counts, segments, is_cyclic);
|
||||
curves, positions, handles_l, handles_r, verts, control_point_counts, segments, is_cyclic);
|
||||
|
||||
populate_curve_widths(geometry, widths);
|
||||
populate_curve_widths(curves, widths);
|
||||
interpolation = get_curve_width_interpolation(
|
||||
widths, segments, control_point_counts, is_cyclic, reports);
|
||||
}
|
||||
|
||||
static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &geometry,
|
||||
static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &curves,
|
||||
pxr::VtArray<pxr::GfVec3f> &verts,
|
||||
pxr::VtIntArray &control_point_counts,
|
||||
pxr::VtArray<float> &widths,
|
||||
|
@ -273,16 +267,16 @@ static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &geometry,
|
|||
{
|
||||
/* Order and range, when representing a batched NurbsCurve should be authored one value per
|
||||
* curve. */
|
||||
const int num_curves = geometry.curve_num;
|
||||
const int num_curves = curves.curve_num;
|
||||
orders.resize(num_curves);
|
||||
|
||||
const Span<float3> positions = geometry.positions();
|
||||
const Span<float3> positions = curves.positions();
|
||||
|
||||
VArray<int8_t> geom_orders = geometry.nurbs_orders();
|
||||
VArray<int8_t> knots_modes = geometry.nurbs_knots_modes();
|
||||
VArray<int8_t> geom_orders = curves.nurbs_orders();
|
||||
VArray<int8_t> knots_modes = curves.nurbs_knots_modes();
|
||||
|
||||
const OffsetIndices points_by_curve = geometry.points_by_curve();
|
||||
for (const int i_curve : geometry.curves_range()) {
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
for (const int i_curve : curves.curves_range()) {
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
for (const int i_point : points) {
|
||||
verts.push_back(
|
||||
|
@ -322,27 +316,26 @@ static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &geometry,
|
|||
}
|
||||
}
|
||||
|
||||
populate_curve_widths(geometry, widths);
|
||||
populate_curve_widths(curves, widths);
|
||||
interpolation = pxr::UsdGeomTokens->vertex;
|
||||
}
|
||||
|
||||
void USDCurvesWriter::set_writer_attributes_for_nurbs(const pxr::UsdGeomCurves usd_curves,
|
||||
const pxr::VtArray<double> knots,
|
||||
const pxr::VtArray<int> orders,
|
||||
const pxr::UsdTimeCode timecode)
|
||||
void USDCurvesWriter::set_writer_attributes_for_nurbs(
|
||||
const pxr::UsdGeomNurbsCurves &usd_nurbs_curves,
|
||||
const pxr::VtArray<double> &knots,
|
||||
const pxr::VtArray<int> &orders,
|
||||
const pxr::UsdTimeCode timecode)
|
||||
{
|
||||
pxr::UsdAttribute attr_knots =
|
||||
pxr::UsdGeomNurbsCurves(usd_curves).CreateKnotsAttr(pxr::VtValue(), true);
|
||||
pxr::UsdAttribute attr_knots = usd_nurbs_curves.CreateKnotsAttr(pxr::VtValue(), true);
|
||||
usd_value_writer_.SetAttribute(attr_knots, pxr::VtValue(knots), timecode);
|
||||
pxr::UsdAttribute attr_order =
|
||||
pxr::UsdGeomNurbsCurves(usd_curves).CreateOrderAttr(pxr::VtValue(), true);
|
||||
pxr::UsdAttribute attr_order = usd_nurbs_curves.CreateOrderAttr(pxr::VtValue(), true);
|
||||
usd_value_writer_.SetAttribute(attr_order, pxr::VtValue(orders), timecode);
|
||||
}
|
||||
|
||||
void USDCurvesWriter::set_writer_attributes(pxr::UsdGeomCurves &usd_curves,
|
||||
const pxr::VtArray<pxr::GfVec3f> verts,
|
||||
const pxr::VtIntArray control_point_counts,
|
||||
const pxr::VtArray<float> widths,
|
||||
const pxr::VtArray<pxr::GfVec3f> &verts,
|
||||
const pxr::VtIntArray &control_point_counts,
|
||||
const pxr::VtArray<float> &widths,
|
||||
const pxr::UsdTimeCode timecode,
|
||||
const pxr::TfToken interpolation)
|
||||
{
|
||||
|
@ -353,7 +346,7 @@ void USDCurvesWriter::set_writer_attributes(pxr::UsdGeomCurves &usd_curves,
|
|||
true);
|
||||
usd_value_writer_.SetAttribute(attr_vertex_counts, pxr::VtValue(control_point_counts), timecode);
|
||||
|
||||
if (widths.size() > 0) {
|
||||
if (!widths.empty()) {
|
||||
pxr::UsdAttribute attr_widths = usd_curves.CreateWidthsAttr(pxr::VtValue(), true);
|
||||
usd_value_writer_.SetAttribute(attr_widths, pxr::VtValue(widths), timecode);
|
||||
|
||||
|
@ -363,7 +356,7 @@ void USDCurvesWriter::set_writer_attributes(pxr::UsdGeomCurves &usd_curves,
|
|||
|
||||
void USDCurvesWriter::do_write(HierarchyContext &context)
|
||||
{
|
||||
Curves *curves;
|
||||
Curves *curves_id;
|
||||
std::unique_ptr<Curves, std::function<void(Curves *)>> converted_curves;
|
||||
|
||||
switch (context.object->type) {
|
||||
|
@ -371,46 +364,33 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
const Curve *legacy_curve = static_cast<Curve *>(context.object->data);
|
||||
converted_curves = std::unique_ptr<Curves, std::function<void(Curves *)>>(
|
||||
bke::curve_legacy_to_curves(*legacy_curve), [](Curves *c) { BKE_id_free(nullptr, c); });
|
||||
curves = converted_curves.get();
|
||||
curves_id = converted_curves.get();
|
||||
break;
|
||||
}
|
||||
case OB_CURVES:
|
||||
curves = static_cast<Curves *>(context.object->data);
|
||||
curves_id = static_cast<Curves *>(context.object->data);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
const bke::CurvesGeometry &geometry = curves->geometry.wrap();
|
||||
if (geometry.points_num() == 0) {
|
||||
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::array<int, CURVE_TYPES_NUM> curve_type_counts = geometry.curve_type_counts();
|
||||
const int number_of_curve_types = std::reduce(
|
||||
curve_type_counts.begin(), curve_type_counts.end(), 0, [](int previous_result, int item) {
|
||||
return item > 0 ? ++previous_result : previous_result;
|
||||
});
|
||||
|
||||
const std::array<int, CURVE_TYPES_NUM> &curve_type_counts = curves.curve_type_counts();
|
||||
const int number_of_curve_types = std::count_if(curve_type_counts.begin(),
|
||||
curve_type_counts.end(),
|
||||
[](const int count) { return count > 0; });
|
||||
if (number_of_curve_types > 1) {
|
||||
BKE_report(
|
||||
reports(), RPT_WARNING, "Cannot export mixed curve types in the same Curves object");
|
||||
return;
|
||||
}
|
||||
|
||||
const VArray<bool> cyclic_values = geometry.cyclic();
|
||||
const bool is_cyclic = cyclic_values[0];
|
||||
bool all_same_cyclic_type = true;
|
||||
|
||||
for (const int i : cyclic_values.index_range()) {
|
||||
if (cyclic_values[i] != is_cyclic) {
|
||||
all_same_cyclic_type = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!all_same_cyclic_type) {
|
||||
if (array_utils::booleans_mix_calc(curves.cyclic()) == array_utils::BooleanMix::Mixed) {
|
||||
BKE_report(reports(),
|
||||
RPT_WARNING,
|
||||
"Cannot export mixed cyclic and non-cyclic curves in the same Curves object");
|
||||
|
@ -418,15 +398,7 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
}
|
||||
|
||||
const pxr::UsdTimeCode timecode = get_export_time_code();
|
||||
pxr::UsdGeomCurves usd_curves;
|
||||
|
||||
pxr::VtArray<pxr::GfVec3f> verts;
|
||||
pxr::VtIntArray control_point_counts;
|
||||
control_point_counts.resize(geometry.curves_num());
|
||||
pxr::VtArray<float> widths;
|
||||
pxr::TfToken interpolation;
|
||||
|
||||
const int8_t curve_type = geometry.curve_types()[0];
|
||||
const int8_t curve_type = curves.curve_types()[0];
|
||||
|
||||
if (first_frame_curve_type == -1) {
|
||||
first_frame_curve_type = curve_type;
|
||||
|
@ -450,51 +422,54 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
return;
|
||||
}
|
||||
|
||||
const bool is_cyclic = curves.cyclic().first();
|
||||
pxr::VtArray<pxr::GfVec3f> verts;
|
||||
pxr::VtIntArray control_point_counts;
|
||||
pxr::VtArray<float> widths;
|
||||
pxr::TfToken interpolation;
|
||||
|
||||
pxr::UsdGeomBasisCurves usd_basis_curves;
|
||||
pxr::UsdGeomNurbsCurves usd_nurbs_curves;
|
||||
pxr::UsdGeomCurves *usd_curves = nullptr;
|
||||
|
||||
control_point_counts.resize(curves.curves_num());
|
||||
switch (curve_type) {
|
||||
case CURVE_TYPE_POLY:
|
||||
usd_curves = DefineUsdGeomBasisCurves(pxr::VtValue(), is_cyclic, false);
|
||||
usd_basis_curves = DefineUsdGeomBasisCurves(pxr::VtValue(), is_cyclic, false);
|
||||
usd_curves = &usd_basis_curves;
|
||||
|
||||
populate_curve_props(geometry,
|
||||
verts,
|
||||
control_point_counts,
|
||||
widths,
|
||||
interpolation,
|
||||
is_cyclic,
|
||||
false,
|
||||
reports());
|
||||
populate_curve_props(
|
||||
curves, verts, control_point_counts, widths, interpolation, is_cyclic, false, reports());
|
||||
break;
|
||||
case CURVE_TYPE_CATMULL_ROM:
|
||||
usd_curves = DefineUsdGeomBasisCurves(
|
||||
usd_basis_curves = DefineUsdGeomBasisCurves(
|
||||
pxr::VtValue(pxr::UsdGeomTokens->catmullRom), is_cyclic, true);
|
||||
usd_curves = &usd_basis_curves;
|
||||
|
||||
populate_curve_props(geometry,
|
||||
verts,
|
||||
control_point_counts,
|
||||
widths,
|
||||
interpolation,
|
||||
is_cyclic,
|
||||
true,
|
||||
reports());
|
||||
populate_curve_props(
|
||||
curves, verts, control_point_counts, widths, interpolation, is_cyclic, true, reports());
|
||||
break;
|
||||
case CURVE_TYPE_BEZIER:
|
||||
usd_curves = DefineUsdGeomBasisCurves(
|
||||
usd_basis_curves = DefineUsdGeomBasisCurves(
|
||||
pxr::VtValue(pxr::UsdGeomTokens->bezier), is_cyclic, true);
|
||||
usd_curves = &usd_basis_curves;
|
||||
|
||||
populate_curve_props_for_bezier(
|
||||
geometry, verts, control_point_counts, widths, interpolation, is_cyclic, reports());
|
||||
curves, verts, control_point_counts, widths, interpolation, is_cyclic, reports());
|
||||
break;
|
||||
case CURVE_TYPE_NURBS: {
|
||||
pxr::VtArray<double> knots;
|
||||
pxr::VtArray<int> orders;
|
||||
orders.resize(geometry.curves_num());
|
||||
orders.resize(curves.curves_num());
|
||||
|
||||
usd_curves = pxr::UsdGeomNurbsCurves::Define(usd_export_context_.stage,
|
||||
usd_export_context_.usd_path);
|
||||
usd_nurbs_curves = pxr::UsdGeomNurbsCurves::Define(usd_export_context_.stage,
|
||||
usd_export_context_.usd_path);
|
||||
usd_curves = &usd_nurbs_curves;
|
||||
|
||||
populate_curve_props_for_nurbs(
|
||||
geometry, verts, control_point_counts, widths, knots, orders, interpolation, is_cyclic);
|
||||
curves, verts, control_point_counts, widths, knots, orders, interpolation, is_cyclic);
|
||||
|
||||
set_writer_attributes_for_nurbs(usd_curves, knots, orders, timecode);
|
||||
set_writer_attributes_for_nurbs(usd_nurbs_curves, knots, orders, timecode);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -502,16 +477,16 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
set_writer_attributes(usd_curves, verts, control_point_counts, widths, timecode, interpolation);
|
||||
set_writer_attributes(*usd_curves, verts, control_point_counts, widths, timecode, interpolation);
|
||||
|
||||
assign_materials(context, usd_curves);
|
||||
assign_materials(context, *usd_curves);
|
||||
|
||||
auto prim = usd_curves.GetPrim();
|
||||
write_id_properties(prim, curves->id, timecode);
|
||||
auto prim = usd_curves->GetPrim();
|
||||
write_id_properties(prim, curves_id->id, timecode);
|
||||
}
|
||||
|
||||
void USDCurvesWriter::assign_materials(const HierarchyContext &context,
|
||||
pxr::UsdGeomCurves usd_curve)
|
||||
const pxr::UsdGeomCurves &usd_curves)
|
||||
{
|
||||
if (context.object->totcol == 0) {
|
||||
return;
|
||||
|
@ -524,15 +499,15 @@ void USDCurvesWriter::assign_materials(const HierarchyContext &context,
|
|||
continue;
|
||||
}
|
||||
|
||||
pxr::UsdPrim curve_prim = usd_curve.GetPrim();
|
||||
pxr::UsdPrim curve_prim = usd_curves.GetPrim();
|
||||
pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(curve_prim);
|
||||
pxr::UsdShadeMaterial usd_material = ensure_usd_material(context, material);
|
||||
api.Bind(usd_material);
|
||||
api.Apply(curve_prim);
|
||||
pxr::UsdShadeMaterialBindingAPI::Apply(curve_prim);
|
||||
|
||||
/* USD seems to support neither per-material nor per-face-group double-sidedness, so we just
|
||||
* use the flag from the first non-empty material slot. */
|
||||
usd_curve.CreateDoubleSidedAttr(
|
||||
usd_curves.CreateDoubleSidedAttr(
|
||||
pxr::VtValue((material->blend_flag & MA_BL_CULL_BACKFACE) == 0));
|
||||
|
||||
curve_material_bound = true;
|
||||
|
@ -541,7 +516,7 @@ void USDCurvesWriter::assign_materials(const HierarchyContext &context,
|
|||
|
||||
if (!curve_material_bound) {
|
||||
/* Blender defaults to double-sided, but USD to single-sided. */
|
||||
usd_curve.CreateDoubleSidedAttr(pxr::VtValue(true));
|
||||
usd_curves.CreateDoubleSidedAttr(pxr::VtValue(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,34 +5,38 @@
|
|||
|
||||
#include "usd_writer_abstract.hh"
|
||||
|
||||
#include <pxr/usd/usdGeom/basisCurves.h>
|
||||
#include <pxr/usd/usdGeom/curves.h>
|
||||
#include <pxr/usd/usdGeom/nurbsCurves.h>
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
/* Writer for writing Curves data as USD curves. */
|
||||
class USDCurvesWriter : public USDAbstractWriter {
|
||||
public:
|
||||
USDCurvesWriter(const USDExporterContext &ctx);
|
||||
~USDCurvesWriter();
|
||||
USDCurvesWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) {}
|
||||
~USDCurvesWriter() final = default;
|
||||
|
||||
protected:
|
||||
virtual void do_write(HierarchyContext &context) override;
|
||||
void assign_materials(const HierarchyContext &context, pxr::UsdGeomCurves usd_curve);
|
||||
void assign_materials(const HierarchyContext &context, const pxr::UsdGeomCurves &usd_curves);
|
||||
|
||||
private:
|
||||
int8_t first_frame_curve_type = -1;
|
||||
pxr::UsdGeomCurves DefineUsdGeomBasisCurves(pxr::VtValue curve_basis, bool cyclic, bool cubic);
|
||||
pxr::UsdGeomBasisCurves DefineUsdGeomBasisCurves(pxr::VtValue curve_basis,
|
||||
bool cyclic,
|
||||
bool cubic) const;
|
||||
|
||||
void set_writer_attributes(pxr::UsdGeomCurves &usd_curves,
|
||||
const pxr::VtArray<pxr::GfVec3f> verts,
|
||||
const pxr::VtIntArray control_point_counts,
|
||||
const pxr::VtArray<float> widths,
|
||||
const pxr::VtArray<pxr::GfVec3f> &verts,
|
||||
const pxr::VtIntArray &control_point_counts,
|
||||
const pxr::VtArray<float> &widths,
|
||||
const pxr::UsdTimeCode timecode,
|
||||
const pxr::TfToken interpolation);
|
||||
|
||||
void set_writer_attributes_for_nurbs(const pxr::UsdGeomCurves usd_curves,
|
||||
const pxr::VtArray<double> knots,
|
||||
const pxr::VtArray<int> orders,
|
||||
void set_writer_attributes_for_nurbs(const pxr::UsdGeomNurbsCurves &usd_nurbs_curves,
|
||||
const pxr::VtArray<double> &knots,
|
||||
const pxr::VtArray<int> &orders,
|
||||
const pxr::UsdTimeCode timecode);
|
||||
};
|
||||
|
||||
|
|
|
@ -135,13 +135,11 @@ void USDGenericMeshWriter::write_custom_data(const Object *obj,
|
|||
|
||||
attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) {
|
||||
/* Skipping "internal" Blender properties. Skipping
|
||||
* material_index as it's dealt with elsewhere. Skipping
|
||||
* edge domain because USD doesn't have a good
|
||||
* conversion for them. */
|
||||
/* Skip "internal" Blender properties and attributes processed elsewhere.
|
||||
* Skip edge domain because USD doesn't have a good conversion for them. */
|
||||
if (attribute_id.name()[0] == '.' || attribute_id.is_anonymous() ||
|
||||
meta_data.domain == bke::AttrDomain::Edge ||
|
||||
ELEM(attribute_id.name(), "position", "material_index"))
|
||||
ELEM(attribute_id.name(), "position", "material_index", "velocity"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ struct USDExportParams {
|
|||
|
||||
/** Communication structure between the wmJob management code and the worker code. Currently used
|
||||
* to generate safely reports from the worker thread. */
|
||||
wmJobWorkerStatus *worker_status;
|
||||
wmJobWorkerStatus *worker_status = nullptr;
|
||||
};
|
||||
|
||||
struct USDImportParams {
|
||||
|
|
|
@ -774,7 +774,7 @@ enum {
|
|||
* - RESET_NEVER: these flags are 'status' ones, and never actually need any reset (except on
|
||||
* initialization during .blend file reading).
|
||||
*
|
||||
* \note: These tags are purely runtime, so changing there value is not an issue. When adding new
|
||||
* \note These tags are purely runtime, so changing there value is not an issue. When adding new
|
||||
* tags, please put them in the relevant category and always keep their values strictly increasing.
|
||||
*/
|
||||
enum {
|
||||
|
@ -906,7 +906,7 @@ enum {
|
|||
* ID is being re-used from the old Main (instead of read from memfile), during memfile undo
|
||||
* processing, because it was detected as unchanged.
|
||||
*
|
||||
* \note: Also means that such ID does not need to be lib-linked during undo readfile process.
|
||||
* \note Also means that such ID does not need to be lib-linked during undo readfile process.
|
||||
*
|
||||
* RESET_AFTER_USE
|
||||
*/
|
||||
|
@ -915,7 +915,7 @@ enum {
|
|||
* ID is being re-used from the old Main (instead of read from memfile), during memfile undo
|
||||
* processing, because it is a 'NO_UNDO' type of ID.
|
||||
*
|
||||
* \note: Also means that such ID does not need to be lib-linked during undo readfile process. It
|
||||
* \note Also means that such ID does not need to be lib-linked during undo readfile process. It
|
||||
* does need to be relinked in a different way however, doing a `session_uid`-based lookup into
|
||||
* the newly read main database.
|
||||
*
|
||||
|
|
|
@ -210,7 +210,7 @@ typedef struct bNodeTreeInterfacePanel {
|
|||
|
||||
/**
|
||||
* Apply a function to every item in the panel, including child panels.
|
||||
* \note: The items are visited in drawing order from top to bottom.
|
||||
* \note The items are visited in drawing order from top to bottom.
|
||||
*
|
||||
* \param fn: Function to execute for each item, iterations stops if false is returned.
|
||||
* \param include_self: Include the panel itself in the iteration.
|
||||
|
@ -400,7 +400,7 @@ typedef struct bNodeTreeInterface {
|
|||
|
||||
/**
|
||||
* Apply a function to every item in the interface.
|
||||
* \note: The items are visited in drawing order from top to bottom.
|
||||
* \note The items are visited in drawing order from top to bottom.
|
||||
*
|
||||
* \param fn: Function to execute for each item, iterations stops if false is returned.
|
||||
* \param include_root: Include the root panel in the iteration.
|
||||
|
@ -412,7 +412,7 @@ typedef struct bNodeTreeInterface {
|
|||
}
|
||||
/**
|
||||
* Apply a function to every item in the interface.
|
||||
* \note: The items are visited in drawing order from top to bottom.
|
||||
* \note The items are visited in drawing order from top to bottom.
|
||||
*
|
||||
* \param fn: Function to execute for each item, iterations stops if false is returned.
|
||||
* \param include_root: Include the root panel in the iteration.
|
||||
|
|
|
@ -2859,7 +2859,7 @@ typedef enum RaytraceEEVEE_DenoiseStages {
|
|||
} RaytraceEEVEE_DenoiseStages;
|
||||
|
||||
typedef enum RaytraceEEVEE_Method {
|
||||
/* NOTE: Each method contains the previos one. */
|
||||
/* NOTE: Each method contains the previous one. */
|
||||
RAYTRACE_EEVEE_METHOD_PROBE = 0,
|
||||
RAYTRACE_EEVEE_METHOD_SCREEN = 1,
|
||||
/* TODO(fclem): Hardware ray-tracing. */
|
||||
|
|
|
@ -680,14 +680,14 @@ enum {
|
|||
* Unlike #OP_IS_REPEAT the selection (and context generally) may be different each time.
|
||||
* See #60777 for an example of when this is needed.
|
||||
*/
|
||||
OP_IS_REPEAT_LAST = (1 << 1),
|
||||
OP_IS_REPEAT_LAST = (1 << 2),
|
||||
|
||||
/** When the cursor is grabbed */
|
||||
OP_IS_MODAL_GRAB_CURSOR = (1 << 2),
|
||||
OP_IS_MODAL_GRAB_CURSOR = (1 << 3),
|
||||
|
||||
/**
|
||||
* Allow modal operators to have the region under the cursor for their context
|
||||
* (the region-type is maintained to prevent errors).
|
||||
*/
|
||||
OP_IS_MODAL_CURSOR_REGION = (1 << 3),
|
||||
OP_IS_MODAL_CURSOR_REGION = (1 << 4),
|
||||
};
|
||||
|
|
|
@ -84,7 +84,7 @@ enum PropertyUnit {
|
|||
PROP_UNIT_CAMERA = (10 << 16), /* mm */
|
||||
PROP_UNIT_POWER = (11 << 16), /* W */
|
||||
PROP_UNIT_TEMPERATURE = (12 << 16), /* C */
|
||||
PROP_UNIT_WAVELENGTH = (13 << 16), /* nm (independent of scene) */
|
||||
PROP_UNIT_WAVELENGTH = (13 << 16), /* `nm` (independent of scene). */
|
||||
};
|
||||
ENUM_OPERATORS(PropertyUnit, PROP_UNIT_TEMPERATURE)
|
||||
|
||||
|
|
|
@ -160,10 +160,10 @@ struct PropertyRNAOrID {
|
|||
*/
|
||||
bool is_idprop;
|
||||
/**
|
||||
* Whether this property is defined as a RNA one, but uses an IDProperty to store its value (aka
|
||||
* python-defined runtine RNA properties).
|
||||
* Whether this property is defined as a RNA one, but uses an #IDProperty to store its value
|
||||
* (aka Python-defined runtime RNA properties).
|
||||
*
|
||||
* \note: In that case, the IDProperty itself may very well not exist (yet), when it has never
|
||||
* \note In that case, the IDProperty itself may very well not exist (yet), when it has never
|
||||
* been set.
|
||||
*
|
||||
* \note Mutually exclusive with #is_idprop.
|
||||
|
|
|
@ -958,7 +958,7 @@ void RNA_def_material(BlenderRNA *brna)
|
|||
"Additionally helps rejecting probes inside the object to avoid light leaks");
|
||||
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
|
||||
|
||||
/* TODO(fclem): Should be renamed to use_raytraced_refraction. */
|
||||
/* TODO(fclem): Should be renamed to use_raytraced_transmission. */
|
||||
prop = RNA_def_property(srna, "use_screen_refraction", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "blend_flag", MA_BL_SS_REFRACTION);
|
||||
RNA_def_property_ui_text(
|
||||
|
|
|
@ -4331,6 +4331,8 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
|
|||
RNA_def_property_string_sdna(prop, nullptr, "filepath");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "File Path", "The path to the preset loaded into this theme (if any)");
|
||||
/* Don't store in presets. */
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
prop = RNA_def_property(srna, "theme_area", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "active_theme_area");
|
||||
|
|
|
@ -106,7 +106,7 @@ static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphCont
|
|||
/**
|
||||
* Rearrange curve buffers by moving points from the start to the back of each stroke.
|
||||
* \note This is an optional feature. The offset is determine by the closest point to an object.
|
||||
* \param curve_offsets Offset of each curve, indicating the point that becomes the new start.
|
||||
* \param curve_offsets: Offset of each curve, indicating the point that becomes the new start.
|
||||
*/
|
||||
static bke::CurvesGeometry reorder_cyclic_curve_points(const bke::CurvesGeometry &src_curves,
|
||||
const IndexMask &curve_selection,
|
||||
|
|
|
@ -1146,13 +1146,17 @@ static void points_in_planes_fn(const float co[3], int i, int j, int k, void *us
|
|||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
M_Geometry_points_in_planes_doc,
|
||||
".. function:: points_in_planes(planes)\n"
|
||||
".. function:: points_in_planes(planes, epsilon_coplanar=1e-4f, epsilon_isect=1e-6f)\n"
|
||||
"\n"
|
||||
" Returns a list of points inside all planes given and a list of index values for "
|
||||
"the planes used.\n"
|
||||
"\n"
|
||||
" :arg planes: List of planes (4D vectors).\n"
|
||||
" :type planes: list of :class:`mathutils.Vector`\n"
|
||||
" :arg epsilon_coplanar: Epsilon value for interpreting plane pairs as co-plannar.\n"
|
||||
" :type epsilon_coplanar: float\n"
|
||||
" :arg epsilon_isect: Epsilon value for intersection.\n"
|
||||
" :type epsilon_isect: float\n"
|
||||
" :return: two lists, once containing the vertices inside the planes, another "
|
||||
"containing the plane indices used\n"
|
||||
" :rtype: pair of lists\n");
|
||||
|
@ -1160,9 +1164,11 @@ static PyObject *M_Geometry_points_in_planes(PyObject * /*self*/, PyObject *args
|
|||
{
|
||||
PyObject *py_planes;
|
||||
float(*planes)[4];
|
||||
float eps_coplanar = 1e-4f;
|
||||
float eps_isect = 1e-6f;
|
||||
uint planes_len;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O:points_in_planes", &py_planes)) {
|
||||
if (!PyArg_ParseTuple(args, "O|ff:points_in_planes", &py_planes, &eps_coplanar, &eps_isect)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1183,9 +1189,6 @@ static PyObject *M_Geometry_points_in_planes(PyObject * /*self*/, PyObject *args
|
|||
|
||||
memset(user_data.planes_used, 0, sizeof(char) * planes_len);
|
||||
|
||||
const float eps_coplanar = 1e-4f;
|
||||
const float eps_isect = 1e-6f;
|
||||
|
||||
const bool has_isect = isect_planes_v3_fn(
|
||||
planes, planes_len, eps_coplanar, eps_isect, points_in_planes_fn, &user_data);
|
||||
PyMem_Free(planes);
|
||||
|
|
|
@ -71,7 +71,7 @@ void SEQ_transform_offset_after_frame(Scene *scene,
|
|||
* Check if `seq` can be moved.
|
||||
* This function also checks `SeqTimelineChannel` flag.
|
||||
*/
|
||||
bool SEQ_transform_is_locked(ListBase *channels, Sequence *seq);
|
||||
bool SEQ_transform_is_locked(ListBase *channels, const Sequence *seq);
|
||||
|
||||
/* Image transformation. */
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ struct Sequence;
|
|||
struct StripElem;
|
||||
|
||||
void SEQ_sequence_base_unique_name_recursive(Scene *scene, ListBase *seqbasep, Sequence *seq);
|
||||
const char *SEQ_sequence_give_name(Sequence *seq);
|
||||
const char *SEQ_sequence_give_name(const Sequence *seq);
|
||||
ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, ListBase **channels, int *r_offset);
|
||||
const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame);
|
||||
/**
|
||||
|
|
|
@ -599,7 +599,7 @@ void SEQ_transform_offset_after_frame(Scene *scene,
|
|||
}
|
||||
}
|
||||
|
||||
bool SEQ_transform_is_locked(ListBase *channels, Sequence *seq)
|
||||
bool SEQ_transform_is_locked(ListBase *channels, const Sequence *seq)
|
||||
{
|
||||
const SeqTimelineChannel *channel = SEQ_channel_get_by_index(channels, seq->machine);
|
||||
return seq->flag & SEQ_LOCK ||
|
||||
|
|
|
@ -161,7 +161,7 @@ static const char *give_seqname_by_type(int type)
|
|||
}
|
||||
}
|
||||
|
||||
const char *SEQ_sequence_give_name(Sequence *seq)
|
||||
const char *SEQ_sequence_give_name(const Sequence *seq)
|
||||
{
|
||||
const char *name = give_seqname_by_type(seq->type);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue