UI: Asset Shelf (Experimental Feature) #104831
|
@ -188,6 +188,23 @@ using uchar = unsigned char;
|
|||
using sycl::half;
|
||||
|
||||
/* math functions */
|
||||
ccl_device_forceinline float __uint_as_float(uint x)
|
||||
{
|
||||
return sycl::bit_cast<float>(x);
|
||||
}
|
||||
ccl_device_forceinline uint __float_as_uint(float x)
|
||||
{
|
||||
return sycl::bit_cast<uint>(x);
|
||||
}
|
||||
ccl_device_forceinline float __int_as_float(int x)
|
||||
{
|
||||
return sycl::bit_cast<float>(x);
|
||||
}
|
||||
ccl_device_forceinline int __float_as_int(float x)
|
||||
{
|
||||
return sycl::bit_cast<int>(x);
|
||||
}
|
||||
|
||||
#define fabsf(x) sycl::fabs((x))
|
||||
#define copysignf(x, y) sycl::copysign((x), (y))
|
||||
#define asinf(x) sycl::asin((x))
|
||||
|
|
|
@ -101,7 +101,6 @@ using std::isfinite;
|
|||
using std::isnan;
|
||||
using std::sqrt;
|
||||
# else
|
||||
using sycl::sqrt;
|
||||
# define isfinite(x) sycl::isfinite((x))
|
||||
# define isnan(x) sycl::isnan((x))
|
||||
# endif
|
||||
|
@ -207,7 +206,7 @@ ccl_device_inline float max4(float a, float b, float c, float d)
|
|||
return max(max(a, b), max(c, d));
|
||||
}
|
||||
|
||||
#if !defined(__KERNEL_METAL__)
|
||||
#if !defined(__KERNEL_METAL__) && !defined(__KERNEL_ONEAPI__)
|
||||
/* Int/Float conversion */
|
||||
|
||||
ccl_device_inline int as_int(uint i)
|
||||
|
@ -795,7 +794,10 @@ ccl_device float bits_to_01(uint bits)
|
|||
|
||||
#if !defined(__KERNEL_GPU__)
|
||||
# if defined(__GNUC__)
|
||||
# define popcount(x) __builtin_popcount(x)
|
||||
ccl_device_inline uint popcount(uint x)
|
||||
{
|
||||
return __builtin_popcount(x);
|
||||
}
|
||||
# else
|
||||
ccl_device_inline uint popcount(uint x)
|
||||
{
|
||||
|
|
|
@ -892,29 +892,6 @@ void GHOST_ContextCGL::initClear()
|
|||
glClearColor(0.294, 0.294, 0.294, 0.000);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0.000, 0.000, 0.000, 0.000);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#if WITH_METAL
|
||||
// TODO (mg_gpusw_apple) this path is never taken, this is legacy left from inital integration
|
||||
// of metal and gl, the whole file should be cleaned up and stripped of the legacy path
|
||||
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
|
||||
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
{
|
||||
auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
|
||||
attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
|
||||
attachment.loadAction = MTLLoadActionClear;
|
||||
attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000);
|
||||
attachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
|
||||
// encoding
|
||||
{
|
||||
id<MTLRenderCommandEncoder> enc = [cmdBuffer
|
||||
renderCommandEncoderWithDescriptor:passDescriptor];
|
||||
[enc endEncoding];
|
||||
}
|
||||
[cmdBuffer commit];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
struct bContext;
|
||||
struct uiBlock;
|
||||
struct uiButViewItem;
|
||||
struct uiLayout;
|
||||
struct uiViewItemHandle;
|
||||
struct ViewLink;
|
||||
|
@ -91,6 +92,8 @@ class AbstractView {
|
|||
*/
|
||||
virtual bool begin_filtering(const bContext &C) const;
|
||||
|
||||
virtual void draw_overlays(const ARegion ®ion) const;
|
||||
|
||||
/**
|
||||
* Makes \a item valid for display in this view. Behavior is undefined for items not registered
|
||||
* with this.
|
||||
|
@ -139,6 +142,8 @@ class AbstractViewItem {
|
|||
* If this wasn't done, the behavior of items is undefined.
|
||||
*/
|
||||
AbstractView *view_ = nullptr;
|
||||
/** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
|
||||
uiButViewItem *view_item_but_ = nullptr;
|
||||
bool is_activatable_ = true;
|
||||
bool is_interactive_ = true;
|
||||
bool is_active_ = false;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
struct bContext;
|
||||
struct uiBlock;
|
||||
struct uiBut;
|
||||
struct uiButViewItem;
|
||||
struct uiLayout;
|
||||
|
||||
namespace blender::ui {
|
||||
|
@ -119,6 +118,8 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
|||
public:
|
||||
virtual ~AbstractTreeView() = default;
|
||||
|
||||
void draw_overlays(const ARegion ®ion) const override;
|
||||
|
||||
void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
|
||||
|
||||
/** Visual feature: Define a number of item rows the view will always show at minimum. If there
|
||||
|
@ -143,6 +144,11 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
|||
* the actual state changes are done in a delayed manner through this function.
|
||||
*/
|
||||
void change_state_delayed();
|
||||
void draw_hierarchy_lines(const ARegion ®ion) const;
|
||||
void draw_hierarchy_lines_recursive(const ARegion ®ion,
|
||||
const TreeViewOrItem &parent,
|
||||
uint pos) const;
|
||||
AbstractTreeViewItem *find_last_visible_descendant(const AbstractTreeViewItem &parent) const;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
@ -170,8 +176,6 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
|
|||
protected:
|
||||
/** This label is used as the default way to identifying an item within its parent. */
|
||||
std::string label_{};
|
||||
/** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
|
||||
uiButViewItem *view_item_but_ = nullptr;
|
||||
|
||||
public:
|
||||
virtual ~AbstractTreeViewItem() = default;
|
||||
|
@ -247,7 +251,7 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
|
|||
|
||||
void ensure_parents_uncollapsed();
|
||||
|
||||
uiButViewItem *view_item_button();
|
||||
uiButViewItem *view_item_button() const;
|
||||
|
||||
private:
|
||||
static void tree_row_click_fn(struct bContext *, void *, void *);
|
||||
|
@ -258,6 +262,7 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
|
|||
void change_state_delayed();
|
||||
|
||||
void add_treerow_button(uiBlock &block);
|
||||
int indent_width() const;
|
||||
void add_indent(uiLayout &row) const;
|
||||
void add_collapse_chevron(uiBlock &block) const;
|
||||
void add_rename_button(uiLayout &row);
|
||||
|
|
|
@ -80,10 +80,6 @@
|
|||
using blender::Vector;
|
||||
|
||||
/* prototypes. */
|
||||
static void ui_but_to_pixelrect(rcti *rect,
|
||||
const ARegion *region,
|
||||
uiBlock *block,
|
||||
const uiBut *but);
|
||||
static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p);
|
||||
static void ui_def_but_rna__panel_type(bContext * /*C*/, uiLayout *layout, void *but_p);
|
||||
static void ui_def_but_rna__menu_type(bContext * /*C*/, uiLayout *layout, void *but_p);
|
||||
|
@ -912,6 +908,7 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
|
|||
case UI_BTYPE_VIEW_ITEM: {
|
||||
uiButViewItem *view_item_oldbut = (uiButViewItem *)oldbut;
|
||||
uiButViewItem *view_item_newbut = (uiButViewItem *)but;
|
||||
ui_view_item_swap_button_pointers(view_item_newbut->view_item, view_item_oldbut->view_item);
|
||||
std::swap(view_item_newbut->view_item, view_item_oldbut->view_item);
|
||||
break;
|
||||
}
|
||||
|
@ -2069,11 +2066,7 @@ void ui_fontscale(float *points, float aspect)
|
|||
*points /= aspect;
|
||||
}
|
||||
|
||||
/* Project button or block (but==nullptr) to pixels in region-space. */
|
||||
static void ui_but_to_pixelrect(rcti *rect,
|
||||
const ARegion *region,
|
||||
uiBlock *block,
|
||||
const uiBut *but)
|
||||
void ui_but_to_pixelrect(rcti *rect, const ARegion *region, const uiBlock *block, const uiBut *but)
|
||||
{
|
||||
rctf rectf;
|
||||
|
||||
|
@ -2169,6 +2162,8 @@ void UI_block_draw(const bContext *C, uiBlock *block)
|
|||
UI_icon_draw_cache_end();
|
||||
BLF_batch_draw_end();
|
||||
|
||||
ui_block_views_draw_overlays(region, block);
|
||||
|
||||
/* restore matrix */
|
||||
GPU_matrix_pop_projection();
|
||||
GPU_matrix_pop();
|
||||
|
|
|
@ -600,6 +600,12 @@ struct uiSafetyRct {
|
|||
|
||||
void ui_fontscale(float *points, float aspect);
|
||||
|
||||
/** Project button or block (but==nullptr) to pixels in region-space. */
|
||||
void ui_but_to_pixelrect(rcti *rect,
|
||||
const ARegion *region,
|
||||
const uiBlock *block,
|
||||
const uiBut *but);
|
||||
|
||||
void ui_block_to_region_fl(const ARegion *region, const uiBlock *block, float *r_x, float *r_y);
|
||||
void ui_block_to_window_fl(const ARegion *region, const uiBlock *block, float *x, float *y);
|
||||
void ui_block_to_window(const ARegion *region, const uiBlock *block, int *x, int *y);
|
||||
|
@ -1461,12 +1467,17 @@ void ui_interface_tag_script_reload_queries();
|
|||
void ui_block_free_views(uiBlock *block);
|
||||
void ui_block_views_bounds_calc(const uiBlock *block);
|
||||
void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params);
|
||||
void ui_block_views_draw_overlays(const ARegion *region, const uiBlock *block);
|
||||
uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
|
||||
const uiViewHandle *new_view);
|
||||
|
||||
uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
|
||||
const uiBlock *new_block, const uiViewItemHandle *new_item_handle);
|
||||
|
||||
/* abstract_view_item.cc */
|
||||
|
||||
void ui_view_item_swap_button_pointers(uiViewItemHandle *a_handle, uiViewItemHandle *b_handle);
|
||||
|
||||
/* interface_templates.cc */
|
||||
|
||||
uiListType *UI_UL_cache_file_layers();
|
||||
|
|
|
@ -83,6 +83,11 @@ bool AbstractView::begin_filtering(const bContext & /*C*/) const
|
|||
return false;
|
||||
}
|
||||
|
||||
void AbstractView::draw_overlays(const ARegion & /*region*/) const
|
||||
{
|
||||
/* Nothing by default. */
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
|
|
@ -286,6 +286,11 @@ class ViewItemAPIWrapper {
|
|||
return a.matches(b);
|
||||
}
|
||||
|
||||
static void swap_button_pointers(AbstractViewItem &a, AbstractViewItem &b)
|
||||
{
|
||||
std::swap(a.view_item_but_, b.view_item_but_);
|
||||
}
|
||||
|
||||
static bool can_rename(const AbstractViewItem &item)
|
||||
{
|
||||
const AbstractView &view = item.get_view();
|
||||
|
@ -340,6 +345,16 @@ bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHand
|
|||
return ViewItemAPIWrapper::matches(a, b);
|
||||
}
|
||||
|
||||
void ui_view_item_swap_button_pointers(uiViewItemHandle *a_handle, uiViewItemHandle *b_handle)
|
||||
{
|
||||
if (!a_handle || !b_handle) {
|
||||
return;
|
||||
}
|
||||
AbstractViewItem &a = reinterpret_cast<AbstractViewItem &>(*a_handle);
|
||||
AbstractViewItem &b = reinterpret_cast<AbstractViewItem &>(*b_handle);
|
||||
ViewItemAPIWrapper::swap_button_pointers(a, b);
|
||||
}
|
||||
|
||||
bool UI_view_item_can_rename(const uiViewItemHandle *item_handle)
|
||||
{
|
||||
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
|
||||
|
|
|
@ -142,6 +142,13 @@ void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *l
|
|||
}
|
||||
}
|
||||
|
||||
void ui_block_views_draw_overlays(const ARegion *region, const uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
|
||||
view_link->view->draw_overlays(*region);
|
||||
}
|
||||
}
|
||||
|
||||
uiViewHandle *UI_region_view_find_at(const ARegion *region, const int xy[2], const int pad)
|
||||
{
|
||||
/* NOTE: Similar to #ui_but_find_mouse_over_ex(). */
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "GPU_immediate.h"
|
||||
|
||||
#include "interface_intern.hh"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
@ -81,6 +83,92 @@ void AbstractTreeView::set_min_rows(int min_rows)
|
|||
min_rows_ = min_rows;
|
||||
}
|
||||
|
||||
AbstractTreeViewItem *AbstractTreeView::find_last_visible_descendant(
|
||||
const AbstractTreeViewItem &parent) const
|
||||
{
|
||||
if (parent.is_collapsed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AbstractTreeViewItem *last_descendant = parent.children_.last().get();
|
||||
while (!last_descendant->children_.is_empty() && !last_descendant->is_collapsed()) {
|
||||
last_descendant = last_descendant->children_.last().get();
|
||||
}
|
||||
|
||||
return last_descendant;
|
||||
}
|
||||
|
||||
void AbstractTreeView::draw_hierarchy_lines_recursive(const ARegion ®ion,
|
||||
const TreeViewOrItem &parent,
|
||||
const uint pos) const
|
||||
{
|
||||
for (const auto &item : parent.children_) {
|
||||
if (!item->is_collapsible() || item->is_collapsed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
draw_hierarchy_lines_recursive(region, *item, pos);
|
||||
|
||||
const AbstractTreeViewItem *first_descendant = item->children_.first().get();
|
||||
const AbstractTreeViewItem *last_descendant = find_last_visible_descendant(*item);
|
||||
if (!first_descendant->view_item_but_ || !last_descendant || !last_descendant->view_item_but_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const uiButViewItem &first_child_but = *first_descendant->view_item_button();
|
||||
const uiButViewItem &last_child_but = *last_descendant->view_item_button();
|
||||
|
||||
BLI_assert(first_child_but.block == last_child_but.block);
|
||||
const uiBlock *block = first_child_but.block;
|
||||
|
||||
rcti first_child_rect;
|
||||
ui_but_to_pixelrect(&first_child_rect, ®ion, block, &first_child_but);
|
||||
rcti last_child_rect;
|
||||
ui_but_to_pixelrect(&last_child_rect, ®ion, block, &last_child_but);
|
||||
|
||||
/* Small vertical padding. */
|
||||
const short line_padding = UI_UNIT_Y / 4.0f;
|
||||
const float x = first_child_rect.xmin + first_descendant->indent_width() -
|
||||
UI_ICON_SIZE * 0.5f + 2 * UI_SCALE_FAC;
|
||||
immBegin(GPU_PRIM_LINES, 2);
|
||||
immVertex2f(pos, x, first_child_rect.ymax - line_padding);
|
||||
immVertex2f(pos, x, last_child_rect.ymin + line_padding);
|
||||
immEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractTreeView::draw_hierarchy_lines(const ARegion ®ion) const
|
||||
{
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
uchar col[4];
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
|
||||
|
||||
float viewport_size[4];
|
||||
GPU_viewport_size_get_f(viewport_size);
|
||||
immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC);
|
||||
immUniform1i("colors_len", 0); /* "simple" mode */
|
||||
immUniform1f("dash_width", 8.0f);
|
||||
/* >= is 1.0 for un-dashed lines. */
|
||||
immUniform1f("udash_factor", 1.0f);
|
||||
UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col);
|
||||
col[3] = 255;
|
||||
immUniformColor4ubv(col);
|
||||
|
||||
GPU_line_width(1.0f);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
draw_hierarchy_lines_recursive(region, *this, pos);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
void AbstractTreeView::draw_overlays(const ARegion ®ion) const
|
||||
{
|
||||
draw_hierarchy_lines(region);
|
||||
}
|
||||
|
||||
void AbstractTreeView::update_children_from_old(const AbstractView &old_view)
|
||||
{
|
||||
const AbstractTreeView &old_tree_view = dynamic_cast<const AbstractTreeView &>(old_view);
|
||||
|
@ -162,14 +250,18 @@ void AbstractTreeViewItem::add_treerow_button(uiBlock &block)
|
|||
UI_but_func_set(view_item_but_, tree_row_click_fn, view_item_but_, nullptr);
|
||||
}
|
||||
|
||||
int AbstractTreeViewItem::indent_width() const
|
||||
{
|
||||
return count_parents() * UI_ICON_SIZE;
|
||||
}
|
||||
|
||||
void AbstractTreeViewItem::add_indent(uiLayout &row) const
|
||||
{
|
||||
uiBlock *block = uiLayoutGetBlock(&row);
|
||||
uiLayout *subrow = uiLayoutRow(&row, true);
|
||||
uiLayoutSetFixedSize(subrow, true);
|
||||
|
||||
const float indent_size = count_parents() * UI_ICON_SIZE;
|
||||
uiDefBut(block, UI_BTYPE_SEPR, 0, "", 0, 0, indent_size, 0, nullptr, 0.0, 0.0, 0, 0, "");
|
||||
uiDefBut(block, UI_BTYPE_SEPR, 0, "", 0, 0, indent_width(), 0, nullptr, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
/* Indent items without collapsing icon some more within their parent. Makes it clear that they
|
||||
* are actually nested and not just a row at the same level without a chevron. */
|
||||
|
@ -407,7 +499,7 @@ bool AbstractTreeViewItem::matches(const AbstractViewItem &other) const
|
|||
return true;
|
||||
}
|
||||
|
||||
uiButViewItem *AbstractTreeViewItem::view_item_button()
|
||||
uiButViewItem *AbstractTreeViewItem::view_item_button() const
|
||||
{
|
||||
return view_item_but_;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,14 @@ std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
|
|||
* this is not supported and will likely generate corrupted geometry.
|
||||
*
|
||||
* \param vert_dest_map_len: The number of non '-1' values in `vert_dest_map`. (not the size)
|
||||
* \param do_mix_vert_data: If true, the groups of vertices in the `vert_dest_map_len`, defined by
|
||||
* source vertices with the same target plus the target vertex, will have their custom data
|
||||
* interpolated into the resulting vertex. If false, only the custom data of the target vertex will
|
||||
* remain.
|
||||
*/
|
||||
Mesh *mesh_merge_verts(const Mesh &mesh, MutableSpan<int> vert_dest_map, int vert_dest_map_len);
|
||||
Mesh *mesh_merge_verts(const Mesh &mesh,
|
||||
MutableSpan<int> vert_dest_map,
|
||||
int vert_dest_map_len,
|
||||
const bool do_mix_vert_data);
|
||||
|
||||
} // namespace blender::geometry
|
||||
|
|
|
@ -87,6 +87,7 @@ struct WeldPoly {
|
|||
|
||||
struct WeldMesh {
|
||||
/* Group of vertices to be merged. */
|
||||
Array<int> vert_group_map; /* Maps the vertex group offset from the target vert index. */
|
||||
Array<int> vert_groups_offs;
|
||||
Array<int> vert_groups_buffer;
|
||||
|
||||
|
@ -356,14 +357,15 @@ static Vector<int> weld_vert_ctx_alloc_and_setup(MutableSpan<int> vert_dest_map,
|
|||
static void weld_vert_groups_setup(Span<int> wvert,
|
||||
Span<int> vert_dest_map,
|
||||
const int vert_kill_len,
|
||||
MutableSpan<int> r_vert_groups_map,
|
||||
Array<int> &r_vert_groups_map,
|
||||
Array<int> &r_vert_groups_buffer,
|
||||
Array<int> &r_vert_groups_offs)
|
||||
{
|
||||
r_vert_groups_map.reinitialize(vert_dest_map.size());
|
||||
r_vert_groups_map.fill(OUT_OF_CONTEXT);
|
||||
const int vert_groups_len = wvert.size() - vert_kill_len;
|
||||
|
||||
/* Add +1 to allow calculation of the length of the last group. */
|
||||
const int vert_groups_len = wvert.size() - vert_kill_len;
|
||||
r_vert_groups_offs.reinitialize(vert_groups_len + 1);
|
||||
r_vert_groups_offs.fill(0);
|
||||
|
||||
|
@ -1374,7 +1376,7 @@ static void weld_poly_find_doubles(const Span<int> corner_verts,
|
|||
static void weld_mesh_context_create(const Mesh &mesh,
|
||||
MutableSpan<int> vert_dest_map,
|
||||
const int vert_kill_len,
|
||||
MutableSpan<int> r_vert_group_map,
|
||||
const bool do_vert_group,
|
||||
WeldMesh *r_weld_mesh)
|
||||
{
|
||||
const Span<int2> edges = mesh.edges();
|
||||
|
@ -1417,12 +1419,14 @@ static void weld_mesh_context_create(const Mesh &mesh,
|
|||
edges.size(),
|
||||
r_weld_mesh);
|
||||
|
||||
weld_vert_groups_setup(wvert,
|
||||
vert_dest_map,
|
||||
vert_kill_len,
|
||||
r_vert_group_map,
|
||||
r_weld_mesh->vert_groups_buffer,
|
||||
r_weld_mesh->vert_groups_offs);
|
||||
if (do_vert_group) {
|
||||
weld_vert_groups_setup(wvert,
|
||||
vert_dest_map,
|
||||
vert_kill_len,
|
||||
r_weld_mesh->vert_group_map,
|
||||
r_weld_mesh->vert_groups_buffer,
|
||||
r_weld_mesh->vert_groups_offs);
|
||||
}
|
||||
|
||||
weld_edge_groups_setup(edges.size(),
|
||||
r_weld_mesh->edge_kill_len,
|
||||
|
@ -1545,7 +1549,8 @@ static void customdata_weld(
|
|||
|
||||
static Mesh *create_merged_mesh(const Mesh &mesh,
|
||||
MutableSpan<int> vert_dest_map,
|
||||
const int removed_vertex_count)
|
||||
const int removed_vertex_count,
|
||||
const bool do_mix_vert_data)
|
||||
{
|
||||
#ifdef USE_WELD_DEBUG_TIME
|
||||
SCOPED_TIMER(__func__);
|
||||
|
@ -1557,10 +1562,9 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
|
|||
const int totvert = mesh.totvert;
|
||||
const int totedge = mesh.totedge;
|
||||
|
||||
Array<int> vert_group_map(totvert);
|
||||
|
||||
WeldMesh weld_mesh;
|
||||
weld_mesh_context_create(mesh, vert_dest_map, removed_vertex_count, vert_group_map, &weld_mesh);
|
||||
weld_mesh_context_create(
|
||||
mesh, vert_dest_map, removed_vertex_count, do_mix_vert_data, &weld_mesh);
|
||||
|
||||
const int result_nverts = totvert - weld_mesh.vert_kill_len;
|
||||
const int result_nedges = totedge - weld_mesh.edge_kill_len;
|
||||
|
@ -1576,15 +1580,23 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
|
|||
|
||||
/* Vertices. */
|
||||
|
||||
/* Be careful when setting values to this array as it uses the same buffer as #vert_group_map.
|
||||
* This map will be used to adjust edges and loops to point to new vertex indices. */
|
||||
MutableSpan<int> vert_final_map = vert_group_map;
|
||||
MutableSpan<int> vert_final_map;
|
||||
Array<int> vert_final_map_local;
|
||||
if (!weld_mesh.vert_group_map.is_empty()) {
|
||||
/* Be careful when setting values to this array as it uses the same buffer as #vert_group_map.
|
||||
* This map will be used to adjust edges and loops to point to new vertex indices. */
|
||||
vert_final_map = weld_mesh.vert_group_map;
|
||||
}
|
||||
else {
|
||||
vert_final_map_local.reinitialize(totvert);
|
||||
vert_final_map = vert_final_map_local;
|
||||
}
|
||||
|
||||
int dest_index = 0;
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
int source_index = i;
|
||||
int count = 0;
|
||||
while (i < totvert && vert_group_map[i] == OUT_OF_CONTEXT) {
|
||||
while (i < totvert && vert_dest_map[i] == OUT_OF_CONTEXT) {
|
||||
vert_final_map[i] = dest_index + count;
|
||||
count++;
|
||||
i++;
|
||||
|
@ -1596,15 +1608,16 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
|
|||
if (i == totvert) {
|
||||
break;
|
||||
}
|
||||
if (vert_group_map[i] != ELEM_MERGED) {
|
||||
int *src_indices;
|
||||
int count;
|
||||
{
|
||||
int *wgroup = &weld_mesh.vert_groups_offs[vert_group_map[i]];
|
||||
src_indices = &weld_mesh.vert_groups_buffer[*wgroup];
|
||||
count = *(wgroup + 1) - *wgroup;
|
||||
if (vert_dest_map[i] == i) {
|
||||
if (do_mix_vert_data) {
|
||||
int *group_offs = &weld_mesh.vert_groups_offs[weld_mesh.vert_group_map[i]];
|
||||
int *src_indices = &weld_mesh.vert_groups_buffer[*group_offs];
|
||||
int count = *(group_offs + 1) - *group_offs;
|
||||
customdata_weld(&mesh.vdata, &result->vdata, src_indices, count, dest_index);
|
||||
}
|
||||
else {
|
||||
CustomData_copy_data(&mesh.vdata, &result->vdata, i, dest_index, 1);
|
||||
}
|
||||
customdata_weld(&mesh.vdata, &result->vdata, src_indices, count, dest_index);
|
||||
vert_final_map[i] = dest_index;
|
||||
dest_index++;
|
||||
}
|
||||
|
@ -1770,7 +1783,7 @@ std::optional<Mesh *> mesh_merge_by_distance_all(const Mesh &mesh,
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
return create_merged_mesh(mesh, vert_dest_map, vert_kill_len);
|
||||
return create_merged_mesh(mesh, vert_dest_map, vert_kill_len, true);
|
||||
}
|
||||
|
||||
struct WeldVertexCluster {
|
||||
|
@ -1869,12 +1882,15 @@ std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
|
|||
}
|
||||
}
|
||||
|
||||
return create_merged_mesh(mesh, vert_dest_map, vert_kill_len);
|
||||
return create_merged_mesh(mesh, vert_dest_map, vert_kill_len, true);
|
||||
}
|
||||
|
||||
Mesh *mesh_merge_verts(const Mesh &mesh, MutableSpan<int> vert_dest_map, int vert_dest_map_len)
|
||||
Mesh *mesh_merge_verts(const Mesh &mesh,
|
||||
MutableSpan<int> vert_dest_map,
|
||||
int vert_dest_map_len,
|
||||
const bool do_mix_vert_data)
|
||||
{
|
||||
return create_merged_mesh(mesh, vert_dest_map, vert_dest_map_len);
|
||||
return create_merged_mesh(mesh, vert_dest_map, vert_dest_map_len, do_mix_vert_data);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -826,7 +826,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
|||
if (tot_doubles > 0) {
|
||||
Mesh *tmp = result;
|
||||
result = geometry::mesh_merge_verts(
|
||||
*tmp, MutableSpan<int>{full_doubles_map, result->totvert}, tot_doubles);
|
||||
*tmp, MutableSpan<int>{full_doubles_map, result->totvert}, tot_doubles, false);
|
||||
BKE_id_free(nullptr, tmp);
|
||||
}
|
||||
MEM_freeN(full_doubles_map);
|
||||
|
|
|
@ -87,7 +87,7 @@ static Mesh *mirror_apply_on_axis(MirrorModifierData *mmd,
|
|||
if (vert_merge_map_len) {
|
||||
Mesh *tmp = result;
|
||||
result = geometry::mesh_merge_verts(
|
||||
*tmp, MutableSpan<int>{vert_merge_map, result->totvert}, vert_merge_map_len);
|
||||
*tmp, MutableSpan<int>{vert_merge_map, result->totvert}, vert_merge_map_len, false);
|
||||
BKE_id_free(nullptr, tmp);
|
||||
}
|
||||
MEM_freeN(vert_merge_map);
|
||||
|
|
|
@ -180,7 +180,8 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result,
|
|||
* Therefore the duplicate polygon test can be skipped. */
|
||||
result = geometry::mesh_merge_verts(*tmp,
|
||||
MutableSpan<int>{full_doubles_map, result->totvert},
|
||||
int(tot_doubles * (step_tot - 1)));
|
||||
int(tot_doubles * (step_tot - 1)),
|
||||
false);
|
||||
|
||||
BKE_id_free(nullptr, tmp);
|
||||
MEM_freeN(full_doubles_map);
|
||||
|
|
Loading…
Reference in New Issue