Blender V4.3
bmo_inset.cc File Reference
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
#include "BLI_math_vector.h"
#include "BLI_memarena.h"
#include "BLI_utildefines_stack.h"
#include "BKE_customdata.hh"
#include "bmesh.hh"
#include "intern/bmesh_operators_private.hh"

Go to the source code of this file.

Classes

struct  InterpFace
 
struct  SplitEdgeInfo
 

Macros

#define USE_LOOP_CUSTOMDATA_MERGE
 
#define ELE_NEW   1
 
#define VERT_ORIG_STORE(_v)
 
#define VERT_ORIG_GET(_v)   (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)
 
#define VERT_ORIG_REMOVE(_v)   BLI_ghash_remove(vert_coords, (_v), nullptr, nullptr)
 

Functions

Generic Face Interpolation

Use for both kinds of inset.

Interpolation, this is more complex for regions since we're not creating new faces and throwing away old ones, so instead, store face data needed for interpolation.

Note
This uses CustomData functions in quite a low-level way which should be avoided, but in this case its hard to do without storing a duplicate mesh.
static void bm_interp_face_store (InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
 
static void bm_interp_face_free (InterpFace *iface, BMesh *bm)
 
static void bm_loop_customdata_merge (BMesh *bm, BMEdge *e_connect, BMLoop *l_a_outer, BMLoop *l_b_outer, BMLoop *l_a_inner, BMLoop *l_b_inner)
 
Inset Individual

Each face has a smaller face created inside it (simple logic).

static void bmo_face_inset_individual (BMesh *bm, BMFace *f, MemArena *interp_arena, const float thickness, const float depth, const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate)
 
void bmo_inset_individual_exec (BMesh *bm, BMOperator *op)
 
Inset Region

The boundary between tagged and untagged faces is inset (more involved logic).

static BMLoopbm_edge_is_mixed_face_tag (BMLoop *l)
 
static float bm_edge_info_average_length (BMVert *v, SplitEdgeInfo *edge_info)
 
static float bm_edge_info_average_length_fallback (BMVert *v_lookup, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
 
static float bm_edge_info_average_length_with_fallback (BMVert *v, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
 
void bmo_inset_region_exec (BMesh *bm, BMOperator *op)
 

Detailed Description

Inset face regions. Inset individual faces.

Definition in file bmo_inset.cc.

Macro Definition Documentation

◆ ELE_NEW

#define ELE_NEW   1

◆ USE_LOOP_CUSTOMDATA_MERGE

#define USE_LOOP_CUSTOMDATA_MERGE

Definition at line 28 of file bmo_inset.cc.

◆ VERT_ORIG_GET

#define VERT_ORIG_GET ( _v)    (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)

Referenced by bmo_inset_region_exec().

◆ VERT_ORIG_REMOVE

#define VERT_ORIG_REMOVE ( _v)    BLI_ghash_remove(vert_coords, (_v), nullptr, nullptr)

Referenced by bmo_inset_region_exec().

◆ VERT_ORIG_STORE

#define VERT_ORIG_STORE ( _v)
Value:
{ \
float *_co = static_cast<float *>(BLI_memarena_alloc(vert_coords_orig, sizeof(float[3]))); \
copy_v3_v3(_co, (_v)->co); \
BLI_ghash_insert(vert_coords, _v, _co); \
} \
(void)0
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)

Referenced by bmo_inset_region_exec().

Function Documentation

◆ bm_edge_info_average_length()

static float bm_edge_info_average_length ( BMVert * v,
SplitEdgeInfo * edge_info )
static

◆ bm_edge_info_average_length_fallback()

static float bm_edge_info_average_length_fallback ( BMVert * v_lookup,
SplitEdgeInfo * edge_info,
BMesh * bm,
void ** vert_lengths_p )
static

Fill in any vertices that are in the inset region but not connected to an edge being inset.

This is lazily initialized since it's a relatively expensive operation, and it's not needed in cases where all vertices being inset are connected to edges that are part of the inset.

Note
This only runs under the following conditions:
  • "depth" is non-zero.
  • "use_relative_offset" is enabled.
  • There are interior vertices which aren't used by an edge being inset.

Use to fill in length accumulated values based on the topological distance to vertices at the inset boundaries.

Unlike edge-lengths of vertices immediately around the vertex, this ensures the values are more evenly distributed.

The number of connected vertices we have added to length_accum. The sign of the value is used to avoid mixing current and previous passes.

  • Zero: Uninitialized, can be added to vert_stack.
  • Positive: Part of the current pass, length_accum has not yet been divided.
  • Minus One: Part of previous passes, length_accum value has been divided.

Definition at line 543 of file bmo_inset.cc.

References BLI_assert, bm, bm_edge_info_average_length(), BM_edge_other_vert(), BM_EDGES_OF_MESH, BM_EDGES_OF_VERT, BM_elem_flag_test, BM_elem_index_get, BM_ELEM_TAG, BM_ITER_ELEM, BM_ITER_MESH, BM_mesh_elem_index_ensure(), BM_VERT, count, e, float, MEM_callocN, MEM_freeN(), MEM_mallocN, STACK_DECLARE, STACK_INIT, STACK_PUSH, STACK_REMOVE, STACK_SIZE, BMesh::totvert, UNLIKELY, and v.

Referenced by bm_edge_info_average_length_with_fallback().

◆ bm_edge_info_average_length_with_fallback()

static float bm_edge_info_average_length_with_fallback ( BMVert * v,
SplitEdgeInfo * edge_info,
BMesh * bm,
void ** vert_lengths_p )
static

◆ bm_edge_is_mixed_face_tag()

static BMLoop * bm_edge_is_mixed_face_tag ( BMLoop * l)
static

Return the tag loop where there is:

  • only 1 tagged face attached to this edge.
  • 1 or more untagged faces.
Note
this function looks to be expensive but in most cases it will only do 2 iterations.

Definition at line 479 of file bmo_inset.cc.

References BM_elem_flag_test, BM_ELEM_TAG, BMLoop::f, l, LIKELY, and BMLoop::radial_next.

Referenced by bmo_inset_region_exec().

◆ bm_interp_face_free()

static void bm_interp_face_free ( InterpFace * iface,
BMesh * bm )
static

◆ bm_interp_face_store()

◆ bm_loop_customdata_merge()

static void bm_loop_customdata_merge ( BMesh * bm,
BMEdge * e_connect,
BMLoop * l_a_outer,
BMLoop * l_b_outer,
BMLoop * l_a_inner,
BMLoop * l_b_inner )
static

This function merges loop customdata (UVs) where interpolating the values across the face causes values to diverge.

Check for diverged values at the vert shared by l_a_inner & l_b_inner.

 -----------------------+
          l_a_outer--> /|<--l_b_outer
                      / |
     (face a)        /  |
                    / <--e_connect
                   /    |
e_a  l_a_inner--> / <--l_b_inner
-----------------+      |
                /|      |
l_a/b_inner_inset| (face b)
              /  |      |
             /   |e_b   |
 (inset face(s)) |      |
           /     |      |

Definition at line 107 of file bmo_inset.cc.

References BLI_assert, bm, BM_edge_in_face(), BM_edge_other_loop(), BM_ELEM_CD_GET_VOID_P, BM_elem_flag_test, BM_ELEM_TAG, BM_ITER_ELEM, BM_LOOPS_OF_VERT, CDT_MIX_MIX, CustomData_data_copy_value(), CustomData_data_equals(), CustomData_data_mix_value(), CustomData_layer_has_math(), BMLoop::e, ELEM, BMLoop::f, CustomData::layers, BMesh::ldata, BMLoop::next, CustomDataLayer::offset, BMLoop::prev, CustomData::totlayer, CustomDataLayer::type, and BMLoop::v.

Referenced by bmo_inset_region_exec().

◆ bmo_face_inset_individual()

◆ bmo_inset_individual_exec()

void bmo_inset_individual_exec ( BMesh * bm,
BMOperator * op )

Individual Face Inset. Find all tagged faces (f), duplicate edges around faces, inset verts of created edges, create new faces between old and new edges, fill face between connected new edges, kill old face (f).

Definition at line 410 of file bmo_inset.cc.

References BLI_memarena_clear(), BLI_memarena_free(), BLI_memarena_new(), BLI_MEMARENA_STD_BUFSIZE, bm, BM_ELEM_TAG, BM_FACE, BM_mesh_elem_hflag_disable_all(), bmo_face_inset_individual(), BMO_ITER, BMO_slot_bool_get(), BMO_slot_buffer_from_enabled_flag(), BMO_slot_buffer_hflag_enable(), BMO_slot_float_get(), ELE_NEW, BMOperator::slots_in, and BMOperator::slots_out.

◆ bmo_inset_region_exec()

void bmo_inset_region_exec ( BMesh * bm,
BMOperator * op )

This case where only one edge attached to #v_split is used. i.e. the face to inset is on a boundary.

                 We want the inset to align flush with the
                 boundary edge, not the normal of the interior
            <--- edge which would give an unsightly bump.
--+-------------------------+---------------+--
  |^v_other    ^e_other    /^v_split        |
  |                       /                 |
  |                      /                  |
  |                     / <- tag split edge |
  |                    /                    |
  |                   /                     |
  |                  /                      |
--+-----------------+-----------------------+--
  |                                         |
  |                                         |
Note
The fact we are doing location comparisons on verts that are moved about doesn't matter because the direction will remain the same in this case.

Loops vars from newly created face (face_a/b)

             l_a->e & l_b->prev->e
+------------------------------------+
|\ l_a                          l_b /|
| \ l_a->prev->e            l_b->e / |
|  \ l_a->prev          l_b->next /  |
|   +----------------------------+   |
|   |l_a_other    ^     l_b_other|   |
|   |        l_b->next->e &...   |   |
|   |        l_a->prev->prev->e  |   |
|   |        (inset face)        |   |
|   +----------------------------+   |
|  /                              \  |
| /                                \ |
|/                                  |
+------------------------------------+

Definition at line 662 of file bmo_inset.cc.

References add_v3_v3(), add_v3_v3v3(), InterpFace::axis_mat, BLI_assert, BLI_ghash_free(), BLI_ghash_ptr_new(), BLI_memarena_alloc(), BLI_memarena_free(), BLI_memarena_new(), BLI_MEMARENA_STD_BUFSIZE, InterpFace::blocks_l, InterpFace::blocks_v, bm, BM_CREATE_NOP, BM_EDGE, BM_edge_calc_face_tangent(), BM_edge_calc_length(), BM_edge_create(), bm_edge_info_average_length_with_fallback(), BM_edge_is_boundary(), BM_edge_is_manifold(), bm_edge_is_mixed_face_tag(), BM_edge_ordered_verts_ex(), BM_edge_other_loop(), BM_edge_other_vert(), BM_EDGES_OF_MESH, BM_EDGES_OF_VERT, BM_elem_attrs_copy(), BM_elem_flag_disable, BM_elem_flag_enable, BM_elem_flag_test, BM_elem_index_get, BM_elem_index_set, BM_ELEM_TAG, BM_FACE, BM_face_copy_shared(), BM_face_create_verts(), BM_FACE_FIRST_LOOP, BM_face_interp_from_face_ex(), BM_FACES_OF_VERT, bm_interp_face_free(), bm_interp_face_store(), BM_ITER_ELEM, BM_ITER_MESH, BM_ITER_MESH_INDEX, bm_loop_customdata_merge(), BM_loop_other_vert_loop(), BM_mesh_elem_hflag_disable_all(), BM_mesh_elem_hflag_enable_all(), BM_VERT, BM_vert_calc_shell_factor(), BM_vert_create(), BM_vert_splice(), BM_VERTS_OF_EDGE, BM_VERTS_OF_MESH, bmesh_kernel_edge_separate(), bmesh_kernel_vert_separate(), BMO_face_flag_enable, BMO_ITER, BMO_slot_bool_get(), BMO_slot_buffer_from_enabled_flag(), BMO_slot_buffer_hflag_disable(), BMO_slot_buffer_hflag_enable(), BMO_slot_float_get(), BMVert::co, compare_v3v3(), copy_v3_v3(), InterpFace::cos_2d, cross_v3_v3v3(), CustomData_bmesh_copy_block(), CustomData_bmesh_free_block_data(), CustomData_has_math(), BMHeader::data, dot_v3v3(), BMLoop::e, BMVert::e, e, SplitEdgeInfo::e_new, SplitEdgeInfo::e_old, ELE_NEW, BMesh::elem_index_dirty, BMLoop::f, InterpFace::f, float, BMLoop::head, BMEdge::l, l, SplitEdgeInfo::l, l_b, BMesh::ldata, len_squared_v3(), len_squared_v3v3(), SplitEdgeInfo::length, madd_v3_v3fl(), madd_v3_v3v3fl(), MEM_callocN, MEM_freeN(), MEM_mallocN, mid_v3_v3v3(), mul_v3_fl(), negate_v3(), BMLoop::next, BMFace::no, BMVert::no, SplitEdgeInfo::no, normalize_v3(), BMLoop::prev, shell_v3v3_mid_normalized_to_dist(), shell_v3v3_normalized_to_dist(), BMOperator::slots_in, BMOperator::slots_out, sub_v3_v3v3(), BMesh::totface, BMesh::totvert, BMLoop::v, v, BMEdge::v1, BMEdge::v2, v2, VERT_ORIG_GET, VERT_ORIG_REMOVE, VERT_ORIG_STORE, and zero_v3().