diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_opdefines.c | 2 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_queries.c | 26 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_bevel.c | 2 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_bevel.c | 80 | ||||
-rw-r--r-- | source/blender/depsgraph/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_brush.c | 21 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_edit.c | 100 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_intern.h | 5 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_wm.c | 241 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_array.c | 38 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_image.c | 2 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_operator_wrap.c | 4 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_operator_wrap.h | 4 | ||||
-rw-r--r-- | source/blenderplayer/bad_level_call_stubs/stubs.c | 4 |
14 files changed, 369 insertions, 161 deletions
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index d2f0fc1721c..200a31b1a57 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1741,6 +1741,8 @@ static BMOpDefine bmo_bevel_def = { }, /* slots_out */ {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */ + {"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output edges */ + {"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* output verts */ {{'\0'}}, }, diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index a774f278c98..f5c14304ea3 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -1515,16 +1515,30 @@ float BM_loop_calc_face_angle(const BMLoop *l) */ void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) { - if (normal_tri_v3(r_normal, - l->prev->v->co, - l->v->co, - l->next->v->co) != 0.0f) - { - /* pass */ +#define FEPSILON 1e-5f + + /* Note: we cannot use result of normal_tri_v3 here to detect colinear vectors (vertex on a straight line) + * from zero value, because it does not normalize both vectors before making crossproduct. + * Instead of adding two costly normalize computations, just check ourselves for colinear case. */ + /* Note: FEPSILON might need some finer tweaking at some point? Seems to be working OK for now though. */ + float v1[3], v2[3], v_tmp[3]; + sub_v3_v3v3(v1, l->prev->v->co, l->v->co); + sub_v3_v3v3(v2, l->next->v->co, l->v->co); + + const float fac = (v2[0] == 0.0f) ? ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : v1[1] / v2[1]) : v1[0] / v2[0]; + + mul_v3_v3fl(v_tmp, v2, fac); + sub_v3_v3(v_tmp, v1); + if (fac != 0.0f && !is_zero_v3(v1) && len_manhattan_v3(v_tmp) > FEPSILON) { + /* Not co-linear, we can compute crossproduct and normalize it into normal. */ + cross_v3_v3v3(r_normal, v1, v2); + normalize_v3(r_normal); } else { copy_v3_v3(r_normal, l->f->no); } + +#undef FEPSILON } /** diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index d5afb39d7b7..2ae87b64286 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -66,5 +66,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material, loop_slide); BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "verts.out", BM_VERT, BM_ELEM_TAG); } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 74841dc2756..6673c5d25cf 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -205,6 +205,29 @@ static int bev_debug_flags = 0; #define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2) #define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4) +/* this flag values will get set on geom we want to return in 'out' slots for edges and verts */ +#define EDGE_OUT 4 +#define VERT_OUT 8 + +/* If we're called from the modifier, tool flags aren't available, but don't need output geometry */ +static void flag_out_edge(BMesh *bm, BMEdge *bme) +{ + if (bm->use_toolflags) + BMO_edge_flag_enable(bm, bme, EDGE_OUT); +} + +static void flag_out_vert(BMesh *bm, BMVert *bmv) +{ + if (bm->use_toolflags) + BMO_vert_flag_enable(bm, bmv, VERT_OUT); +} + +static void disable_flag_out_edge(BMesh *bm, BMEdge *bme) +{ + if (bm->use_toolflags) + BMO_edge_flag_disable(bm, bme, EDGE_OUT); +} + /* Are d1 and d2 parallel or nearly so? */ static bool nearly_parallel(const float d1[3], const float d2[3]) { @@ -262,6 +285,7 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert NewVert *nv = mesh_vert(vm, i, j, k); nv->v = BM_vert_create(bm, nv->co, eg, BM_CREATE_NOP); BM_elem_flag_disable(nv->v, BM_ELEM_TAG); + flag_out_vert(bm, nv->v); } static void copy_mesh_vert( @@ -504,9 +528,12 @@ static BMFace *bev_create_ngon( } /* not essential for bevels own internal logic, - * this is done so the operator can select newly created faces */ + * this is done so the operator can select newly created geometry */ if (f) { BM_elem_flag_enable(f, BM_ELEM_TAG); + BM_ITER_ELEM(bme, &iter, f, BM_EDGES_OF_FACE) { + flag_out_edge(bm, bme); + } } if (mat_nr >= 0) @@ -3213,6 +3240,7 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv) BMFace *f_new; BLI_assert(v_fan == l_fan->v); f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, false); + flag_out_edge(bm, l_new->e); if (f_new->len > f->len) { f = f_new; @@ -3259,6 +3287,7 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv) else { BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false); f = l_new->f; + flag_out_edge(bm, l_new->e); /* walk around the new face to get the next verts to split */ l_a = l_new->prev; @@ -3278,7 +3307,7 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) { VMesh *vm = bv->vmesh; BMVert *v1, *v2; - BMEdge *e_eg; + BMEdge *e_eg, *bme; Profile *pro; float co[3]; BoundVert *bndv; @@ -3320,7 +3349,9 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) v1 = mesh_vert(vm, 0, 0, k)->v; v2 = mesh_vert(vm, 0, 0, k + 1)->v; BLI_assert(v1 != NULL && v2 != NULL); - BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE); + bme = BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE); + if (bme) + flag_out_edge(bm, bme); } } } @@ -3901,7 +3932,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) /* Face f has at least one beveled vertex. Rebuild f */ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) { - BMIter liter; + BMIter liter, eiter, fiter; BMLoop *l, *lprev; BevVert *bv; BoundVert *v, *vstart, *vend; @@ -3909,10 +3940,10 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) VMesh *vm; int i, k, n; bool do_rebuild = false; - bool go_ccw, corner3special; + bool go_ccw, corner3special, keep; BMVert *bmv; BMEdge *bme, *bme_new, *bme_prev; - BMFace *f_new; + BMFace *f_new, *f_other; BMVert **vv = NULL; BMVert **vv_fix = NULL; BMEdge **ee = NULL; @@ -4050,9 +4081,21 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) } } - /* don't select newly created boundary faces... */ + /* don't select newly or return created boundary faces... */ if (f_new) { BM_elem_flag_disable(f_new, BM_ELEM_TAG); + /* Also don't want new edges that aren't part of a new bevel face */ + BM_ITER_ELEM(bme, &eiter, f_new, BM_EDGES_OF_FACE) { + keep = false; + BM_ITER_ELEM(f_other, &fiter, bme, BM_FACES_OF_EDGE) { + if (BM_elem_flag_test(f_other, BM_ELEM_TAG)) { + keep = true; + break; + } + } + if (!keep) + disable_flag_out_edge(bm, bme); + } } } @@ -4134,8 +4177,9 @@ static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v) } } } while ((bndv = bndv->next) != bv->vmesh->boundstart); - if (vclosest) + if (vclosest) { BM_edge_create(bm, vclosest, votherclosest, e, BM_CREATE_NO_DOUBLE); + } } } @@ -4539,9 +4583,9 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp) /** * - Currently only bevels BM_ELEM_TAG'd verts and edges. * - * - Newly created faces are BM_ELEM_TAG'd too, - * the caller needs to ensure this is cleared before calling - * if its going to use this face tag. + * - Newly created faces, edges, and verts are BM_ELEM_TAG'd too, + * the caller needs to ensure these are cleared before calling + * if its going to use this tag. * * - If limit_offset is set, adjusts offset down if necessary * to avoid geometry collisions. @@ -4633,6 +4677,20 @@ void BM_mesh_bevel( } } + /* When called from operator (as opposed to modifier), bm->use_toolflags + * will be set, and we to transfer the oflags to BM_ELEM_TAGs */ + if (bm->use_toolflags) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test(bm, v, VERT_OUT)) + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test(bm, e, EDGE_OUT)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } + } + /* primary free */ BLI_ghash_free(bp.vert_hash, NULL, NULL); BLI_memarena_free(bp.mem_arena); diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index d5dcb84aaf5..5eb5d69d62e 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -89,6 +89,7 @@ set(SRC intern/depsgraph_intern.h intern/depsgraph_types.h + util/deg_util_foreach.h util/deg_util_function.h ) diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index c2807f72fbb..1577cb76f99 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -773,6 +773,9 @@ typedef struct tGPSB_CloneBrushData { /* for "stamp" mode, the currently pasted brushes */ bGPDstroke **new_strokes; + + /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */ + GHash *new_colors; } tGPSB_CloneBrushData; /* Initialise "clone" brush data */ @@ -816,6 +819,11 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) { data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array"); } + + /* Init colormap for mapping between the pasted stroke's source colour(names) + * and the final colours that will be used here instead... + */ + data->new_colors = gp_copybuf_validate_colormap(gso->gpd); } /* Free custom data used for "clone" brush */ @@ -829,6 +837,12 @@ static void gp_brush_clone_free(tGP_BrushEditData *gso) data->new_strokes = NULL; } + /* free copybuf colormap */ + if (data->new_colors) { + BLI_ghash_free(data->new_colors, NULL, NULL); + data->new_colors = NULL; + } + /* free the customdata itself */ MEM_freeN(data); gso->customdata = NULL; @@ -869,6 +883,13 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); + /* Fix color references */ + BLI_assert(new_stroke->colorname[0] != '\0'); + new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname); + + BLI_assert(new_stroke->palcolor != NULL); + BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname)); + /* Adjust all the stroke's points, so that the strokes * get pasted relative to where the cursor is now */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index b4cfc1a8d87..1d70d3685c7 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -38,8 +38,11 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -335,11 +338,27 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot) /* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */ ListBase gp_strokes_copypastebuf = {NULL, NULL}; +/* Hash for hanging on to all the palette colors used by strokes in the buffer + * + * This is needed to prevent dangling and unsafe pointers when pasting across datablocks, + * or after a color used by a stroke in the buffer gets deleted (via user action or undo). + */ +GHash *gp_strokes_copypastebuf_colors = NULL; + /* Free copy/paste buffer data */ void ED_gpencil_strokes_copybuf_free(void) { bGPDstroke *gps, *gpsn; + /* Free the palettes buffer + * NOTE: This is done before the strokes so that the name ptrs (keys) are still safe + */ + if (gp_strokes_copypastebuf_colors) { + BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN); + gp_strokes_copypastebuf_colors = NULL; + } + + /* Free the stroke buffer */ for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) { gpsn = gps->next; @@ -352,6 +371,46 @@ void ED_gpencil_strokes_copybuf_free(void) gp_strokes_copypastebuf.first = gp_strokes_copypastebuf.last = NULL; } +/* Ensure that destination datablock has all the colours the pasted strokes need + * Helper function for copy-pasting strokes + */ +GHash *gp_copybuf_validate_colormap(bGPdata *gpd) +{ + GHash *new_colors = BLI_ghash_str_new("GPencil Paste Dst Colors"); + GHashIterator gh_iter; + + /* If there's no active palette yet (i.e. new datablock), add one */ + bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); + if (palette == NULL) { + palette = BKE_gpencil_palette_addnew(gpd, "Pasted Palette", true); + } + + /* For each color, figure out what to map to... */ + GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) { + bGPDpalettecolor *palcolor; + char *name = BLI_ghashIterator_getKey(&gh_iter); + + /* Look for existing color to map to */ + /* XXX: What to do if same name but different color? Behaviour here should depend on a property? */ + palcolor = BKE_gpencil_palettecolor_getbyname(palette, name); + if (palcolor == NULL) { + /* Doesn't Exist - Create new matching color for this palette */ + /* XXX: This still doesn't fix the pasting across file boundaries problem... */ + bGPDpalettecolor *src_color = BLI_ghashIterator_getValue(&gh_iter); + + palcolor = MEM_dupallocN(src_color); + BLI_addtail(&palette->colors, palcolor); + + BLI_uniquename(&palette->colors, palcolor, DATA_("GP Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info)); + } + + /* Store this mapping (for use later when pasting) */ + BLI_ghash_insert(new_colors, name, palcolor); + } + + return new_colors; +} + /* --------------------- */ /* Copy selected strokes */ @@ -413,7 +472,26 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - /* done - no updates needed */ + /* Build up hash of colors used in these strokes, making copies of these to protect against dangling pointers */ + if (gp_strokes_copypastebuf.first) { + gp_strokes_copypastebuf_colors = BLI_ghash_str_new("GPencil CopyBuf Colors"); + + for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { + if (ED_gpencil_stroke_can_use(C, gps)) { + if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, gps->colorname) == false) { + bGPDpalettecolor *color = MEM_dupallocN(gps->palcolor); + + BLI_ghash_insert(gp_strokes_copypastebuf_colors, gps->colorname, color); + gps->palcolor = color; + } + } + } + } + + /* updates (to ensure operator buttons are refreshed, when used via hotkeys) */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); // XXX? + + /* done */ return OPERATOR_FINISHED; } @@ -458,6 +536,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) bGPDframe *gpf; eGP_PasteMode type = RNA_enum_get(op->ptr, "type"); + GHash *new_colors; /* check for various error conditions */ if (gpd == NULL) { @@ -515,6 +594,10 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) } CTX_DATA_END; + /* Ensure that all the necessary colors exist */ + new_colors = gp_copybuf_validate_colormap(gpd); + + /* Copy over the strokes from the buffer (and adjust the colors) */ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { /* Need to verify if layer exists */ @@ -533,6 +616,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) */ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); if (gpf) { + /* Create new stroke */ bGPDstroke *new_stroke = MEM_dupallocN(gps); new_stroke->tmp_layerinfo[0] = '\0'; @@ -543,10 +627,22 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); + + /* Fix color references */ + BLI_assert(new_stroke->colorname[0] != '\0'); + new_stroke->palcolor = BLI_ghash_lookup(new_colors, new_stroke->colorname); + + BLI_assert(new_stroke->palcolor != NULL); + BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname)); + + /*new_stroke->flag |= GP_STROKE_RECALC_COLOR; */ } } } + /* free temp data */ + BLI_ghash_free(new_colors, NULL, NULL); + /* updates */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 5c7c9b84adb..13af06fd4fd 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -40,6 +40,8 @@ struct bGPdata; struct bGPDstroke; struct bGPDspoint; +struct GHash; + struct ARegion; struct View2D; struct wmOperatorType; @@ -155,6 +157,9 @@ int gp_brush_crt_presets_poll(bContext *C); extern ListBase gp_strokes_copypastebuf; +/* Build a map for converting between old colornames and destination-color-refs */ +struct GHash *gp_copybuf_validate_colormap(bGPdata *gpd); + /* Stroke Editing ------------------------------------ */ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index f6e67d5f765..fe30890d5ba 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1031,35 +1031,8 @@ static void rna_wmClipboard_set(PointerRNA *UNUSED(ptr), const char *value) } #ifdef WITH_PYTHON -static void rna_Operator_unregister(struct Main *bmain, StructRNA *type) -{ - const char *idname; - wmOperatorType *ot = RNA_struct_blender_type_get(type); - wmWindowManager *wm; - - if (!ot) - return; - - /* update while blender is running */ - wm = bmain->wm.first; - if (wm) { - WM_operator_stack_clear(wm); - WM_operator_handlers_clear(wm, ot); - } - WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); - - RNA_struct_free_extension(type, &ot->ext); - - idname = ot->idname; - WM_operatortype_remove_ptr(ot); - MEM_freeN((void *)idname); - - /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */ - RNA_struct_free(&BLENDER_RNA, type); -} - -static int operator_poll(bContext *C, wmOperatorType *ot) +static int rna_operator_poll_cb(bContext *C, wmOperatorType *ot) { extern FunctionRNA rna_Operator_poll_func; @@ -1084,7 +1057,7 @@ static int operator_poll(bContext *C, wmOperatorType *ot) return visible; } -static int operator_execute(bContext *C, wmOperator *op) +static int rna_operator_execute_cb(bContext *C, wmOperator *op) { extern FunctionRNA rna_Operator_execute_func; @@ -1110,7 +1083,7 @@ static int operator_execute(bContext *C, wmOperator *op) } /* same as execute() but no return value */ -static bool operator_check(bContext *C, wmOperator *op) +static bool rna_operator_check_cb(bContext *C, wmOperator *op) { extern FunctionRNA rna_Operator_check_func; @@ -1135,7 +1108,7 @@ static bool operator_check(bContext *C, wmOperator *op) return result; } -static int operator_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int rna_operator_invoke_cb(bContext *C, wmOperator *op, const wmEvent *event) { extern FunctionRNA rna_Operator_invoke_func; @@ -1162,7 +1135,7 @@ static int operator_invoke(bContext *C, wmOperator *op, const wmEvent *event) } /* same as invoke */ -static int operator_modal(bContext *C, wmOperator *op, const wmEvent *event) +static int rna_operator_modal_cb(bContext *C, wmOperator *op, const wmEvent *event) { extern FunctionRNA rna_Operator_modal_func; @@ -1188,7 +1161,7 @@ static int operator_modal(bContext *C, wmOperator *op, const wmEvent *event) return result; } -static void operator_draw(bContext *C, wmOperator *op) +static void rna_operator_draw_cb(bContext *C, wmOperator *op) { extern FunctionRNA rna_Operator_draw_func; @@ -1207,7 +1180,7 @@ static void operator_draw(bContext *C, wmOperator *op) } /* same as exec(), but call cancel */ -static void operator_cancel(bContext *C, wmOperator *op) +static void rna_operator_cancel_cb(bContext *C, wmOperator *op) { extern FunctionRNA rna_Operator_cancel_func; @@ -1225,35 +1198,42 @@ static void operator_cancel(bContext *C, wmOperator *op) RNA_parameter_list_free(&list); } -void operator_wrapper(wmOperatorType *ot, void *userdata); -void macro_wrapper(wmOperatorType *ot, void *userdata); +static void rna_Operator_unregister(struct Main *bmain, StructRNA *type); -static char _operator_idname[OP_MAX_TYPENAME]; -static char _operator_name[OP_MAX_TYPENAME]; -static char _operator_descr[RNA_DYN_DESCR_MAX]; -static char _operator_ctxt[RNA_DYN_DESCR_MAX]; -static char _operator_undo_group[OP_MAX_TYPENAME]; -static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +/* bpy_operator_wrap.c */ +extern void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata); +extern void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata); + +static StructRNA *rna_Operator_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { wmOperatorType dummyot = {NULL}; wmOperator dummyop = {NULL}; PointerRNA dummyotr; int have_function[7]; + struct { + char idname[OP_MAX_TYPENAME]; + char name[OP_MAX_TYPENAME]; + char descr[RNA_DYN_DESCR_MAX]; + char ctxt[RNA_DYN_DESCR_MAX]; + char undo_group[OP_MAX_TYPENAME]; + } temp_buffers; + /* setup dummy operator & operator type to store static properties in */ dummyop.type = &dummyot; - dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */ - dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */ - dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */ - dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */ - dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */ + dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */ + dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */ + dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */ + dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr); /* clear in case they are left unset */ - _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0'; + temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0'; /* We have to set default op context! */ - strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); /* validate the python class */ if (validate(&dummyotr, data, have_function) != 0) @@ -1264,7 +1244,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * /* inconveniently long name sanity check */ { - char *ch = _operator_idname; + char *ch = temp_buffers.idname; int i; int dot = 0; for (i = 0; *ch; i++) { @@ -1277,7 +1257,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * else { BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', at position %d", - identifier, _operator_idname, i); + identifier, temp_buffers.idname, i); return NULL; } @@ -1286,7 +1266,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * if (i > ((int)sizeof(dummyop.idname)) - 3) { BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', " - "is too long, maximum length is %d", identifier, _operator_idname, + "is too long, maximum length is %d", identifier, temp_buffers.idname, (int)sizeof(dummyop.idname) - 3); return NULL; } @@ -1294,34 +1274,34 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * if (dot != 1) { BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character", - identifier, _operator_idname); + identifier, temp_buffers.idname); return NULL; } } /* end sanity check */ { - int idlen = strlen(_operator_idname) + 4; - int namelen = strlen(_operator_name) + 1; - int desclen = strlen(_operator_descr) + 1; - int ctxtlen = strlen(_operator_ctxt) + 1; - int ugrouplen = strlen(_operator_undo_group) + 1; - char *ch; + const uint idname_len = strlen(temp_buffers.idname) + 4; + const uint name_len = strlen(temp_buffers.name) + 1; + const uint desc_len = strlen(temp_buffers.descr) + 1; + const uint ctxt_len = strlen(temp_buffers.ctxt) + 1; + const uint undo_group_len = strlen(temp_buffers.undo_group) + 1; /* 2 terminators and 3 to convert a.b -> A_OT_b */ - ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname"); - WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */ + char *ch = MEM_mallocN( + sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__); + WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */ dummyot.idname = ch; - ch += idlen; - strcpy(ch, _operator_name); + ch += idname_len; + memcpy(ch, temp_buffers.name, name_len); dummyot.name = ch; - ch += namelen; - strcpy(ch, _operator_descr); + ch += name_len; + memcpy(ch, temp_buffers.descr, desc_len); dummyot.description = ch; - ch += desclen; - strcpy(ch, _operator_ctxt); + ch += desc_len; + memcpy(ch, temp_buffers.ctxt, ctxt_len); dummyot.translation_context = ch; - ch += ctxtlen; - strcpy(ch, _operator_undo_group); + ch += ctxt_len; + memcpy(ch, temp_buffers.undo_group, undo_group_len); dummyot.undo_group = ch; } } @@ -1344,14 +1324,14 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * dummyot.ext.call = call; dummyot.ext.free = free; - dummyot.pyop_poll = (have_function[0]) ? operator_poll : NULL; - dummyot.exec = (have_function[1]) ? operator_execute : NULL; - dummyot.check = (have_function[2]) ? operator_check : NULL; - dummyot.invoke = (have_function[3]) ? operator_invoke : NULL; - dummyot.modal = (have_function[4]) ? operator_modal : NULL; - dummyot.ui = (have_function[5]) ? operator_draw : NULL; - dummyot.cancel = (have_function[6]) ? operator_cancel : NULL; - WM_operatortype_append_ptr(operator_wrapper, (void *)&dummyot); + dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL; + dummyot.exec = (have_function[1]) ? rna_operator_execute_cb : NULL; + dummyot.check = (have_function[2]) ? rna_operator_check_cb : NULL; + dummyot.invoke = (have_function[3]) ? rna_operator_invoke_cb : NULL; + dummyot.modal = (have_function[4]) ? rna_operator_modal_cb : NULL; + dummyot.ui = (have_function[5]) ? rna_operator_draw_cb : NULL; + dummyot.cancel = (have_function[6]) ? rna_operator_cancel_cb : NULL; + WM_operatortype_append_ptr(BPY_RNA_operator_wrapper, (void *)&dummyot); /* update while blender is running */ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); @@ -1359,70 +1339,107 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * return dummyot.ext.srna; } +static void rna_Operator_unregister(struct Main *bmain, StructRNA *type) +{ + const char *idname; + wmOperatorType *ot = RNA_struct_blender_type_get(type); + wmWindowManager *wm; + + if (!ot) + return; + + /* update while blender is running */ + wm = bmain->wm.first; + if (wm) { + WM_operator_stack_clear(wm); + + WM_operator_handlers_clear(wm, ot); + } + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + + RNA_struct_free_extension(type, &ot->ext); + + idname = ot->idname; + WM_operatortype_remove_ptr(ot); + MEM_freeN((void *)idname); + + /* not to be confused with the RNA_struct_free that WM_operatortype_remove calls, they are 2 different srna's */ + RNA_struct_free(&BLENDER_RNA, type); +} + static void **rna_Operator_instance(PointerRNA *ptr) { wmOperator *op = ptr->data; return &op->py_instance; } -static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_MacroOperator_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { wmOperatorType dummyot = {NULL}; wmOperator dummyop = {NULL}; PointerRNA dummyotr; int have_function[4]; + struct { + char idname[OP_MAX_TYPENAME]; + char name[OP_MAX_TYPENAME]; + char descr[RNA_DYN_DESCR_MAX]; + char ctxt[RNA_DYN_DESCR_MAX]; + char undo_group[OP_MAX_TYPENAME]; + } temp_buffers; + /* setup dummy operator & operator type to store static properties in */ dummyop.type = &dummyot; - dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */ - dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */ - dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */ - dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */ - dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */ + dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */ + dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */ + dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */ + dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr); /* clear in case they are left unset */ - _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0'; + temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0'; /* We have to set default op context! */ - strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); /* validate the python class */ if (validate(&dummyotr, data, have_function) != 0) return NULL; + if (strlen(identifier) >= sizeof(dummyop.idname)) { + BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s' is too long, maximum length is %d", + identifier, (int)sizeof(dummyop.idname)); + return NULL; + } + { /* convert foo.bar to FOO_OT_bar * allocate the description and the idname in 1 go */ - int idlen = strlen(_operator_idname) + 4; - int namelen = strlen(_operator_name) + 1; - int desclen = strlen(_operator_descr) + 1; - int ctxtlen = strlen(_operator_ctxt) + 1; - int ugrouplen = strlen(_operator_undo_group) + 1; - char *ch; + const uint idname_len = strlen(temp_buffers.idname) + 4; + const uint name_len = strlen(temp_buffers.name) + 1; + const uint desc_len = strlen(temp_buffers.descr) + 1; + const uint ctxt_len = strlen(temp_buffers.ctxt) + 1; + const uint undo_group_len = strlen(temp_buffers.undo_group) + 1; /* 2 terminators and 3 to convert a.b -> A_OT_b */ - ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname"); - WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */ + char *ch = MEM_mallocN( + sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__); + WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */ dummyot.idname = ch; - ch += idlen; - strcpy(ch, _operator_name); + ch += idname_len; + memcpy(ch, temp_buffers.name, name_len); dummyot.name = ch; - ch += namelen; - strcpy(ch, _operator_descr); + ch += name_len; + memcpy(ch, temp_buffers.descr, desc_len); dummyot.description = ch; - ch += desclen; - strcpy(ch, _operator_ctxt); + ch += desc_len; + memcpy(ch, temp_buffers.ctxt, ctxt_len); dummyot.translation_context = ch; - ch += ctxtlen; - strcpy(ch, _operator_undo_group); + ch += ctxt_len; + memcpy(ch, temp_buffers.undo_group, undo_group_len); dummyot.undo_group = ch; } - if (strlen(identifier) >= sizeof(dummyop.idname)) { - BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s' is too long, maximum length is %d", - identifier, (int)sizeof(dummyop.idname)); - return NULL; - } - /* check if we have registered this operator type before, and remove it */ { wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true); @@ -1440,10 +1457,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v dummyot.ext.call = call; dummyot.ext.free = free; - dummyot.pyop_poll = (have_function[0]) ? operator_poll : NULL; - dummyot.ui = (have_function[3]) ? operator_draw : NULL; + dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL; + dummyot.ui = (have_function[3]) ? rna_operator_draw_cb : NULL; - WM_operatortype_append_macro_ptr(macro_wrapper, (void *)&dummyot); + WM_operatortype_append_macro_ptr(BPY_RNA_operator_macro_wrapper, (void *)&dummyot); /* update while blender is running */ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 78a5631bb94..09597b5b42f 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -50,6 +50,7 @@ #include "BKE_curve.h" #include "BKE_library_query.h" #include "BKE_modifier.h" +#include "BKE_mesh.h" #include "MOD_util.h" @@ -123,25 +124,6 @@ static void updateDepsgraph(ModifierData *md, } } -static float vertarray_size(const MVert *mvert, int numVerts, int axis) -{ - int i; - float min_co, max_co; - - /* if there are no vertices, width is 0 */ - if (numVerts == 0) return 0; - - /* find the minimum and maximum coordinates on the desired axis */ - min_co = max_co = mvert->co[axis]; - mvert++; - for (i = 1; i < numVerts; ++i, ++mvert) { - if (mvert->co[axis] < min_co) min_co = mvert->co[axis]; - if (mvert->co[axis] > max_co) max_co = mvert->co[axis]; - } - - return max_co - min_co; -} - BLI_INLINE float sum_v3(const float v[3]) { return v[0] + v[1] + v[2]; @@ -438,12 +420,22 @@ static DerivedMesh *arrayModifier_doArray( unit_m4(offset); src_mvert = dm->getVertArray(dm); - if (amd->offset_type & MOD_ARR_OFF_CONST) - add_v3_v3v3(offset[3], offset[3], amd->offset); + if (amd->offset_type & MOD_ARR_OFF_CONST) { + add_v3_v3(offset[3], amd->offset); + } if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { - for (j = 0; j < 3; j++) - offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j); + float min[3], max[3]; + const MVert *src_mv; + + INIT_MINMAX(min, max); + for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) { + minmax_v3v3_v3(min, max, src_mv->co); + } + + for (j = 3; j--; ) { + offset[3][j] += amd->scale[j] * (max[j] - min[j]); + } } if (use_offset_ob) { diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index a95a99449fd..8139e29bade 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -117,7 +117,7 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree, bNode *node, else { sock = BLI_findlink(&node->outputs, sock_index); NodeImageLayer *sockdata = sock->storage; - if(sockdata) { + if (sockdata) { BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name)); } } diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 11e27ca3e3c..90719905a79 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -118,7 +118,7 @@ static void operator_properties_init(wmOperatorType *ot) } -void operator_wrapper(wmOperatorType *ot, void *userdata) +void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata) { /* take care not to overwrite anything set in * WM_operatortype_append_ptr before opfunc() is called */ @@ -134,7 +134,7 @@ void operator_wrapper(wmOperatorType *ot, void *userdata) operator_properties_init(ot); } -void macro_wrapper(wmOperatorType *ot, void *userdata) +void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata) { wmOperatorType *data = (wmOperatorType *)userdata; diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h index 05a566a1485..0828c58e2bd 100644 --- a/source/blender/python/intern/bpy_operator_wrap.h +++ b/source/blender/python/intern/bpy_operator_wrap.h @@ -33,7 +33,7 @@ struct wmOperatorType; PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args); /* exposed to rna/wm api */ -void operator_wrapper(struct wmOperatorType *ot, void *userdata); -void macro_wrapper(struct wmOperatorType *ot, void *userdata); +void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata); +void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata); #endif diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 283bab1583a..f9d96bf6d4d 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -799,7 +799,8 @@ int collada_export(struct Scene *sce, void ED_mesh_calc_tessface(struct Mesh *mesh, bool free_mpoly) RET_NONE /* bpy/python internal api */ -void operator_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE +void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE +void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE void BPY_text_free_code(struct Text *text) RET_NONE void BPY_id_release(struct ID *id) RET_NONE int BPY_context_member_get(struct bContext *C, const char *member, struct bContextDataResult *result) RET_ZERO @@ -807,7 +808,6 @@ void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTa float BPY_driver_exec(PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime) RET_ZERO /* might need this one! */ void BPY_DECREF(void *pyob_ptr) RET_NONE void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) RET_NONE -void macro_wrapper(struct wmOperatorType *ot, void *userdata) RET_NONE bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id) RET_ZERO struct PyObject *pyrna_id_CreatePyObject(struct ID *id) RET_NULL bool pyrna_id_CheckPyObject(struct PyObject *obj) RET_ZERO |