WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
101 changed files with 1220 additions and 950 deletions
Showing only changes of commit cf2afed071 - Show all commits

View File

@ -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;
}

View File

@ -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),

View File

@ -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"

View File

@ -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):

View File

@ -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")

View File

@ -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.
*/

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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).
*/

View File

@ -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).
*/

View File

@ -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;
};

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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()

View File

@ -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.
*/

View File

@ -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, &region->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);

View File

@ -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);
}
}
/** \} */

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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];

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);
}

View File

@ -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.

View File

@ -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));

View File

@ -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",

View File

@ -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");

View File

@ -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, &center, &half_extent);

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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;

View File

@ -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. */

View File

@ -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);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -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) {

View File

@ -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);

View File

@ -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];

View File

@ -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(&params, 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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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 {

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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);
}
/** \} */

View File

@ -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;
}

View File

@ -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));

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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,

View File

@ -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,

View File

@ -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());

View File

@ -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));
}
}

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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 {

View File

@ -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.
*

View File

@ -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.

View File

@ -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. */

View File

@ -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),
};

View File

@ -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)

View File

@ -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.

View File

@ -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(

View File

@ -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");

View File

@ -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,

View File

@ -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);

View File

@ -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. */

View File

@ -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);
/**

View File

@ -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 ||

View File

@ -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