Cleanup: Refactor BKE_nlatrack_add to multiple methods to handle adding a new NLA track to the track list. Insert before, after, head, and tail #104929
|
@ -871,15 +871,6 @@ bool BKE_mesh_validate_all_customdata(struct CustomData *vdata,
|
|||
bool *r_change);
|
||||
|
||||
void BKE_mesh_strip_loose_faces(struct Mesh *me);
|
||||
/**
|
||||
* Works on both loops and polys!
|
||||
*
|
||||
* \note It won't try to guess which loops of an invalid poly to remove!
|
||||
* this is the work of the caller, to mark those loops.
|
||||
* See e.g. #BKE_mesh_validate_arrays().
|
||||
*/
|
||||
void BKE_mesh_strip_loose_polysloops(struct Mesh *me);
|
||||
void BKE_mesh_strip_loose_edges(struct Mesh *me);
|
||||
|
||||
/**
|
||||
* Calculate edges from polygons.
|
||||
|
@ -921,7 +912,7 @@ void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1);
|
|||
|
||||
/**
|
||||
* \return The material index for each polygon. May be null.
|
||||
* \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/
|
||||
* \note In C++ code, prefer using the attribute API (#AttributeAccessor).
|
||||
*/
|
||||
BLI_INLINE const int *BKE_mesh_material_indices(const Mesh *mesh)
|
||||
{
|
||||
|
@ -930,7 +921,7 @@ BLI_INLINE const int *BKE_mesh_material_indices(const Mesh *mesh)
|
|||
|
||||
/**
|
||||
* \return The material index for each polygon. Create the layer if it doesn't exist.
|
||||
* \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/
|
||||
* \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor).
|
||||
*/
|
||||
BLI_INLINE int *BKE_mesh_material_indices_for_write(Mesh *mesh)
|
||||
{
|
||||
|
|
|
@ -153,8 +153,7 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float
|
|||
/**
|
||||
* Find per-corner coordinate with given per-face UV coord.
|
||||
*/
|
||||
int mdisp_rot_face_to_crn(
|
||||
struct MPoly *poly, int face_side, float u, float v, float *x, float *y);
|
||||
int mdisp_rot_face_to_crn(struct MPoly *poly, int face_side, float u, float v, float *x, float *y);
|
||||
|
||||
/* Reshaping, define in multires_reshape.cc */
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ using blender::Span;
|
|||
|
||||
static CLG_LogRef LOG = {"bke.mesh"};
|
||||
|
||||
void mesh_strip_polysloops(Mesh *me);
|
||||
void mesh_strip_edges(Mesh *me);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal functions
|
||||
* \{ */
|
||||
|
@ -862,11 +865,11 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
|||
}
|
||||
|
||||
if (free_flag.polyloops) {
|
||||
BKE_mesh_strip_loose_polysloops(mesh);
|
||||
mesh_strip_polysloops(mesh);
|
||||
}
|
||||
|
||||
if (free_flag.edges) {
|
||||
BKE_mesh_strip_loose_edges(mesh);
|
||||
mesh_strip_edges(mesh);
|
||||
}
|
||||
|
||||
if (recalc_flag.edges) {
|
||||
|
@ -1205,7 +1208,7 @@ void BKE_mesh_strip_loose_faces(Mesh *me)
|
|||
}
|
||||
}
|
||||
|
||||
void BKE_mesh_strip_loose_polysloops(Mesh *me)
|
||||
void mesh_strip_polysloops(Mesh *me)
|
||||
{
|
||||
MutableSpan<MPoly> polys = me->polys_for_write();
|
||||
MutableSpan<MLoop> loops = me->loops_for_write();
|
||||
|
@ -1279,7 +1282,7 @@ void BKE_mesh_strip_loose_polysloops(Mesh *me)
|
|||
MEM_freeN(new_idx);
|
||||
}
|
||||
|
||||
void BKE_mesh_strip_loose_edges(Mesh *me)
|
||||
void mesh_strip_edges(Mesh *me)
|
||||
{
|
||||
MEdge *e;
|
||||
int a, b;
|
||||
|
|
|
@ -95,7 +95,8 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, PBVHVertRef vertex, float r_
|
|||
zero_v4(r_color);
|
||||
for (const int i_poly : Span(melem.indices, melem.count)) {
|
||||
const MPoly &poly = pbvh.polys[i_poly];
|
||||
Span<T> colors{static_cast<const T *>(pbvh.color_layer->data) + poly.loopstart, poly.totloop};
|
||||
Span<T> colors{static_cast<const T *>(pbvh.color_layer->data) + poly.loopstart,
|
||||
poly.totloop};
|
||||
Span<MLoop> loops{pbvh.mloop + poly.loopstart, poly.totloop};
|
||||
|
||||
for (const int i_loop : IndexRange(poly.totloop)) {
|
||||
|
@ -128,7 +129,8 @@ static void pbvh_vertex_color_set(PBVH &pbvh, PBVHVertRef vertex, const float co
|
|||
|
||||
for (const int i_poly : Span(melem.indices, melem.count)) {
|
||||
const MPoly &poly = pbvh.polys[i_poly];
|
||||
MutableSpan<T> colors{static_cast<T *>(pbvh.color_layer->data) + poly.loopstart, poly.totloop};
|
||||
MutableSpan<T> colors{static_cast<T *>(pbvh.color_layer->data) + poly.loopstart,
|
||||
poly.totloop};
|
||||
Span<MLoop> loops{pbvh.mloop + poly.loopstart, poly.totloop};
|
||||
|
||||
for (const int i_loop : IndexRange(poly.totloop)) {
|
||||
|
|
|
@ -45,9 +45,6 @@
|
|||
|
||||
#include "CCGSubSurf.h"
|
||||
|
||||
/* assumes MLoop's are laid out 4 for each poly, in order */
|
||||
#define USE_LOOP_LAYOUT_FAST
|
||||
|
||||
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
|
||||
int drawInteriorEdges,
|
||||
int useSubsurfUv,
|
||||
|
@ -574,8 +571,12 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
|
|||
|
||||
crease = useFlatSubdiv ? creaseFactor : (creases ? creases[i] * creaseFactor : 0.0f);
|
||||
|
||||
ccgSubSurf_syncEdge(
|
||||
ss, POINTER_FROM_INT(i), POINTER_FROM_UINT(edge->v1), POINTER_FROM_UINT(edge->v2), crease, &e);
|
||||
ccgSubSurf_syncEdge(ss,
|
||||
POINTER_FROM_INT(i),
|
||||
POINTER_FROM_UINT(edge->v1),
|
||||
POINTER_FROM_UINT(edge->v2),
|
||||
crease,
|
||||
&e);
|
||||
|
||||
((int *)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index) ? *index++ : i;
|
||||
}
|
||||
|
|
|
@ -346,7 +346,8 @@ struct PBVHBatches {
|
|||
|
||||
if (!(poly->flag & ME_SMOOTH)) {
|
||||
smooth = true;
|
||||
BKE_mesh_calc_poly_normal(poly, args->mloop + poly->loopstart, args->vert_positions, fno);
|
||||
BKE_mesh_calc_poly_normal(
|
||||
poly, args->mloop + poly->loopstart, args->vert_positions, fno);
|
||||
normal_float_to_short_v3(no, fno);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -3643,7 +3643,7 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
|
|||
/** \name View Channel Operator
|
||||
* \{ */
|
||||
|
||||
static void get_normalized_fcurve_bounds(FCurve *fcu,
|
||||
static bool get_normalized_fcurve_bounds(FCurve *fcu,
|
||||
bAnimContext *ac,
|
||||
const bAnimListElem *ale,
|
||||
const bool include_handles,
|
||||
|
@ -3651,14 +3651,18 @@ static void get_normalized_fcurve_bounds(FCurve *fcu,
|
|||
rctf *r_bounds)
|
||||
{
|
||||
const bool fcu_selection_only = false;
|
||||
BKE_fcurve_calc_bounds(fcu,
|
||||
&r_bounds->xmin,
|
||||
&r_bounds->xmax,
|
||||
&r_bounds->ymin,
|
||||
&r_bounds->ymax,
|
||||
fcu_selection_only,
|
||||
include_handles,
|
||||
range);
|
||||
const bool found_bounds = BKE_fcurve_calc_bounds(fcu,
|
||||
&r_bounds->xmin,
|
||||
&r_bounds->xmax,
|
||||
&r_bounds->ymin,
|
||||
&r_bounds->ymax,
|
||||
fcu_selection_only,
|
||||
include_handles,
|
||||
range);
|
||||
if (!found_bounds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const short mapping_flag = ANIM_get_normalization_flags(ac);
|
||||
|
||||
float offset;
|
||||
|
@ -3674,9 +3678,10 @@ static void get_normalized_fcurve_bounds(FCurve *fcu,
|
|||
r_bounds->ymin -= (min_height - height) / 2;
|
||||
r_bounds->ymax += (min_height - height) / 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void get_gpencil_bounds(bGPDlayer *gpl, const float range[2], rctf *r_bounds)
|
||||
static bool get_gpencil_bounds(bGPDlayer *gpl, const float range[2], rctf *r_bounds)
|
||||
{
|
||||
bool found_start = false;
|
||||
int start_frame = 0;
|
||||
|
@ -3698,6 +3703,8 @@ static void get_gpencil_bounds(bGPDlayer *gpl, const float range[2], rctf *r_bou
|
|||
r_bounds->xmax = end_frame;
|
||||
r_bounds->ymin = 0;
|
||||
r_bounds->ymax = 1;
|
||||
|
||||
return found_start;
|
||||
}
|
||||
|
||||
static bool get_channel_bounds(bAnimContext *ac,
|
||||
|
@ -3710,14 +3717,12 @@ static bool get_channel_bounds(bAnimContext *ac,
|
|||
switch (ale->datatype) {
|
||||
case ALE_GPFRAME: {
|
||||
bGPDlayer *gpl = (bGPDlayer *)ale->data;
|
||||
get_gpencil_bounds(gpl, range, r_bounds);
|
||||
found_bounds = true;
|
||||
found_bounds = get_gpencil_bounds(gpl, range, r_bounds);
|
||||
break;
|
||||
}
|
||||
case ALE_FCURVE: {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
get_normalized_fcurve_bounds(fcu, ac, ale, include_handles, range, r_bounds);
|
||||
found_bounds = true;
|
||||
found_bounds = get_normalized_fcurve_bounds(fcu, ac, ale, include_handles, range, r_bounds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3806,6 +3811,7 @@ static int graphkeys_view_selected_channels_exec(bContext *C, wmOperator *op)
|
|||
|
||||
if (!valid_bounds) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
WM_report(RPT_WARNING, "No keyframes to focus on.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@ -3892,6 +3898,7 @@ static int graphkeys_channel_view_pick_invoke(bContext *C, wmOperator *op, const
|
|||
|
||||
if (!found_bounds) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
WM_report(RPT_WARNING, "No keyframes to focus on.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -223,11 +223,6 @@ static PanelType *fmodifier_subpanel_register(ARegionType *region_type,
|
|||
/** \name General UI Callbacks and Drawing
|
||||
* \{ */
|
||||
|
||||
/* XXX! -------------------------------- */
|
||||
/* Temporary definition for limits of float number buttons
|
||||
* (FLT_MAX tends to infinity with old system). */
|
||||
#define UI_FLT_MAX 10000.0f
|
||||
|
||||
#define B_REDR 1
|
||||
#define B_FMODIFIER_REDRAW 20
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
/* own includes */
|
||||
#include "../gizmo_library_intern.h"
|
||||
|
||||
#define GIZMO_RESIZER_SIZE 10.0f
|
||||
#define GIZMO_MARGIN_OFFSET_SCALE 1.5f
|
||||
|
||||
static void gizmo_calc_matrix_final_no_offset(const wmGizmo *gz,
|
||||
|
|
|
@ -57,10 +57,6 @@ struct wmTimer;
|
|||
#define UI_MENU_SCROLL_MOUSE (UI_MENU_SCROLL_ARROW + 2 * UI_DPI_FAC)
|
||||
#define UI_MENU_SCROLL_PAD (4 * UI_DPI_FAC)
|
||||
|
||||
/* panel limits */
|
||||
#define UI_PANEL_MINX 100
|
||||
#define UI_PANEL_MINY 70
|
||||
|
||||
/** Popover width (multiplied by #U.widget_unit) */
|
||||
#define UI_POPOVER_WIDTH_UNITS 10
|
||||
|
||||
|
|
|
@ -38,10 +38,6 @@
|
|||
|
||||
#include "view3d_intern.h"
|
||||
|
||||
#define B_SEL_VERT 110
|
||||
#define B_SEL_EDGE 111
|
||||
#define B_SEL_FACE 112
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Toggle Matcap Flip Operator
|
||||
* \{ */
|
||||
|
|
|
@ -2992,6 +2992,15 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
|
|||
Object *obedit = CTX_data_edit_object(C);
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
|
||||
if (obact && obact->type == OB_GPENCIL && GPENCIL_ANY_MODE((bGPdata *)obact->data)) {
|
||||
/* Prevent acting on Grease Pencil (when not in object mode), it implements its own selection
|
||||
* operator in other modes. We might still fall trough to here (because that operator uses
|
||||
* OPERATOR_PASS_THROUGH to make tweak work) but if we dont stop here code below assumes we are
|
||||
* in object mode it might falsely toggle object selection. Alternatively, this could be put in
|
||||
* the poll funtion instead. */
|
||||
return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
ViewContext vc;
|
||||
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Utilities for manipulating UV islands.
|
||||
*
|
||||
* \note This is similar to `GEO_uv_parametrizer.h`,
|
||||
* \note This is similar to `GEO_uv_parametrizer.hh`,
|
||||
* however the data structures there don't support arbitrary topology
|
||||
* such as an edge with 3 or more faces using it.
|
||||
* This API uses #BMesh data structures and doesn't have limitations for manifold meshes.
|
||||
|
@ -466,7 +466,7 @@ static bool island_has_pins(const Scene *scene,
|
|||
/* -------------------------------------------------------------------- */
|
||||
/** \name Public UV Island Packing
|
||||
*
|
||||
* \note This behavior loosely follows #GEO_uv_parametrizer_pack.
|
||||
* \note This behavior loosely follows #geometry::uv_parametrizer_pack.
|
||||
* \{ */
|
||||
|
||||
void ED_uvedit_pack_islands_multi(const Scene *scene,
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "GEO_uv_pack.hh"
|
||||
#include "GEO_uv_parametrizer.h"
|
||||
#include "GEO_uv_parametrizer.hh"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
|
@ -69,6 +69,9 @@
|
|||
|
||||
#include "uvedit_intern.h"
|
||||
|
||||
using blender::geometry::ParamHandle;
|
||||
using blender::geometry::ParamKey;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utility Functions
|
||||
* \{ */
|
||||
|
@ -335,7 +338,7 @@ static void uvedit_prepare_pinned_indices(ParamHandle *handle,
|
|||
if (pin) {
|
||||
int bmvertindex = BM_elem_index_get(l->v);
|
||||
const float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
GEO_uv_prepare_pin_index(handle, bmvertindex, luv);
|
||||
blender::geometry::uv_prepare_pin_index(handle, bmvertindex, luv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -343,7 +346,7 @@ static void uvedit_prepare_pinned_indices(ParamHandle *handle,
|
|||
static void construct_param_handle_face_add(ParamHandle *handle,
|
||||
const Scene *scene,
|
||||
BMFace *efa,
|
||||
ParamKey face_index,
|
||||
blender::geometry::ParamKey face_index,
|
||||
const UnwrapOptions *options,
|
||||
const BMUVOffsets offsets)
|
||||
{
|
||||
|
@ -362,7 +365,7 @@ static void construct_param_handle_face_add(ParamHandle *handle,
|
|||
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
|
||||
vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv);
|
||||
vkeys[i] = blender::geometry::uv_find_pin_index(handle, BM_elem_index_get(l->v), luv);
|
||||
co[i] = l->v->co;
|
||||
uv[i] = luv;
|
||||
pin[i] = BM_ELEM_CD_GET_BOOL(l, offsets.pin);
|
||||
|
@ -372,7 +375,7 @@ static void construct_param_handle_face_add(ParamHandle *handle,
|
|||
}
|
||||
}
|
||||
|
||||
GEO_uv_parametrizer_face_add(
|
||||
blender::geometry::uv_parametrizer_face_add(
|
||||
handle, face_index, i, vkeys.data(), co.data(), uv.data(), pin.data(), select.data());
|
||||
}
|
||||
|
||||
|
@ -406,11 +409,12 @@ static void construct_param_edge_set_seams(ParamHandle *handle,
|
|||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
float *luv_next = BM_ELEM_CD_GET_FLOAT_P(l->next, offsets.uv);
|
||||
ParamKey vkeys[2];
|
||||
vkeys[0] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv);
|
||||
vkeys[1] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->next->v), luv_next);
|
||||
vkeys[0] = blender::geometry::uv_find_pin_index(handle, BM_elem_index_get(l->v), luv);
|
||||
vkeys[1] = blender::geometry::uv_find_pin_index(
|
||||
handle, BM_elem_index_get(l->next->v), luv_next);
|
||||
|
||||
/* Set the seam. */
|
||||
GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
blender::geometry::uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -428,7 +432,7 @@ static ParamHandle *construct_param_handle(const Scene *scene,
|
|||
BMIter iter;
|
||||
int i;
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
ParamHandle *handle = blender::geometry::uv_parametrizer_construct_begin();
|
||||
|
||||
if (options->correct_aspect) {
|
||||
float aspx, aspy;
|
||||
|
@ -436,7 +440,7 @@ static ParamHandle *construct_param_handle(const Scene *scene,
|
|||
ED_uvedit_get_aspect(ob, &aspx, &aspy);
|
||||
|
||||
if (aspx != aspy) {
|
||||
GEO_uv_parametrizer_aspect_ratio(handle, aspx, aspy);
|
||||
blender::geometry::uv_parametrizer_aspect_ratio(handle, aspx, aspy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,10 +462,11 @@ static ParamHandle *construct_param_handle(const Scene *scene,
|
|||
|
||||
construct_param_edge_set_seams(handle, bm, options);
|
||||
|
||||
GEO_uv_parametrizer_construct_end(handle,
|
||||
options->fill_holes,
|
||||
options->topology_from_uvs,
|
||||
result_info ? &result_info->count_failed : nullptr);
|
||||
blender::geometry::uv_parametrizer_construct_end(handle,
|
||||
options->fill_holes,
|
||||
options->topology_from_uvs,
|
||||
result_info ? &result_info->count_failed :
|
||||
nullptr);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
@ -478,7 +483,7 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
|
|||
BMIter iter;
|
||||
int i;
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
ParamHandle *handle = blender::geometry::uv_parametrizer_construct_begin();
|
||||
|
||||
if (options->correct_aspect) {
|
||||
Object *ob = objects[0];
|
||||
|
@ -486,7 +491,7 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
|
|||
|
||||
ED_uvedit_get_aspect(ob, &aspx, &aspy);
|
||||
if (aspx != aspy) {
|
||||
GEO_uv_parametrizer_aspect_ratio(handle, aspx, aspy);
|
||||
blender::geometry::uv_parametrizer_aspect_ratio(handle, aspx, aspy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,7 +528,7 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
|
|||
offset += bm->totface;
|
||||
}
|
||||
|
||||
GEO_uv_parametrizer_construct_end(
|
||||
blender::geometry::uv_parametrizer_construct_end(
|
||||
handle, options->fill_holes, options->topology_from_uvs, nullptr);
|
||||
|
||||
return handle;
|
||||
|
@ -607,7 +612,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
|
||||
const BMUVOffsets offsets = BM_uv_map_get_offsets(em->bm);
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
ParamHandle *handle = blender::geometry::uv_parametrizer_construct_begin();
|
||||
|
||||
if (options->correct_aspect) {
|
||||
float aspx, aspy;
|
||||
|
@ -615,7 +620,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
ED_uvedit_get_aspect(ob, &aspx, &aspy);
|
||||
|
||||
if (aspx != aspy) {
|
||||
GEO_uv_parametrizer_aspect_ratio(handle, aspx, aspy);
|
||||
blender::geometry::uv_parametrizer_aspect_ratio(handle, aspx, aspy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -712,7 +717,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
texface_from_original_index(
|
||||
scene, offsets, origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3]);
|
||||
|
||||
GEO_uv_parametrizer_face_add(handle, key, 4, vkeys, co, uv, pin, select);
|
||||
blender::geometry::uv_parametrizer_face_add(handle, key, 4, vkeys, co, uv, pin, select);
|
||||
}
|
||||
|
||||
/* these are calculated from original mesh too */
|
||||
|
@ -722,14 +727,15 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
|
|||
ParamKey vkeys[2];
|
||||
vkeys[0] = (ParamKey)edge->v1;
|
||||
vkeys[1] = (ParamKey)edge->v2;
|
||||
GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
blender::geometry::uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
}
|
||||
}
|
||||
|
||||
GEO_uv_parametrizer_construct_end(handle,
|
||||
options->fill_holes,
|
||||
options->topology_from_uvs,
|
||||
result_info ? &result_info->count_failed : nullptr);
|
||||
blender::geometry::uv_parametrizer_construct_end(handle,
|
||||
options->fill_holes,
|
||||
options->topology_from_uvs,
|
||||
result_info ? &result_info->count_failed :
|
||||
nullptr);
|
||||
|
||||
/* cleanup */
|
||||
MEM_freeN(faceMap);
|
||||
|
@ -787,9 +793,9 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
|
|||
ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options);
|
||||
ms->lasttime = PIL_check_seconds_timer();
|
||||
|
||||
GEO_uv_parametrizer_stretch_begin(ms->handle);
|
||||
blender::geometry::uv_parametrizer_stretch_begin(ms->handle);
|
||||
if (ms->blend != 0.0f) {
|
||||
GEO_uv_parametrizer_stretch_blend(ms->handle, ms->blend);
|
||||
blender::geometry::uv_parametrizer_stretch_blend(ms->handle, ms->blend);
|
||||
}
|
||||
|
||||
op->customdata = ms;
|
||||
|
@ -805,8 +811,8 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
|
|||
ToolSettings *ts = scene->toolsettings;
|
||||
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
|
||||
|
||||
GEO_uv_parametrizer_stretch_blend(ms->handle, ms->blend);
|
||||
GEO_uv_parametrizer_stretch_iter(ms->handle);
|
||||
blender::geometry::uv_parametrizer_stretch_blend(ms->handle, ms->blend);
|
||||
blender::geometry::uv_parametrizer_stretch_iter(ms->handle);
|
||||
|
||||
ms->i++;
|
||||
RNA_int_set(op->ptr, "iterations", ms->i);
|
||||
|
@ -814,7 +820,7 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
|
|||
if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
|
||||
char str[UI_MAX_DRAW_STR];
|
||||
|
||||
GEO_uv_parametrizer_flush(ms->handle);
|
||||
blender::geometry::uv_parametrizer_flush(ms->handle);
|
||||
|
||||
if (area) {
|
||||
BLI_snprintf(str, sizeof(str), TIP_("Minimize Stretch. Blend %.2f"), ms->blend);
|
||||
|
@ -854,14 +860,14 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
|
|||
}
|
||||
|
||||
if (cancel) {
|
||||
GEO_uv_parametrizer_flush_restore(ms->handle);
|
||||
blender::geometry::uv_parametrizer_flush_restore(ms->handle);
|
||||
}
|
||||
else {
|
||||
GEO_uv_parametrizer_flush(ms->handle);
|
||||
blender::geometry::uv_parametrizer_flush(ms->handle);
|
||||
}
|
||||
|
||||
GEO_uv_parametrizer_stretch_end(ms->handle);
|
||||
GEO_uv_parametrizer_delete(ms->handle);
|
||||
blender::geometry::uv_parametrizer_stretch_end(ms->handle);
|
||||
blender::geometry::uv_parametrizer_delete(ms->handle);
|
||||
|
||||
for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
|
||||
Object *obedit = ms->objects_edit[ob_index];
|
||||
|
@ -1175,9 +1181,9 @@ static int average_islands_scale_exec(bContext *C, wmOperator *op)
|
|||
const bool shear = RNA_boolean_get(op->ptr, "shear");
|
||||
|
||||
ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options);
|
||||
GEO_uv_parametrizer_average(handle, false, scale_uv, shear);
|
||||
GEO_uv_parametrizer_flush(handle);
|
||||
GEO_uv_parametrizer_delete(handle);
|
||||
blender::geometry::uv_parametrizer_average(handle, false, scale_uv, shear);
|
||||
blender::geometry::uv_parametrizer_flush(handle);
|
||||
blender::geometry::uv_parametrizer_delete(handle);
|
||||
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
|
@ -1250,7 +1256,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
|
|||
handle = construct_param_handle(scene, obedit, em->bm, &options, nullptr);
|
||||
}
|
||||
|
||||
GEO_uv_parametrizer_lscm_begin(handle, true, abf);
|
||||
blender::geometry::uv_parametrizer_lscm_begin(handle, true, abf);
|
||||
|
||||
/* Create or increase size of g_live_unwrap.handles array */
|
||||
if (g_live_unwrap.handles == nullptr) {
|
||||
|
@ -1272,8 +1278,8 @@ void ED_uvedit_live_unwrap_re_solve(void)
|
|||
{
|
||||
if (g_live_unwrap.handles) {
|
||||
for (int i = 0; i < g_live_unwrap.len; i++) {
|
||||
GEO_uv_parametrizer_lscm_solve(g_live_unwrap.handles[i], nullptr, nullptr);
|
||||
GEO_uv_parametrizer_flush(g_live_unwrap.handles[i]);
|
||||
blender::geometry::uv_parametrizer_lscm_solve(g_live_unwrap.handles[i], nullptr, nullptr);
|
||||
blender::geometry::uv_parametrizer_flush(g_live_unwrap.handles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1282,11 +1288,11 @@ void ED_uvedit_live_unwrap_end(short cancel)
|
|||
{
|
||||
if (g_live_unwrap.handles) {
|
||||
for (int i = 0; i < g_live_unwrap.len; i++) {
|
||||
GEO_uv_parametrizer_lscm_end(g_live_unwrap.handles[i]);
|
||||
blender::geometry::uv_parametrizer_lscm_end(g_live_unwrap.handles[i]);
|
||||
if (cancel) {
|
||||
GEO_uv_parametrizer_flush_restore(g_live_unwrap.handles[i]);
|
||||
blender::geometry::uv_parametrizer_flush_restore(g_live_unwrap.handles[i]);
|
||||
}
|
||||
GEO_uv_parametrizer_delete(g_live_unwrap.handles[i]);
|
||||
blender::geometry::uv_parametrizer_delete(g_live_unwrap.handles[i]);
|
||||
}
|
||||
MEM_freeN(g_live_unwrap.handles);
|
||||
g_live_unwrap.handles = nullptr;
|
||||
|
@ -1521,6 +1527,9 @@ static void uv_transform_properties(wmOperatorType *ot, int radius)
|
|||
"Align",
|
||||
"How to determine rotation around the pole");
|
||||
RNA_def_enum(ot->srna, "pole", pole_items, PINCH, "Pole", "How to handle faces at the poles");
|
||||
RNA_def_boolean(
|
||||
ot->srna, "seam", 0, "Preserve Seams", "Separate projections by islands isolated by seams");
|
||||
|
||||
if (radius) {
|
||||
RNA_def_float(ot->srna,
|
||||
"radius",
|
||||
|
@ -1804,17 +1813,19 @@ static void uvedit_unwrap(const Scene *scene,
|
|||
handle = construct_param_handle(scene, obedit, em->bm, options, result_info);
|
||||
}
|
||||
|
||||
GEO_uv_parametrizer_lscm_begin(handle, false, scene->toolsettings->unwrapper == 0);
|
||||
GEO_uv_parametrizer_lscm_solve(handle,
|
||||
result_info ? &result_info->count_changed : nullptr,
|
||||
result_info ? &result_info->count_failed : nullptr);
|
||||
GEO_uv_parametrizer_lscm_end(handle);
|
||||
blender::geometry::uv_parametrizer_lscm_begin(
|
||||
handle, false, scene->toolsettings->unwrapper == 0);
|
||||
blender::geometry::uv_parametrizer_lscm_solve(
|
||||
handle,
|
||||
result_info ? &result_info->count_changed : nullptr,
|
||||
result_info ? &result_info->count_failed : nullptr);
|
||||
blender::geometry::uv_parametrizer_lscm_end(handle);
|
||||
|
||||
GEO_uv_parametrizer_average(handle, true, false, false);
|
||||
blender::geometry::uv_parametrizer_average(handle, true, false, false);
|
||||
|
||||
GEO_uv_parametrizer_flush(handle);
|
||||
blender::geometry::uv_parametrizer_flush(handle);
|
||||
|
||||
GEO_uv_parametrizer_delete(handle);
|
||||
blender::geometry::uv_parametrizer_delete(handle);
|
||||
}
|
||||
|
||||
static void uvedit_unwrap_multi(const Scene *scene,
|
||||
|
@ -2797,25 +2808,114 @@ static void uv_map_mirror(BMFace *efa,
|
|||
}
|
||||
}
|
||||
|
||||
static void uv_sphere_project(BMFace *efa,
|
||||
const float center[3],
|
||||
const float rotmat[3][3],
|
||||
const bool fan,
|
||||
const int cd_loop_uv_offset)
|
||||
/** Store a face and it's current branch on the generalized atan2 function.
|
||||
*
|
||||
* In complex analysis, we can generalize the arctangent function
|
||||
* into a multi-valued function that is "almost everywhere continuous"
|
||||
* in the complex plane.
|
||||
*
|
||||
* The downside is that we need to keep track of which "branch" of the
|
||||
* multi-valued function we are currently on.
|
||||
*
|
||||
* \note Even though atan2(a+bi, c+di) is now (multiply) defined for all
|
||||
* complex inputs, we will only evaluate it with `b==0` and `d==0`.
|
||||
*/
|
||||
|
||||
struct uv_face_branch {
|
||||
BMFace *efa;
|
||||
float branch;
|
||||
};
|
||||
|
||||
/** Compute the sphere projection for a BMFace using #map_to_sphere and store on BMLoops.
|
||||
*
|
||||
* Heuristics are used in #uv_map_mirror to improve winding.
|
||||
*
|
||||
* if `fan` is true, faces with UVs at the pole have corrections appled to fan the UVs.
|
||||
*
|
||||
* if `use_seams` is true, the unwrapping will flood fill across the mesh, using
|
||||
* seams to mark boundaries, and #BM_ELEM_TAG to prevent revisiting faces.
|
||||
*/
|
||||
static float uv_sphere_project(const Scene *scene,
|
||||
BMesh *bm,
|
||||
BMFace *efa_init,
|
||||
const float center[3],
|
||||
const float rotmat[3][3],
|
||||
const bool fan,
|
||||
const BMUVOffsets offsets,
|
||||
const bool only_selected_uvs,
|
||||
const bool use_seams,
|
||||
const float branch_init)
|
||||
{
|
||||
blender::Array<bool, BM_DEFAULT_NGON_STACK_SIZE> regular(efa->len);
|
||||
int i;
|
||||
BMLoop *l;
|
||||
BMIter iter;
|
||||
BM_ITER_ELEM_INDEX (l, &iter, efa, BM_LOOPS_OF_FACE, i) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
||||
float pv[3];
|
||||
sub_v3_v3v3(pv, l->v->co, center);
|
||||
mul_m3_v3(rotmat, pv);
|
||||
regular[i] = map_to_sphere(&luv[0], &luv[1], pv[0], pv[1], pv[2]);
|
||||
float max_u = 0.0f;
|
||||
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
return max_u;
|
||||
}
|
||||
|
||||
uv_map_mirror(efa, regular.data(), fan, cd_loop_uv_offset);
|
||||
/* Similar to BM_mesh_calc_face_groups with added connectivity information. */
|
||||
blender::Vector<uv_face_branch> stack;
|
||||
stack.append({efa_init, branch_init});
|
||||
|
||||
while (stack.size()) {
|
||||
uv_face_branch face_branch = stack.pop_last();
|
||||
BMFace *efa = face_branch.efa;
|
||||
|
||||
if (use_seams) {
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
|
||||
continue; /* Faces might be in the stack more than once. */
|
||||
}
|
||||
|
||||
BM_elem_flag_set(efa, BM_ELEM_TAG, true); /* Visited, don't consider again. */
|
||||
}
|
||||
|
||||
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
continue; /* Unselected face, ignore. */
|
||||
}
|
||||
|
||||
if (only_selected_uvs) {
|
||||
if (!uvedit_face_select_test(scene, efa, offsets)) {
|
||||
uvedit_face_select_disable(scene, bm, efa, offsets);
|
||||
continue; /* Unselected UV, ignore. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember which UVs are at the pole. */
|
||||
blender::Array<bool, BM_DEFAULT_NGON_STACK_SIZE> regular(efa->len);
|
||||
|
||||
int i;
|
||||
BMLoop *l;
|
||||
BMIter iter;
|
||||
BM_ITER_ELEM_INDEX (l, &iter, efa, BM_LOOPS_OF_FACE, i) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
float pv[3];
|
||||
sub_v3_v3v3(pv, l->v->co, center);
|
||||
mul_m3_v3(rotmat, pv);
|
||||
regular[i] = map_to_sphere(&luv[0], &luv[1], pv[0], pv[1], pv[2]);
|
||||
if (!use_seams) {
|
||||
continue; /* Nothing more to do. */
|
||||
}
|
||||
|
||||
/* Move UV to correct branch. */
|
||||
luv[0] = luv[0] + ceilf(face_branch.branch - 0.5f - luv[0]);
|
||||
max_u = max_ff(max_u, luv[0]);
|
||||
|
||||
BMEdge *edge = l->e;
|
||||
if (BM_elem_flag_test(edge, BM_ELEM_SEAM)) {
|
||||
continue; /* Stop flood fill at seams. */
|
||||
}
|
||||
|
||||
/* Extend flood fill by pushing to stack. */
|
||||
BMFace *efa2;
|
||||
BMIter iter2;
|
||||
BM_ITER_ELEM (efa2, &iter2, edge, BM_FACES_OF_EDGE) {
|
||||
if (!BM_elem_flag_test(efa2, BM_ELEM_TAG)) {
|
||||
stack.append({efa2, luv[0]});
|
||||
}
|
||||
}
|
||||
}
|
||||
uv_map_mirror(efa, regular.data(), fan, offsets.uv);
|
||||
}
|
||||
|
||||
return max_u;
|
||||
}
|
||||
|
||||
static int sphere_project_exec(bContext *C, wmOperator *op)
|
||||
|
@ -2855,20 +2955,25 @@ static int sphere_project_exec(bContext *C, wmOperator *op)
|
|||
uv_map_transform_center(scene, v3d, obedit, em, center, nullptr);
|
||||
|
||||
const bool fan = RNA_enum_get(op->ptr, "pole");
|
||||
const bool use_seams = RNA_boolean_get(op->ptr, "seam");
|
||||
|
||||
if (use_seams) {
|
||||
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
|
||||
}
|
||||
|
||||
float island_offset = 0.0f;
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (only_selected_uvs) {
|
||||
if (!uvedit_face_select_test(scene, efa, offsets)) {
|
||||
uvedit_face_select_disable(scene, em->bm, efa, offsets);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
uv_sphere_project(efa, center, rotmat, fan, offsets.uv);
|
||||
const float max_u = uv_sphere_project(scene,
|
||||
em->bm,
|
||||
efa,
|
||||
center,
|
||||
rotmat,
|
||||
fan,
|
||||
offsets,
|
||||
only_selected_uvs,
|
||||
use_seams,
|
||||
island_offset + 0.5f);
|
||||
island_offset = ceilf(max_ff(max_u, island_offset));
|
||||
}
|
||||
|
||||
const bool per_face_aspect = true;
|
||||
|
@ -2906,25 +3011,92 @@ void UV_OT_sphere_project(wmOperatorType *ot)
|
|||
/** \name Cylinder UV Project Operator
|
||||
* \{ */
|
||||
|
||||
static void uv_cylinder_project(BMFace *efa,
|
||||
const float center[3],
|
||||
const float rotmat[3][3],
|
||||
const bool fan,
|
||||
const int cd_loop_uv_offset)
|
||||
/* See #uv_sphere_project for description of parameters. */
|
||||
static float uv_cylinder_project(const Scene *scene,
|
||||
BMesh *bm,
|
||||
BMFace *efa_init,
|
||||
const float center[3],
|
||||
const float rotmat[3][3],
|
||||
const bool fan,
|
||||
const BMUVOffsets offsets,
|
||||
const bool only_selected_uvs,
|
||||
const bool use_seams,
|
||||
const float branch_init)
|
||||
{
|
||||
blender::Array<bool, BM_DEFAULT_NGON_STACK_SIZE> regular(efa->len);
|
||||
int i;
|
||||
BMLoop *l;
|
||||
BMIter iter;
|
||||
BM_ITER_ELEM_INDEX (l, &iter, efa, BM_LOOPS_OF_FACE, i) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
||||
float pv[3];
|
||||
sub_v3_v3v3(pv, l->v->co, center);
|
||||
mul_m3_v3(rotmat, pv);
|
||||
regular[i] = map_to_tube(&luv[0], &luv[1], pv[0], pv[1], pv[2]);
|
||||
float max_u = 0.0f;
|
||||
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
return max_u;
|
||||
}
|
||||
|
||||
uv_map_mirror(efa, regular.data(), fan, cd_loop_uv_offset);
|
||||
/* Similar to BM_mesh_calc_face_groups with added connectivity information. */
|
||||
|
||||
blender::Vector<uv_face_branch> stack;
|
||||
|
||||
stack.append({efa_init, branch_init});
|
||||
|
||||
while (stack.size()) {
|
||||
uv_face_branch face_branch = stack.pop_last();
|
||||
BMFace *efa = face_branch.efa;
|
||||
|
||||
if (use_seams) {
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
|
||||
continue; /* Faces might be in the stack more than once. */
|
||||
}
|
||||
|
||||
BM_elem_flag_set(efa, BM_ELEM_TAG, true); /* Visited, don't consider again. */
|
||||
}
|
||||
|
||||
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
continue; /* Unselected face, ignore. */
|
||||
}
|
||||
|
||||
if (only_selected_uvs) {
|
||||
if (!uvedit_face_select_test(scene, efa, offsets)) {
|
||||
uvedit_face_select_disable(scene, bm, efa, offsets);
|
||||
continue; /* Unselected UV, ignore. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember which UVs are at the pole. */
|
||||
blender::Array<bool, BM_DEFAULT_NGON_STACK_SIZE> regular(efa->len);
|
||||
|
||||
int i;
|
||||
BMLoop *l;
|
||||
BMIter iter;
|
||||
BM_ITER_ELEM_INDEX (l, &iter, efa, BM_LOOPS_OF_FACE, i) {
|
||||
float *luv = BM_ELEM_CD_GET_FLOAT_P(l, offsets.uv);
|
||||
float pv[3];
|
||||
sub_v3_v3v3(pv, l->v->co, center);
|
||||
mul_m3_v3(rotmat, pv);
|
||||
regular[i] = map_to_tube(&luv[0], &luv[1], pv[0], pv[1], pv[2]);
|
||||
|
||||
if (!use_seams) {
|
||||
continue; /* Nothing more to do. */
|
||||
}
|
||||
|
||||
/* Move UV to correct branch. */
|
||||
luv[0] = luv[0] + ceilf(face_branch.branch - 0.5f - luv[0]);
|
||||
max_u = max_ff(max_u, luv[0]);
|
||||
|
||||
BMEdge *edge = l->e;
|
||||
if (BM_elem_flag_test(edge, BM_ELEM_SEAM)) {
|
||||
continue; /* Stop flood fill at seams. */
|
||||
}
|
||||
|
||||
/* Extend flood fill by pushing to stack. */
|
||||
BMFace *efa2;
|
||||
BMIter iter2;
|
||||
BM_ITER_ELEM (efa2, &iter2, edge, BM_FACES_OF_EDGE) {
|
||||
if (!BM_elem_flag_test(efa2, BM_ELEM_TAG)) {
|
||||
stack.append({efa2, luv[0]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uv_map_mirror(efa, regular.data(), fan, offsets.uv);
|
||||
}
|
||||
|
||||
return max_u;
|
||||
}
|
||||
|
||||
static int cylinder_project_exec(bContext *C, wmOperator *op)
|
||||
|
@ -2964,6 +3136,13 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
|
|||
uv_map_transform_center(scene, v3d, obedit, em, center, nullptr);
|
||||
|
||||
const bool fan = RNA_enum_get(op->ptr, "pole");
|
||||
const bool use_seams = RNA_boolean_get(op->ptr, "seam");
|
||||
|
||||
if (use_seams) {
|
||||
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
|
||||
}
|
||||
|
||||
float island_offset = 0.0f;
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
|
@ -2975,7 +3154,17 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
|
|||
continue;
|
||||
}
|
||||
|
||||
uv_cylinder_project(efa, center, rotmat, fan, offsets.uv);
|
||||
const float max_u = uv_cylinder_project(scene,
|
||||
em->bm,
|
||||
efa,
|
||||
center,
|
||||
rotmat,
|
||||
fan,
|
||||
offsets,
|
||||
only_selected_uvs,
|
||||
use_seams,
|
||||
island_offset + 0.5f);
|
||||
island_offset = ceilf(max_ff(max_u, island_offset));
|
||||
}
|
||||
|
||||
const bool per_face_aspect = true;
|
||||
|
|
|
@ -49,7 +49,7 @@ set(SRC
|
|||
GEO_subdivide_curves.hh
|
||||
GEO_trim_curves.hh
|
||||
GEO_uv_pack.hh
|
||||
GEO_uv_parametrizer.h
|
||||
GEO_uv_parametrizer.hh
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_sys_types.h" /* for intptr_t support */
|
||||
|
||||
/** \file
|
||||
* \ingroup geo
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */
|
||||
typedef uintptr_t ParamKey; /* Key (hash) for identifying verts and faces. */
|
||||
#define PARAM_KEY_MAX UINTPTR_MAX
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Chart Construction:
|
||||
*
|
||||
* Faces and seams may only be added between #GEO_uv_parametrizer_construct_begin and
|
||||
* #GEO_uv_parametrizer_construct_end.
|
||||
*
|
||||
* The pointers to `co` and `uv` are stored, rather than being copied. Vertices are implicitly
|
||||
* created.
|
||||
*
|
||||
* In #GEO_uv_parametrizer_construct_end the mesh will be split up according to the seams. The
|
||||
* resulting charts must be manifold, connected and open (at least one boundary loop). The output
|
||||
* will be written to the `uv` pointers.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
ParamHandle *GEO_uv_parametrizer_construct_begin(void);
|
||||
|
||||
void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy);
|
||||
|
||||
void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
|
||||
|
||||
ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
|
||||
|
||||
void GEO_uv_parametrizer_face_add(ParamHandle *handle,
|
||||
const ParamKey key,
|
||||
const int nverts,
|
||||
const ParamKey *vkeys,
|
||||
const float **co,
|
||||
float **uv, /* Output will eventually be written to `uv`. */
|
||||
const bool *pin,
|
||||
const bool *select);
|
||||
|
||||
void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys);
|
||||
|
||||
void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
|
||||
bool fill,
|
||||
bool topology_from_uvs,
|
||||
int *count_fail);
|
||||
void GEO_uv_parametrizer_delete(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Least Squares Conformal Maps:
|
||||
*
|
||||
* Charts with less than two pinned vertices are assigned two pins. LSCM is divided to three steps:
|
||||
*
|
||||
* 1. Begin: compute matrix and its factorization (expensive).
|
||||
* 2. Solve using pinned coordinates (cheap).
|
||||
* 3. End: clean up.
|
||||
*
|
||||
* UV coordinates are allowed to change within begin/end, for quick re-solving.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf);
|
||||
void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed);
|
||||
void GEO_uv_parametrizer_lscm_end(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Stretch
|
||||
* \{ */
|
||||
|
||||
void GEO_uv_parametrizer_stretch_begin(ParamHandle *handle);
|
||||
void GEO_uv_parametrizer_stretch_blend(ParamHandle *handle, float blend);
|
||||
void GEO_uv_parametrizer_stretch_iter(ParamHandle *handle);
|
||||
void GEO_uv_parametrizer_stretch_end(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Packing
|
||||
* \{ */
|
||||
|
||||
void GEO_uv_parametrizer_pack(ParamHandle *handle,
|
||||
float margin,
|
||||
bool do_rotate,
|
||||
bool ignore_pinned);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Average area for all charts
|
||||
* \{ */
|
||||
|
||||
void GEO_uv_parametrizer_average(ParamHandle *handle,
|
||||
bool ignore_pinned,
|
||||
bool scale_uv,
|
||||
bool shear);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Simple x,y scale
|
||||
* \{ */
|
||||
|
||||
void GEO_uv_parametrizer_scale(ParamHandle *handle, float x, float y);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Flushing
|
||||
* \{ */
|
||||
|
||||
void GEO_uv_parametrizer_flush(ParamHandle *handle);
|
||||
void GEO_uv_parametrizer_flush_restore(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_sys_types.h" /* for intptr_t support */
|
||||
|
||||
/** \file
|
||||
* \ingroup geo
|
||||
*/
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
struct ParamHandle; /* Handle to an array of charts. */
|
||||
using ParamKey = uintptr_t; /* Key (hash) for identifying verts and faces. */
|
||||
#define PARAM_KEY_MAX UINTPTR_MAX
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Chart Construction:
|
||||
*
|
||||
* Faces and seams may only be added between #geometry::uv_parametrizer_construct_begin and
|
||||
* #geometry::uv_parametrizer_construct_end.
|
||||
*
|
||||
* The pointers to `co` and `uv` are stored, rather than being copied. Vertices are implicitly
|
||||
* created.
|
||||
*
|
||||
* In #geometry::uv_parametrizer_construct_end the mesh will be split up according to the seams.
|
||||
* The resulting charts must be manifold, connected and open (at least one boundary loop). The
|
||||
* output will be written to the `uv` pointers.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
ParamHandle *uv_parametrizer_construct_begin();
|
||||
|
||||
void uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy);
|
||||
|
||||
void uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
|
||||
|
||||
ParamKey uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
|
||||
|
||||
void uv_parametrizer_face_add(ParamHandle *handle,
|
||||
const ParamKey key,
|
||||
const int nverts,
|
||||
const ParamKey *vkeys,
|
||||
const float **co,
|
||||
float **uv, /* Output will eventually be written to `uv`. */
|
||||
const bool *pin,
|
||||
const bool *select);
|
||||
|
||||
void uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys);
|
||||
|
||||
void uv_parametrizer_construct_end(ParamHandle *handle,
|
||||
bool fill,
|
||||
bool topology_from_uvs,
|
||||
int *count_fail);
|
||||
void uv_parametrizer_delete(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Least Squares Conformal Maps:
|
||||
*
|
||||
* Charts with less than two pinned vertices are assigned two pins. LSCM is divided to three steps:
|
||||
*
|
||||
* 1. Begin: compute matrix and its factorization (expensive).
|
||||
* 2. Solve using pinned coordinates (cheap).
|
||||
* 3. End: clean up.
|
||||
*
|
||||
* UV coordinates are allowed to change within begin/end, for quick re-solving.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf);
|
||||
void uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed);
|
||||
void uv_parametrizer_lscm_end(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Stretch
|
||||
* \{ */
|
||||
|
||||
void uv_parametrizer_stretch_begin(ParamHandle *handle);
|
||||
void uv_parametrizer_stretch_blend(ParamHandle *handle, float blend);
|
||||
void uv_parametrizer_stretch_iter(ParamHandle *handle);
|
||||
void uv_parametrizer_stretch_end(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Packing
|
||||
* \{ */
|
||||
|
||||
void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Average area for all charts
|
||||
* \{ */
|
||||
|
||||
void uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned, bool scale_uv, bool shear);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Simple x,y scale
|
||||
* \{ */
|
||||
|
||||
void uv_parametrizer_scale(ParamHandle *handle, float x, float y);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Flushing
|
||||
* \{ */
|
||||
|
||||
void uv_parametrizer_flush(ParamHandle *handle);
|
||||
void uv_parametrizer_flush_restore(ParamHandle *handle);
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::geometry
|
|
@ -152,7 +152,7 @@ static float pack_islands_margin_fraction(const Span<PackIsland *> &island_vecto
|
|||
static float calc_margin_from_aabb_length_sum(const Span<PackIsland *> &island_vector,
|
||||
const UVPackIsland_Params ¶ms)
|
||||
{
|
||||
/* Logic matches behavior from #GEO_uv_parametrizer_pack.
|
||||
/* Logic matches behavior from #geometry::uv_parametrizer_pack.
|
||||
* Attempt to give predictable results not dependent on current UV scale by using
|
||||
* `aabb_length_sum` (was "`area`") to multiply the margin by the length (was "area"). */
|
||||
double aabb_length_sum = 0.0f;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* \ingroup eduv
|
||||
*/
|
||||
|
||||
#include "GEO_uv_parametrizer.h"
|
||||
#include "GEO_uv_parametrizer.hh"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_convexhull_2d.h"
|
||||
|
@ -22,6 +22,8 @@
|
|||
|
||||
/* Utils */
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
#define param_assert(condition) \
|
||||
if (!(condition)) { /* `printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();` */ \
|
||||
} \
|
||||
|
@ -31,18 +33,18 @@
|
|||
|
||||
/* Special Purpose Hash */
|
||||
|
||||
typedef uintptr_t PHashKey;
|
||||
using PHashKey = uintptr_t;
|
||||
|
||||
typedef struct PHashLink {
|
||||
struct PHashLink {
|
||||
struct PHashLink *next;
|
||||
PHashKey key;
|
||||
} PHashLink;
|
||||
};
|
||||
|
||||
typedef struct PHash {
|
||||
struct PHash {
|
||||
PHashLink **list;
|
||||
PHashLink **buckets;
|
||||
int size, cursize, cursize_id;
|
||||
} PHash;
|
||||
};
|
||||
|
||||
/* Simplices */
|
||||
|
||||
|
@ -170,7 +172,7 @@ struct ParamHandle {
|
|||
PHash *hash_edges;
|
||||
PHash *hash_faces;
|
||||
|
||||
struct GHash *pin_hash;
|
||||
GHash *pin_hash;
|
||||
int unique_pin_count;
|
||||
|
||||
PChart **charts;
|
||||
|
@ -1188,7 +1190,7 @@ static void p_chart_fill_boundary(ParamHandle *handle, PChart *chart, PEdge *be,
|
|||
PEdge *e, *e1, *e2;
|
||||
|
||||
PFace *f;
|
||||
struct Heap *heap = BLI_heap_new();
|
||||
Heap *heap = BLI_heap_new();
|
||||
float angle;
|
||||
|
||||
e = be;
|
||||
|
@ -2263,7 +2265,7 @@ static void p_chart_simplify(PChart *chart)
|
|||
|
||||
#define ABF_MAX_ITER 20
|
||||
|
||||
using PAbfSystem = struct PAbfSystem {
|
||||
struct PAbfSystem {
|
||||
int ninterior, nfaces, nangles;
|
||||
float *alpha, *beta, *sine, *cosine, *weight;
|
||||
float *bAlpha, *bTriangle, *bInterior;
|
||||
|
@ -3654,7 +3656,7 @@ static void p_chart_rotate_fit_aabb(PChart *chart)
|
|||
|
||||
/* Exported */
|
||||
|
||||
ParamHandle *GEO_uv_parametrizer_construct_begin()
|
||||
ParamHandle *uv_parametrizer_construct_begin()
|
||||
{
|
||||
ParamHandle *handle = new ParamHandle();
|
||||
handle->construction_chart = (PChart *)MEM_callocN(sizeof(PChart), "PChart");
|
||||
|
@ -3672,13 +3674,13 @@ ParamHandle *GEO_uv_parametrizer_construct_begin()
|
|||
return handle;
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_aspect_ratio(ParamHandle *phandle, float aspx, float aspy)
|
||||
void uv_parametrizer_aspect_ratio(ParamHandle *phandle, float aspx, float aspy)
|
||||
{
|
||||
phandle->aspx = aspx;
|
||||
phandle->aspy = aspy;
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_delete(ParamHandle *phandle)
|
||||
void uv_parametrizer_delete(ParamHandle *phandle)
|
||||
{
|
||||
if (!phandle) {
|
||||
return;
|
||||
|
@ -3714,7 +3716,7 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle)
|
|||
delete phandle;
|
||||
}
|
||||
|
||||
using GeoUVPinIndex = struct GeoUVPinIndex {
|
||||
struct GeoUVPinIndex {
|
||||
struct GeoUVPinIndex *next;
|
||||
float uv[2];
|
||||
ParamKey reindex;
|
||||
|
@ -3729,7 +3731,7 @@ using GeoUVPinIndex = struct GeoUVPinIndex {
|
|||
* For everything else, just return the #BMVert index.
|
||||
* Note that #ParamKeys will eventually be hashed, so they don't need to be contiguous.
|
||||
*/
|
||||
ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
|
||||
ParamKey uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
|
||||
{
|
||||
if (!handle->pin_hash) {
|
||||
return bmvertindex; /* No verts pinned. */
|
||||
|
@ -3765,7 +3767,7 @@ static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2]
|
|||
return pinuv;
|
||||
}
|
||||
|
||||
void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
|
||||
void uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
|
||||
{
|
||||
if (!handle->pin_hash) {
|
||||
handle->pin_hash = BLI_ghash_int_new("uv pin reindex");
|
||||
|
@ -3848,20 +3850,20 @@ static void p_add_ngon(ParamHandle *handle,
|
|||
bool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
|
||||
bool tri_select[3] = {select[v0], select[v1], select[v2]};
|
||||
|
||||
GEO_uv_parametrizer_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select);
|
||||
uv_parametrizer_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select);
|
||||
}
|
||||
|
||||
BLI_memarena_clear(arena);
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
|
||||
const ParamKey key,
|
||||
const int nverts,
|
||||
const ParamKey *vkeys,
|
||||
const float **co,
|
||||
float **uv,
|
||||
const bool *pin,
|
||||
const bool *select)
|
||||
void uv_parametrizer_face_add(ParamHandle *phandle,
|
||||
const ParamKey key,
|
||||
const int nverts,
|
||||
const ParamKey *vkeys,
|
||||
const float **co,
|
||||
float **uv,
|
||||
const bool *pin,
|
||||
const bool *select)
|
||||
{
|
||||
BLI_assert(nverts >= 3);
|
||||
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
|
||||
|
@ -3870,7 +3872,7 @@ void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
|
|||
/* Protect against (manifold) geometry which has a non-manifold triangulation.
|
||||
* See #102543. */
|
||||
|
||||
blender::Vector<int, 32> permute;
|
||||
Vector<int, 32> permute;
|
||||
permute.reserve(nverts);
|
||||
for (int i = 0; i < nverts; i++) {
|
||||
permute.append_unchecked(i);
|
||||
|
@ -3894,7 +3896,7 @@ void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
|
|||
|
||||
/* An existing triangle has already been inserted.
|
||||
* As a heuristic, attempt to add the *previous* triangle.
|
||||
* NOTE: Should probably call `GEO_uv_parametrizer_face_add`
|
||||
* NOTE: Should probably call `uv_parametrizer_face_add`
|
||||
* instead of `p_face_add_construct`. */
|
||||
int iprev = permute[(i + pm - 1) % pm];
|
||||
p_face_add_construct(phandle, key, vkeys, co, uv, iprev, i0, i1, pin, select);
|
||||
|
@ -3907,11 +3909,11 @@ void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
|
|||
if (permute.size() != nverts) {
|
||||
int pm = permute.size();
|
||||
/* Add the remaining pm-gon. */
|
||||
blender::Array<ParamKey> vkeys_sub(pm);
|
||||
blender::Array<const float *> co_sub(pm);
|
||||
blender::Array<float *> uv_sub(pm);
|
||||
blender::Array<bool> pin_sub(pm);
|
||||
blender::Array<bool> select_sub(pm);
|
||||
Array<ParamKey> vkeys_sub(pm);
|
||||
Array<const float *> co_sub(pm);
|
||||
Array<float *> uv_sub(pm);
|
||||
Array<bool> pin_sub(pm);
|
||||
Array<bool> select_sub(pm);
|
||||
for (int i = 0; i < pm; i++) {
|
||||
int j = permute[i];
|
||||
vkeys_sub[i] = vkeys[j];
|
||||
|
@ -3942,7 +3944,7 @@ void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys)
|
||||
void uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys)
|
||||
{
|
||||
PEdge *e;
|
||||
|
||||
|
@ -3954,10 +3956,10 @@ void GEO_uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys)
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
|
||||
bool fill,
|
||||
bool topology_from_uvs,
|
||||
int *count_fail)
|
||||
void uv_parametrizer_construct_end(ParamHandle *phandle,
|
||||
bool fill,
|
||||
bool topology_from_uvs,
|
||||
int *count_fail)
|
||||
{
|
||||
PChart *chart = phandle->construction_chart;
|
||||
int i, j;
|
||||
|
@ -4007,7 +4009,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
|
|||
phandle->state = PHANDLE_STATE_CONSTRUCTED;
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
|
||||
void uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
|
||||
{
|
||||
param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
|
||||
phandle->state = PHANDLE_STATE_LSCM;
|
||||
|
@ -4020,7 +4022,7 @@ void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, int *count_failed)
|
||||
void uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, int *count_failed)
|
||||
{
|
||||
param_assert(phandle->state == PHANDLE_STATE_LSCM);
|
||||
|
||||
|
@ -4056,7 +4058,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_lscm_end(ParamHandle *phandle)
|
||||
void uv_parametrizer_lscm_end(ParamHandle *phandle)
|
||||
{
|
||||
BLI_assert(phandle->state == PHANDLE_STATE_LSCM);
|
||||
|
||||
|
@ -4070,7 +4072,7 @@ void GEO_uv_parametrizer_lscm_end(ParamHandle *phandle)
|
|||
phandle->state = PHANDLE_STATE_CONSTRUCTED;
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_stretch_begin(ParamHandle *phandle)
|
||||
void uv_parametrizer_stretch_begin(ParamHandle *phandle)
|
||||
{
|
||||
PChart *chart;
|
||||
PVert *v;
|
||||
|
@ -4099,13 +4101,13 @@ void GEO_uv_parametrizer_stretch_begin(ParamHandle *phandle)
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_stretch_blend(ParamHandle *phandle, float blend)
|
||||
void uv_parametrizer_stretch_blend(ParamHandle *phandle, float blend)
|
||||
{
|
||||
param_assert(phandle->state == PHANDLE_STATE_STRETCH);
|
||||
phandle->blend = blend;
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_stretch_iter(ParamHandle *phandle)
|
||||
void uv_parametrizer_stretch_iter(ParamHandle *phandle)
|
||||
{
|
||||
PChart *chart;
|
||||
int i;
|
||||
|
@ -4118,7 +4120,7 @@ void GEO_uv_parametrizer_stretch_iter(ParamHandle *phandle)
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_stretch_end(ParamHandle *phandle)
|
||||
void uv_parametrizer_stretch_end(ParamHandle *phandle)
|
||||
{
|
||||
param_assert(phandle->state == PHANDLE_STATE_STRETCH);
|
||||
phandle->state = PHANDLE_STATE_CONSTRUCTED;
|
||||
|
@ -4141,10 +4143,7 @@ static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pi
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_pack(ParamHandle *handle,
|
||||
float margin,
|
||||
bool do_rotate,
|
||||
bool ignore_pinned)
|
||||
void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
|
||||
{
|
||||
if (handle->ncharts == 0) {
|
||||
return;
|
||||
|
@ -4156,9 +4155,9 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
|
|||
}
|
||||
|
||||
if (handle->aspx != handle->aspy) {
|
||||
GEO_uv_parametrizer_scale(handle, 1.0f / handle->aspx, 1.0f / handle->aspy);
|
||||
uv_parametrizer_scale(handle, 1.0f / handle->aspx, 1.0f / handle->aspy);
|
||||
}
|
||||
blender::Vector<blender::geometry::PackIsland *> pack_island_vector;
|
||||
Vector<PackIsland *> pack_island_vector;
|
||||
int unpacked = 0;
|
||||
for (int i = 0; i < handle->ncharts; i++) {
|
||||
PChart *chart = handle->charts[i];
|
||||
|
@ -4168,7 +4167,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
|
|||
continue;
|
||||
}
|
||||
|
||||
blender::geometry::PackIsland *pack_island = new blender::geometry::PackIsland();
|
||||
geometry::PackIsland *pack_island = new geometry::PackIsland();
|
||||
pack_island_vector.append(pack_island);
|
||||
|
||||
float minv[2];
|
||||
|
@ -4198,7 +4197,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
|
|||
|
||||
for (int64_t i : pack_island_vector.index_range()) {
|
||||
BoxPack *box = box_array + i;
|
||||
blender::geometry::PackIsland *pack_island = pack_island_vector[box->index];
|
||||
PackIsland *pack_island = pack_island_vector[box->index];
|
||||
pack_island->bounds_rect.xmin = box->x;
|
||||
pack_island->bounds_rect.ymin = box->y;
|
||||
pack_island->bounds_rect.xmax = box->x + box->w;
|
||||
|
@ -4213,7 +4212,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
|
|||
unpacked++;
|
||||
continue;
|
||||
}
|
||||
blender::geometry::PackIsland *pack_island = pack_island_vector[i - unpacked];
|
||||
PackIsland *pack_island = pack_island_vector[i - unpacked];
|
||||
|
||||
float minv[2];
|
||||
float maxv[2];
|
||||
|
@ -4237,14 +4236,11 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
|
|||
}
|
||||
MEM_freeN(box_array);
|
||||
if (handle->aspx != handle->aspy) {
|
||||
GEO_uv_parametrizer_scale(handle, handle->aspx, handle->aspy);
|
||||
uv_parametrizer_scale(handle, handle->aspx, handle->aspy);
|
||||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_average(ParamHandle *phandle,
|
||||
bool ignore_pinned,
|
||||
bool scale_uv,
|
||||
bool shear)
|
||||
void uv_parametrizer_average(ParamHandle *phandle, bool ignore_pinned, bool scale_uv, bool shear)
|
||||
{
|
||||
int i;
|
||||
float tot_area_3d = 0.0f;
|
||||
|
@ -4384,7 +4380,7 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle,
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_scale(ParamHandle *phandle, float x, float y)
|
||||
void uv_parametrizer_scale(ParamHandle *phandle, float x, float y)
|
||||
{
|
||||
PChart *chart;
|
||||
int i;
|
||||
|
@ -4395,7 +4391,7 @@ void GEO_uv_parametrizer_scale(ParamHandle *phandle, float x, float y)
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_flush(ParamHandle *phandle)
|
||||
void uv_parametrizer_flush(ParamHandle *phandle)
|
||||
{
|
||||
PChart *chart;
|
||||
int i;
|
||||
|
@ -4411,7 +4407,7 @@ void GEO_uv_parametrizer_flush(ParamHandle *phandle)
|
|||
}
|
||||
}
|
||||
|
||||
void GEO_uv_parametrizer_flush_restore(ParamHandle *phandle)
|
||||
void uv_parametrizer_flush_restore(ParamHandle *phandle)
|
||||
{
|
||||
PChart *chart;
|
||||
PFace *f;
|
||||
|
@ -4425,3 +4421,5 @@ void GEO_uv_parametrizer_flush_restore(ParamHandle *phandle)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::geometry
|
||||
|
|
|
@ -650,7 +650,6 @@ typedef enum eBrushCurvesSculptDensityMode {
|
|||
} eBrushCurvesSculptDensityMode;
|
||||
|
||||
#define MAX_BRUSH_PIXEL_RADIUS 500
|
||||
#define GP_MAX_BRUSH_PIXEL_RADIUS 1000
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
/** \file
|
||||
* \ingroup DNA
|
||||
*
|
||||
* Types defined in this file are deprecated, converted into modifiers on load.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
@ -57,12 +59,14 @@ typedef struct Effect {
|
|||
struct Effect *next, *prev;
|
||||
short type, flag, buttype;
|
||||
char _pad0[2];
|
||||
|
||||
} Effect;
|
||||
|
||||
typedef struct BuildEff {
|
||||
/* NOTE: match #Effect. */
|
||||
struct BuildEff *next, *prev;
|
||||
short type, flag, buttype;
|
||||
/* End header. */
|
||||
|
||||
char _pad0[2];
|
||||
|
||||
float len, sfra;
|
||||
|
@ -81,8 +85,12 @@ typedef struct Particle {
|
|||
struct Collection;
|
||||
|
||||
typedef struct PartEff {
|
||||
/* NOTE: match #Effect. */
|
||||
struct PartEff *next, *prev;
|
||||
short type, flag, buttype, stype, vertgroup, userjit;
|
||||
short type, flag, buttype;
|
||||
/* End header. */
|
||||
|
||||
short stype, vertgroup, userjit;
|
||||
|
||||
float sta, end, lifetime;
|
||||
int totpart, totkey, seed;
|
||||
|
@ -111,8 +119,10 @@ typedef struct PartEff {
|
|||
} PartEff;
|
||||
|
||||
typedef struct WaveEff {
|
||||
/* NOTE: match #Effect. */
|
||||
struct WaveEff *next, *prev;
|
||||
short type, flag, buttype, stype;
|
||||
/* End header. */
|
||||
|
||||
float startx, starty, height, width;
|
||||
float narrow, speed, minfac, damp;
|
||||
|
|
|
@ -306,12 +306,12 @@ typedef struct Ipo {
|
|||
#define WO_MISTSTA 10
|
||||
#define WO_MISTHI 11
|
||||
|
||||
/* Stars are deprecated */
|
||||
#define WO_STAR_R 12
|
||||
#define WO_STAR_G 13
|
||||
#define WO_STAR_B 14
|
||||
#define WO_STARDIST 15
|
||||
#define WO_STARSIZE 16
|
||||
/* Stars are deprecated & unused. */
|
||||
// #define WO_STAR_R 12
|
||||
// #define WO_STAR_G 13
|
||||
// #define WO_STAR_B 14
|
||||
// #define WO_STARDIST 15
|
||||
// #define WO_STARSIZE 16
|
||||
|
||||
/* ********** Light (ID_LA) ********** */
|
||||
|
||||
|
|
|
@ -411,7 +411,8 @@ enum {
|
|||
|
||||
#define ME_POLY_LOOP_PREV(mloop, poly, i) \
|
||||
(&(mloop)[(poly)->loopstart + (((i) + (poly)->totloop - 1) % (poly)->totloop)])
|
||||
#define ME_POLY_LOOP_NEXT(mloop, poly, i) (&(mloop)[(poly)->loopstart + (((i) + 1) % (poly)->totloop)])
|
||||
#define ME_POLY_LOOP_NEXT(mloop, poly, i) \
|
||||
(&(mloop)[(poly)->loopstart + (((i) + 1) % (poly)->totloop)])
|
||||
|
||||
/** Number of tri's that make up this polygon once tessellated. */
|
||||
#define ME_POLY_TRI_TOT(poly) ((poly)->totloop - 2)
|
||||
|
|
|
@ -1016,7 +1016,12 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
|
|||
|
||||
static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool UNUSED(clear_proxy))
|
||||
{
|
||||
BKE_lib_id_make_local(bmain, self, 0);
|
||||
if (ID_IS_LINKED(self)) {
|
||||
BKE_lib_id_make_local(bmain, self, 0);
|
||||
}
|
||||
else if (ID_IS_OVERRIDE_LIBRARY_REAL(self)) {
|
||||
BKE_lib_override_library_make_local(self);
|
||||
}
|
||||
|
||||
ID *ret_id = self->newid ? self->newid : self;
|
||||
BKE_id_newptr_and_tag_clear(self);
|
||||
|
|
|
@ -107,7 +107,7 @@ static void smoothModifier_do(
|
|||
memset(accumulated_vecs_count, 0, sizeof(*accumulated_vecs_count) * (size_t)verts_num);
|
||||
}
|
||||
|
||||
for (const int i : edges.index_range()) {
|
||||
for (const int i : edges.index_range()) {
|
||||
float fvec[3];
|
||||
const uint idx1 = edges[i].v1;
|
||||
const uint idx2 = edges[i].v2;
|
||||
|
|
|
@ -465,10 +465,9 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
|||
}
|
||||
}
|
||||
|
||||
MEdge *ed;
|
||||
for (i = 0, ed = &edges[edges_num]; i < edges_num; i++, ed++) {
|
||||
ed->v1 += verts_num;
|
||||
ed->v2 += verts_num;
|
||||
for (MEdge &edge : edges.slice(edges_num, edges_num)) {
|
||||
edge.v1 += verts_num;
|
||||
edge.v2 += verts_num;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1047,10 +1046,11 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
|||
origindex_edge = static_cast<int *>(
|
||||
CustomData_get_layer_for_write(&result->edata, CD_ORIGINDEX, result->totedge));
|
||||
orig_ed = (origindex_edge) ? &origindex_edge[(edges_num * stride) + newEdges] : nullptr;
|
||||
MEdge *ed = &edges[(edges_num * stride) + newEdges]; /* start after copied edges */
|
||||
for (i = 0; i < rimVerts; i++, ed++) {
|
||||
ed->v1 = new_vert_arr[i];
|
||||
ed->v2 = (do_shell ? new_vert_arr[i] : i) + verts_num;
|
||||
/* Start after copied edges. */
|
||||
int new_edge_index = int(edges_num * stride + newEdges);
|
||||
for (i = 0; i < rimVerts; i++) {
|
||||
edges[new_edge_index].v1 = new_vert_arr[i];
|
||||
edges[new_edge_index].v2 = (do_shell ? new_vert_arr[i] : i) + verts_num;
|
||||
|
||||
if (orig_ed) {
|
||||
*orig_ed = ORIGINDEX_NONE;
|
||||
|
@ -1058,15 +1058,16 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
|||
}
|
||||
|
||||
if (crease_rim) {
|
||||
result_edge_crease[ed - edges.data()] = crease_rim;
|
||||
result_edge_crease[new_edge_index] = crease_rim;
|
||||
}
|
||||
new_edge_index++;
|
||||
}
|
||||
|
||||
/* faces */
|
||||
MPoly *poly = &polys[polys_num * stride];
|
||||
MLoop *ml = &loops[loops_num * stride];
|
||||
int new_poly_index = int(polys_num * stride);
|
||||
blender::MutableSpan<MLoop> new_loops = loops.drop_front(loops_num * stride);
|
||||
j = 0;
|
||||
for (i = 0; i < newPolys; i++, poly++) {
|
||||
for (i = 0; i < newPolys; i++) {
|
||||
uint eidx = new_edge_arr[i];
|
||||
uint pidx = edge_users[eidx];
|
||||
int k1, k2;
|
||||
|
@ -1080,24 +1081,25 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
|||
flip = false;
|
||||
}
|
||||
|
||||
ed = &edges[eidx];
|
||||
const MEdge &edge = edges[eidx];
|
||||
|
||||
/* copy most of the face settings */
|
||||
CustomData_copy_data(
|
||||
&mesh->pdata, &result->pdata, int(pidx), int((polys_num * stride) + i), 1);
|
||||
poly->loopstart = int(j + (loops_num * stride));
|
||||
poly->flag = polys[pidx].flag;
|
||||
polys[new_poly_index].loopstart = int(j + (loops_num * stride));
|
||||
polys[new_poly_index].flag = polys[pidx].flag;
|
||||
|
||||
/* notice we use 'poly->totloop' which is later overwritten,
|
||||
/* notice we use 'polys[new_poly_index].totloop' which is later overwritten,
|
||||
* we could lookup the original face but there's no point since this is a copy
|
||||
* and will have the same value, just take care when changing order of assignment */
|
||||
|
||||
/* prev loop */
|
||||
k1 = polys[pidx].loopstart + (((edge_order[eidx] - 1) + poly->totloop) % poly->totloop);
|
||||
k1 = polys[pidx].loopstart + (((edge_order[eidx] - 1) + polys[new_poly_index].totloop) %
|
||||
polys[new_poly_index].totloop);
|
||||
|
||||
k2 = polys[pidx].loopstart + (edge_order[eidx]);
|
||||
|
||||
poly->totloop = 4;
|
||||
polys[new_poly_index].totloop = 4;
|
||||
|
||||
CustomData_copy_data(&mesh->ldata, &result->ldata, k2, int((loops_num * stride) + j + 0), 1);
|
||||
CustomData_copy_data(&mesh->ldata, &result->ldata, k1, int((loops_num * stride) + j + 1), 1);
|
||||
|
@ -1105,45 +1107,45 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
|||
CustomData_copy_data(&mesh->ldata, &result->ldata, k2, int((loops_num * stride) + j + 3), 1);
|
||||
|
||||
if (flip == false) {
|
||||
ml[j].v = ed->v1;
|
||||
ml[j++].e = eidx;
|
||||
new_loops[j].v = edge.v1;
|
||||
new_loops[j++].e = eidx;
|
||||
|
||||
ml[j].v = ed->v2;
|
||||
ml[j++].e = (edges_num * stride) + old_vert_arr[ed->v2] + newEdges;
|
||||
new_loops[j].v = edge.v2;
|
||||
new_loops[j++].e = (edges_num * stride) + old_vert_arr[edge.v2] + newEdges;
|
||||
|
||||
ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + verts_num;
|
||||
ml[j++].e = (do_shell ? eidx : i) + edges_num;
|
||||
new_loops[j].v = (do_shell ? edge.v2 : old_vert_arr[edge.v2]) + verts_num;
|
||||
new_loops[j++].e = (do_shell ? eidx : i) + edges_num;
|
||||
|
||||
ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + verts_num;
|
||||
ml[j++].e = (edges_num * stride) + old_vert_arr[ed->v1] + newEdges;
|
||||
new_loops[j].v = (do_shell ? edge.v1 : old_vert_arr[edge.v1]) + verts_num;
|
||||
new_loops[j++].e = (edges_num * stride) + old_vert_arr[edge.v1] + newEdges;
|
||||
}
|
||||
else {
|
||||
ml[j].v = ed->v2;
|
||||
ml[j++].e = eidx;
|
||||
new_loops[j].v = edge.v2;
|
||||
new_loops[j++].e = eidx;
|
||||
|
||||
ml[j].v = ed->v1;
|
||||
ml[j++].e = (edges_num * stride) + old_vert_arr[ed->v1] + newEdges;
|
||||
new_loops[j].v = edge.v1;
|
||||
new_loops[j++].e = (edges_num * stride) + old_vert_arr[edge.v1] + newEdges;
|
||||
|
||||
ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + verts_num;
|
||||
ml[j++].e = (do_shell ? eidx : i) + edges_num;
|
||||
new_loops[j].v = (do_shell ? edge.v1 : old_vert_arr[edge.v1]) + verts_num;
|
||||
new_loops[j++].e = (do_shell ? eidx : i) + edges_num;
|
||||
|
||||
ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + verts_num;
|
||||
ml[j++].e = (edges_num * stride) + old_vert_arr[ed->v2] + newEdges;
|
||||
new_loops[j].v = (do_shell ? edge.v2 : old_vert_arr[edge.v2]) + verts_num;
|
||||
new_loops[j++].e = (edges_num * stride) + old_vert_arr[edge.v2] + newEdges;
|
||||
}
|
||||
|
||||
if (origindex_edge) {
|
||||
origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
|
||||
origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;
|
||||
origindex_edge[new_loops[j - 3].e] = ORIGINDEX_NONE;
|
||||
origindex_edge[new_loops[j - 1].e] = ORIGINDEX_NONE;
|
||||
}
|
||||
|
||||
/* use the next material index if option enabled */
|
||||
if (mat_ofs_rim) {
|
||||
dst_material_index[poly - polys.data()] += mat_ofs_rim;
|
||||
CLAMP(dst_material_index[poly - polys.data()], 0, mat_nr_max);
|
||||
dst_material_index[new_poly_index] += mat_ofs_rim;
|
||||
CLAMP(dst_material_index[new_poly_index], 0, mat_nr_max);
|
||||
}
|
||||
if (crease_outer) {
|
||||
/* crease += crease_outer; without wrapping */
|
||||
float *cr = &(result_edge_crease[ed - edges.data()]);
|
||||
float *cr = &(result_edge_crease[eidx]);
|
||||
float tcr = *cr + crease_outer;
|
||||
*cr = tcr > 1.0f ? 1.0f : tcr;
|
||||
}
|
||||
|
@ -1158,34 +1160,36 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
|||
#ifdef SOLIDIFY_SIDE_NORMALS
|
||||
if (do_side_normals) {
|
||||
normal_quad_v3(nor,
|
||||
vert_positions[ml[j - 4].v],
|
||||
vert_positions[ml[j - 3].v],
|
||||
vert_positions[ml[j - 2].v],
|
||||
vert_positions[ml[j - 1].v]);
|
||||
vert_positions[new_loops[j - 4].v],
|
||||
vert_positions[new_loops[j - 3].v],
|
||||
vert_positions[new_loops[j - 2].v],
|
||||
vert_positions[new_loops[j - 1].v]);
|
||||
|
||||
add_v3_v3(edge_vert_nos[ed->v1], nor);
|
||||
add_v3_v3(edge_vert_nos[ed->v2], nor);
|
||||
add_v3_v3(edge_vert_nos[edge.v1], nor);
|
||||
add_v3_v3(edge_vert_nos[edge.v2], nor);
|
||||
}
|
||||
#endif
|
||||
|
||||
new_poly_index++;
|
||||
}
|
||||
|
||||
#ifdef SOLIDIFY_SIDE_NORMALS
|
||||
if (do_side_normals) {
|
||||
const MEdge *edge_orig = edges.data();
|
||||
ed = &edges[edges_num * stride];
|
||||
for (i = 0; i < rimVerts; i++, ed++, edge_orig++) {
|
||||
for (i = 0; i < rimVerts; i++) {
|
||||
const MEdge &edge_orig = edges[i];
|
||||
const MEdge &edge = edges[edges_num * stride + i];
|
||||
float nor_cpy[3];
|
||||
int k;
|
||||
|
||||
/* NOTE: only the first vertex (lower half of the index) is calculated. */
|
||||
BLI_assert(ed->v1 < verts_num);
|
||||
normalize_v3_v3(nor_cpy, edge_vert_nos[edge_orig->v1]);
|
||||
BLI_assert(edge.v1 < verts_num);
|
||||
normalize_v3_v3(nor_cpy, edge_vert_nos[edge_orig.v1]);
|
||||
|
||||
for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
|
||||
copy_v3_v3(nor, mesh_vert_normals[*(&ed->v1 + k)]);
|
||||
copy_v3_v3(nor, mesh_vert_normals[*(&edge.v1 + k)]);
|
||||
add_v3_v3(nor, nor_cpy);
|
||||
normalize_v3(nor);
|
||||
copy_v3_v3((float *)mesh_vert_normals[*(&ed->v1 + k)], nor);
|
||||
copy_v3_v3((float *)mesh_vert_normals[*(&edge.v1 + k)], nor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1800,7 +1800,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
|
|||
int k;
|
||||
for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) {
|
||||
const MEdge *edge = &orig_edges[(*edge_ptr)->old_edge];
|
||||
sub_v3_v3v3(tmp, orig_mvert_co[vm[edge->v1] == i ? edge->v2 : edge->v1], orig_mvert_co[i]);
|
||||
sub_v3_v3v3(
|
||||
tmp, orig_mvert_co[vm[edge->v1] == i ? edge->v2 : edge->v1], orig_mvert_co[i]);
|
||||
add_v3_v3(move_nor, tmp);
|
||||
}
|
||||
if (k == 1) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "GEO_uv_parametrizer.h"
|
||||
#include "GEO_uv_parametrizer.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
@ -56,10 +56,10 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
|||
evaluator.add_with_destination(uv_field, uv.as_mutable_span());
|
||||
evaluator.evaluate();
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
geometry::ParamHandle *handle = geometry::uv_parametrizer_construct_begin();
|
||||
for (const int poly_index : selection) {
|
||||
const MPoly &poly = polys[poly_index];
|
||||
Array<ParamKey, 16> mp_vkeys(poly.totloop);
|
||||
Array<geometry::ParamKey, 16> mp_vkeys(poly.totloop);
|
||||
Array<bool, 16> mp_pin(poly.totloop);
|
||||
Array<bool, 16> mp_select(poly.totloop);
|
||||
Array<const float *, 16> mp_co(poly.totloop);
|
||||
|
@ -72,20 +72,20 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
|||
mp_pin[i] = false;
|
||||
mp_select[i] = false;
|
||||
}
|
||||
GEO_uv_parametrizer_face_add(handle,
|
||||
poly_index,
|
||||
poly.totloop,
|
||||
mp_vkeys.data(),
|
||||
mp_co.data(),
|
||||
mp_uv.data(),
|
||||
mp_pin.data(),
|
||||
mp_select.data());
|
||||
geometry::uv_parametrizer_face_add(handle,
|
||||
poly_index,
|
||||
poly.totloop,
|
||||
mp_vkeys.data(),
|
||||
mp_co.data(),
|
||||
mp_uv.data(),
|
||||
mp_pin.data(),
|
||||
mp_select.data());
|
||||
}
|
||||
GEO_uv_parametrizer_construct_end(handle, true, true, nullptr);
|
||||
geometry::uv_parametrizer_construct_end(handle, true, true, nullptr);
|
||||
|
||||
GEO_uv_parametrizer_pack(handle, margin, rotate, true);
|
||||
GEO_uv_parametrizer_flush(handle);
|
||||
GEO_uv_parametrizer_delete(handle);
|
||||
geometry::uv_parametrizer_pack(handle, margin, rotate, true);
|
||||
geometry::uv_parametrizer_flush(handle);
|
||||
geometry::uv_parametrizer_delete(handle);
|
||||
|
||||
return mesh.attributes().adapt_domain<float3>(
|
||||
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "GEO_uv_parametrizer.h"
|
||||
#include "GEO_uv_parametrizer.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
@ -84,10 +84,10 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
|||
|
||||
Array<float3> uv(loops.size(), float3(0));
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
geometry::ParamHandle *handle = geometry::uv_parametrizer_construct_begin();
|
||||
for (const int poly_index : selection) {
|
||||
const MPoly &poly = polys[poly_index];
|
||||
Array<ParamKey, 16> mp_vkeys(poly.totloop);
|
||||
Array<geometry::ParamKey, 16> mp_vkeys(poly.totloop);
|
||||
Array<bool, 16> mp_pin(poly.totloop);
|
||||
Array<bool, 16> mp_select(poly.totloop);
|
||||
Array<const float *, 16> mp_co(poly.totloop);
|
||||
|
@ -100,31 +100,32 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
|||
mp_pin[i] = false;
|
||||
mp_select[i] = false;
|
||||
}
|
||||
GEO_uv_parametrizer_face_add(handle,
|
||||
poly_index,
|
||||
poly.totloop,
|
||||
mp_vkeys.data(),
|
||||
mp_co.data(),
|
||||
mp_uv.data(),
|
||||
mp_pin.data(),
|
||||
mp_select.data());
|
||||
geometry::uv_parametrizer_face_add(handle,
|
||||
poly_index,
|
||||
poly.totloop,
|
||||
mp_vkeys.data(),
|
||||
mp_co.data(),
|
||||
mp_uv.data(),
|
||||
mp_pin.data(),
|
||||
mp_select.data());
|
||||
}
|
||||
for (const int i : seam) {
|
||||
const MEdge &edge = edges[i];
|
||||
ParamKey vkeys[2]{edge.v1, edge.v2};
|
||||
GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
geometry::ParamKey vkeys[2]{edge.v1, edge.v2};
|
||||
geometry::uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
}
|
||||
/* TODO: once field input nodes are able to emit warnings (#94039), emit a
|
||||
* warning if we fail to solve an island. */
|
||||
GEO_uv_parametrizer_construct_end(handle, fill_holes, false, nullptr);
|
||||
geometry::uv_parametrizer_construct_end(handle, fill_holes, false, nullptr);
|
||||
|
||||
GEO_uv_parametrizer_lscm_begin(handle, false, method == GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED);
|
||||
GEO_uv_parametrizer_lscm_solve(handle, nullptr, nullptr);
|
||||
GEO_uv_parametrizer_lscm_end(handle);
|
||||
GEO_uv_parametrizer_average(handle, true, false, false);
|
||||
GEO_uv_parametrizer_pack(handle, margin, true, true);
|
||||
GEO_uv_parametrizer_flush(handle);
|
||||
GEO_uv_parametrizer_delete(handle);
|
||||
geometry::uv_parametrizer_lscm_begin(
|
||||
handle, false, method == GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED);
|
||||
geometry::uv_parametrizer_lscm_solve(handle, nullptr, nullptr);
|
||||
geometry::uv_parametrizer_lscm_end(handle);
|
||||
geometry::uv_parametrizer_average(handle, true, false, false);
|
||||
geometry::uv_parametrizer_pack(handle, margin, true, true);
|
||||
geometry::uv_parametrizer_flush(handle);
|
||||
geometry::uv_parametrizer_delete(handle);
|
||||
|
||||
return mesh.attributes().adapt_domain<float3>(
|
||||
VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
|
||||
|
|
|
@ -27,8 +27,8 @@ extern "C" {
|
|||
#define CLOTH_FORCE_SPRING_STRUCTURAL
|
||||
#define CLOTH_FORCE_SPRING_SHEAR
|
||||
#define CLOTH_FORCE_SPRING_BEND
|
||||
#define CLOTH_FORCE_SPRING_GOAL
|
||||
#define CLOTH_FORCE_EFFECTORS
|
||||
// #define CLOTH_FORCE_SPRING_GOAL /* UNUSED. */
|
||||
// #define CLOTH_FORCE_EFFECTORS /* UNUSED. */
|
||||
|
||||
//#define IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
|
||||
|
||||
|
|
|
@ -83,26 +83,6 @@
|
|||
# include "BLI_threads.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* When windows are activated, simulate modifier press/release to match the current state of
|
||||
* held modifier keys, see #40317.
|
||||
*/
|
||||
#define USE_WIN_ACTIVATE
|
||||
|
||||
/**
|
||||
* When the window is de-activated, release all held modifiers.
|
||||
*
|
||||
* Needed so events generated over unfocused (non-active) windows don't have modifiers held.
|
||||
* Since modifier press/release events aren't send to unfocused windows it's best to assume
|
||||
* modifiers are not pressed. This means when modifiers *are* held, events will incorrectly
|
||||
* reported as not being held. Since this is standard behavior for Linux/MS-Window,
|
||||
* opt to use this.
|
||||
*
|
||||
* NOTE(@ideasman42): Events generated for non-active windows are rare,
|
||||
* this happens when using the mouse-wheel over an unfocused window, see: #103722.
|
||||
*/
|
||||
#define USE_WIN_DEACTIVATE
|
||||
|
||||
/* the global to talk to ghost */
|
||||
static GHOST_SystemHandle g_system = NULL;
|
||||
#if !(defined(WIN32) || defined(__APPLE__))
|
||||
|
@ -172,6 +152,7 @@ enum ModSide {
|
|||
|
||||
static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
|
||||
static bool wm_window_timer(const bContext *C);
|
||||
static uint8_t wm_ghost_modifier_query(const enum ModSide side);
|
||||
|
||||
void wm_get_screensize(int *r_width, int *r_height)
|
||||
{
|
||||
|
@ -538,6 +519,106 @@ void WM_window_set_dpi(const wmWindow *win)
|
|||
U.widget_unit = (int)roundf(18.0f * U.dpi_fac) + (2 * pixelsize);
|
||||
}
|
||||
|
||||
/**
|
||||
* When windows are activated, simulate modifier press/release to match the current state of
|
||||
* held modifier keys, see #40317.
|
||||
*
|
||||
* NOTE(@ideasman42): There is a bug in Windows11 where Alt-Tab sends an Alt-press event
|
||||
* to the window after it's deactivated, this means window de-activation is not a fool-proof
|
||||
* way of ensuring modifier keys are cleared for inactive windows. So any event added to an
|
||||
* inactive window must run #wm_window_update_eventstate_modifiers first to ensure no modifier
|
||||
* keys are held. See: #105277.
|
||||
*/
|
||||
static void wm_window_update_eventstate_modifiers(wmWindowManager *wm, wmWindow *win)
|
||||
{
|
||||
const uint8_t keymodifier_sided[2] = {
|
||||
wm_ghost_modifier_query(MOD_SIDE_LEFT),
|
||||
wm_ghost_modifier_query(MOD_SIDE_RIGHT),
|
||||
};
|
||||
const uint8_t keymodifier = keymodifier_sided[0] | keymodifier_sided[1];
|
||||
const uint8_t keymodifier_eventstate = win->eventstate->modifier;
|
||||
if (keymodifier != keymodifier_eventstate) {
|
||||
GHOST_TEventKeyData kdata = {
|
||||
.key = GHOST_kKeyUnknown,
|
||||
.utf8_buf = {'\0'},
|
||||
.is_repeat = false,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
|
||||
if (keymodifier_eventstate & g_modifier_table[i].flag) {
|
||||
if ((keymodifier & g_modifier_table[i].flag) == 0) {
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
|
||||
kdata.key = g_modifier_table[i].ghost_key_pair[side];
|
||||
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata);
|
||||
/* Only ever send one release event
|
||||
* (currently releasing multiple isn't needed and only confuses logic). */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (keymodifier & g_modifier_table[i].flag) {
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if (keymodifier_sided[side] & g_modifier_table[i].flag) {
|
||||
kdata.key = g_modifier_table[i].ghost_key_pair[side];
|
||||
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyDown, &kdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the window is de-activated, release all held modifiers.
|
||||
*
|
||||
* Needed so events generated over unfocused (non-active) windows don't have modifiers held.
|
||||
* Since modifier press/release events aren't send to unfocused windows it's best to assume
|
||||
* modifiers are not pressed. This means when modifiers *are* held, events will incorrectly
|
||||
* reported as not being held. Since this is standard behavior for Linux/MS-Window,
|
||||
* opt to use this.
|
||||
*
|
||||
* NOTE(@ideasman42): Events generated for non-active windows are rare,
|
||||
* this happens when using the mouse-wheel over an unfocused window, see: #103722.
|
||||
*/
|
||||
static void wm_window_update_eventstate_modifiers_clear(wmWindowManager *wm, wmWindow *win)
|
||||
{
|
||||
/* Release all held modifiers before de-activating the window. */
|
||||
if (win->eventstate->modifier != 0) {
|
||||
const uint8_t keymodifier_eventstate = win->eventstate->modifier;
|
||||
const uint8_t keymodifier_l = wm_ghost_modifier_query(MOD_SIDE_LEFT);
|
||||
const uint8_t keymodifier_r = wm_ghost_modifier_query(MOD_SIDE_RIGHT);
|
||||
/* NOTE(@ideasman42): when non-zero, there are modifiers held in
|
||||
* `win->eventstate` which are not considered held by the GHOST internal state.
|
||||
* While this should not happen, it's important all modifier held in event-state
|
||||
* receive release events. Without this, so any events generated while the window
|
||||
* is *not* active will have modifiers held. */
|
||||
const uint8_t keymodifier_unhandled = keymodifier_eventstate &
|
||||
~(keymodifier_l | keymodifier_r);
|
||||
const uint8_t keymodifier_sided[2] = {
|
||||
keymodifier_l | keymodifier_unhandled,
|
||||
keymodifier_r,
|
||||
};
|
||||
GHOST_TEventKeyData kdata = {
|
||||
.key = GHOST_kKeyUnknown,
|
||||
.utf8_buf = {'\0'},
|
||||
.is_repeat = false,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
|
||||
if (keymodifier_eventstate & g_modifier_table[i].flag) {
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
|
||||
kdata.key = g_modifier_table[i].ghost_key_pair[side];
|
||||
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_window_update_eventstate(wmWindow *win)
|
||||
{
|
||||
/* Update mouse position when a window is activated. */
|
||||
|
@ -1144,40 +1225,7 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
|||
|
||||
switch (type) {
|
||||
case GHOST_kEventWindowDeactivate: {
|
||||
#ifdef USE_WIN_DEACTIVATE
|
||||
/* Release all held modifiers before de-activating the window. */
|
||||
if (win->eventstate->modifier != 0) {
|
||||
const uint8_t keymodifier_eventstate = win->eventstate->modifier;
|
||||
const uint8_t keymodifier_l = wm_ghost_modifier_query(MOD_SIDE_LEFT);
|
||||
const uint8_t keymodifier_r = wm_ghost_modifier_query(MOD_SIDE_RIGHT);
|
||||
/* NOTE(@ideasman42): when non-zero, there are modifiers held in
|
||||
* `win->eventstate` which are not considered held by the GHOST internal state.
|
||||
* While this should not happen, it's important all modifier held in event-state
|
||||
* receive release events. Without this, so any events generated while the window
|
||||
* is *not* active will have modifiers held. */
|
||||
const uint8_t keymodifier_unhandled = keymodifier_eventstate &
|
||||
~(keymodifier_l | keymodifier_r);
|
||||
const uint8_t keymodifier_sided[2] = {
|
||||
keymodifier_l | keymodifier_unhandled,
|
||||
keymodifier_r,
|
||||
};
|
||||
GHOST_TEventKeyData kdata = {
|
||||
.key = GHOST_kKeyUnknown,
|
||||
.utf8_buf = {'\0'},
|
||||
.is_repeat = false,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
|
||||
if (keymodifier_eventstate & g_modifier_table[i].flag) {
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
|
||||
kdata.key = g_modifier_table[i].ghost_key_pair[side];
|
||||
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* USE_WIN_DEACTIVATE */
|
||||
wm_window_update_eventstate_modifiers_clear(wm, win);
|
||||
|
||||
wm_event_add_ghostevent(wm, win, type, data);
|
||||
win->active = 0;
|
||||
|
@ -1185,62 +1233,18 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
|||
}
|
||||
case GHOST_kEventWindowActivate: {
|
||||
|
||||
/* No context change! C->wm->windrawable is drawable, or for area queues. */
|
||||
/* Ensure the event state matches modifiers (window was inactive). */
|
||||
wm_window_update_eventstate_modifiers(wm, win);
|
||||
/* Entering window, update mouse position (without sending an event). */
|
||||
wm_window_update_eventstate(win);
|
||||
|
||||
/* No context change! `C->wm->windrawable` is drawable, or for area queues. */
|
||||
wm->winactive = win;
|
||||
|
||||
win->active = 1;
|
||||
|
||||
/* bad ghost support for modifier keys... so on activate we set the modifiers again */
|
||||
|
||||
const uint8_t keymodifier_sided[2] = {
|
||||
wm_ghost_modifier_query(MOD_SIDE_LEFT),
|
||||
wm_ghost_modifier_query(MOD_SIDE_RIGHT),
|
||||
};
|
||||
const uint8_t keymodifier = keymodifier_sided[0] | keymodifier_sided[1];
|
||||
const uint8_t keymodifier_eventstate = win->eventstate->modifier;
|
||||
if (keymodifier != keymodifier_eventstate) {
|
||||
GHOST_TEventKeyData kdata = {
|
||||
.key = GHOST_kKeyUnknown,
|
||||
.utf8_buf = {'\0'},
|
||||
.is_repeat = false,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
|
||||
if (keymodifier_eventstate & g_modifier_table[i].flag) {
|
||||
if ((keymodifier & g_modifier_table[i].flag) == 0) {
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
|
||||
kdata.key = g_modifier_table[i].ghost_key_pair[side];
|
||||
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata);
|
||||
/* Only ever send one release event
|
||||
* (currently releasing multiple isn't needed and only confuses logic). */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef USE_WIN_ACTIVATE
|
||||
else {
|
||||
if (keymodifier & g_modifier_table[i].flag) {
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if (keymodifier_sided[side] & g_modifier_table[i].flag) {
|
||||
kdata.key = g_modifier_table[i].ghost_key_pair[side];
|
||||
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyDown, &kdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef USE_WIN_ACTIVATE
|
||||
}
|
||||
}
|
||||
|
||||
/* keymodifier zero, it hangs on hotkeys that open windows otherwise */
|
||||
win->eventstate->keymodifier = 0;
|
||||
|
||||
/* entering window, update mouse pos. but no event */
|
||||
wm_window_update_eventstate(win);
|
||||
|
||||
win->addmousemove = 1; /* enables highlighted buttons */
|
||||
|
||||
wm_window_make_drawable(wm, win);
|
||||
|
@ -1397,7 +1401,9 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
|||
case GHOST_kEventDraggingDropDone: {
|
||||
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
|
||||
|
||||
/* entering window, update mouse pos */
|
||||
/* Ensure the event state matches modifiers (window was inactive). */
|
||||
wm_window_update_eventstate_modifiers(wm, win);
|
||||
/* Entering window, update mouse position (without sending an event). */
|
||||
wm_window_update_eventstate(win);
|
||||
|
||||
wmEvent event;
|
||||
|
@ -1418,9 +1424,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
|||
|
||||
event.flag = 0;
|
||||
|
||||
/* No context change! C->wm->windrawable is drawable, or for area queues. */
|
||||
/* No context change! `C->wm->windrawable` is drawable, or for area queues. */
|
||||
wm->winactive = win;
|
||||
|
||||
win->active = 1;
|
||||
|
||||
wm_event_add(win, &event);
|
||||
|
@ -1493,8 +1498,9 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
|
|||
case GHOST_kEventButtonDown:
|
||||
case GHOST_kEventButtonUp: {
|
||||
if (win->active == 0) {
|
||||
/* Entering window, update cursor and tablet state.
|
||||
/* Entering window, update cursor/tablet state & modifiers.
|
||||
* (ghost sends win-activate *after* the mouse-click in window!) */
|
||||
wm_window_update_eventstate_modifiers(wm, win);
|
||||
wm_window_update_eventstate(win);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue