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

Merged
Nate Rupsis merged 8 commits from nrupsis/blender:T82241-cleanup-NLATrack_insert into main 2023-03-02 15:02:42 +01:00
31 changed files with 759 additions and 556 deletions
Showing only changes of commit 6118426e74 - Show all commits

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
* \{ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -650,7 +650,6 @@ typedef enum eBrushCurvesSculptDensityMode {
} eBrushCurvesSculptDensityMode;
#define MAX_BRUSH_PIXEL_RADIUS 500
#define GP_MAX_BRUSH_PIXEL_RADIUS 1000
#ifdef __cplusplus
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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