diff options
Diffstat (limited to 'source')
70 files changed, 2203 insertions, 1570 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 17ef8e901f4..503c7a7f435 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -67,6 +67,7 @@ int BKE_brush_clone_image_delete(struct Brush *brush); /* jitter */ void BKE_brush_jitter_pos(const struct Scene *scene, struct Brush *brush, const float pos[2], float jitterpos[2]); +void BKE_brush_randomize_texture_coordinates(struct UnifiedPaintSettings *ups); /* brush curve */ void BKE_brush_curve_preset(struct Brush *b, int preset); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 26ac2cc8bb4..0f8e25b9df5 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -232,6 +232,8 @@ void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, in unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame); float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame); +/* Guess offset for the first frame in the sequence */ +int BKE_image_sequence_guess_offset(struct Image *image); #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index e62994576a3..e234d6c519e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -628,70 +628,46 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree); * * Examples: * - * FOREACH_NODETREE(bmain, nodetree) + * FOREACH_NODETREE(bmain, nodetree) { * if (id == nodetree) * printf("This is a linkable node tree"); - * FOREACH_NODETREE_END + * } FOREACH_NODETREE_END * - * FOREACH_NODETREE(bmain, nodetree) + * FOREACH_NODETREE(bmain, nodetree) { * if (nodetree->idname == "ShaderNodeTree") * printf("This is a shader node tree); * if (GS(id) == ID_MA) * printf(" and it's owned by a material"); - * FOREACH_NODETREE_END + * } FOREACH_NODETREE_END */ +/* should be an opaque type, only for internal use by BKE_node_tree_iter_*** */ +struct NodeTreeIterStore { + bNodeTree *ngroup; + Scene *scene; + Material *mat; + Tex *tex; + Lamp *lamp; + World *world; +}; + +void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain); +bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, + struct bNodeTree **r_nodetree, struct ID **r_id); + #define FOREACH_NODETREE(bmain, _nodetree, _id) \ { \ + struct NodeTreeIterStore _nstore; \ bNodeTree *_nodetree; \ ID *_id; \ - bNodeTree *_ngroup = bmain->nodetree.first; \ - Scene *_scene = bmain->scene.first; \ - Material *_mat = bmain->mat.first; \ - Tex *_tex = bmain->tex.first; \ - Lamp *_lamp = bmain->lamp.first; \ - World *_world = bmain->world.first; \ /* avoid compiler warning about unused variables */ \ - (void)_id; \ - (void)_nodetree; \ - do { \ - if (_ngroup) { \ - _nodetree = _ngroup; \ - _id = (ID *)_ngroup; \ - _ngroup = _ngroup->id.next; \ - } \ - else if (_scene) { \ - _nodetree = _scene->nodetree; \ - _id = (ID *)_scene; \ - _scene = _scene->id.next; \ - } \ - else if (_mat) { \ - _nodetree = _mat->nodetree; \ - _id = (ID *)_mat; \ - _mat = _mat->id.next; \ - } \ - else if (_tex) { \ - _nodetree = _tex->nodetree; \ - _id = (ID *)_tex; \ - _tex = _tex->id.next; \ - } \ - else if (_lamp) { \ - _nodetree = _lamp->nodetree; \ - _id = (ID *)_lamp; \ - _lamp = _lamp->id.next; \ - } \ - else if (_world) { \ - _nodetree = _world->nodetree; \ - _id = (ID *)_world; \ - _world = _world->id.next; \ - } \ - else \ - break; \ + BKE_node_tree_iter_init(&_nstore, bmain); \ + while (BKE_node_tree_iter_step(&_nstore, &_nodetree, &_id) == true) { \ if (_nodetree) { #define FOREACH_NODETREE_END \ } \ - } while (TRUE); \ + } \ } /* ************** SHADER NODES *************** */ diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index ec1b6577469..64f0b97c3f0 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -47,6 +47,7 @@ typedef struct SoundWaveform { } SoundWaveform; void sound_init_once(void); +void sound_exit_once(void); void sound_init(struct Main *main); @@ -139,4 +140,6 @@ void *sound_get_factory(void *sound); float sound_get_length(struct bSound *sound); +int sound_is_jack_supported(void); + #endif diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 888426735c5..2f666bf5922 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -525,21 +525,16 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br, float radius = 1.0f; /* Quite warnings */ float co[3]; - if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW || - mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) - { + if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { /* keep coordinates relative to mouse */ rotation += ups->brush_rotation; - point_2d[0] -= ups->tex_mouse[0]; - point_2d[1] -= ups->tex_mouse[1]; + x = point_2d[0] - ups->tex_mouse[0]; + y = point_2d[1] - ups->tex_mouse[1]; /* use pressure adjusted size for fixed mode */ radius = ups->pixel_radius; - - x = point_2d[0]; - y = point_2d[1]; } else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { /* leave the coordinates relative to the screen */ @@ -550,6 +545,14 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br, x = point_2d[0]; y = point_2d[1]; } + else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) { + rotation += ups->brush_rotation; + /* these contain a random coordinate */ + x = point_2d[0] - ups->tex_mouse[0]; + y = point_2d[1] - ups->tex_mouse[1]; + + radius = ups->pixel_radius; + } x /= radius; y /= radius; @@ -661,6 +664,14 @@ float BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2 rotation += ups->brush_rotation; radius = ups->pixel_radius; } + else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) { + rotation += ups->brush_rotation; + /* these contain a random coordinate */ + x -= ups->tex_mouse[0]; + y -= ups->tex_mouse[1]; + + radius = ups->pixel_radius; + } x /= radius; y /= radius; @@ -981,6 +992,14 @@ void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], } } +void BKE_brush_randomize_texture_coordinates(UnifiedPaintSettings *ups) +{ + /* we multiply with brush radius as an optimization for the brush + * texture sampling functions */ + ups->tex_mouse[0] = BLI_rng_get_float(brush_rng) * ups->pixel_radius; + ups->tex_mouse[1] = BLI_rng_get_float(brush_rng) * ups->pixel_radius; +} + /* Uses the brush curve control to find a strength value between 0 and 1 */ float BKE_brush_curve_strength_clamp(Brush *br, float p, const float len) { @@ -1021,7 +1040,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); - /*do normalized cannonical view coords for texture*/ + /* do normalized cannonical view coords for texture */ for (y = -1.0, iy = 0; iy < side; iy++, y += step) { for (x = -1.0, ix = 0; ix < side; ix++, x += step) { co[0] = x; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 853a55b49c2..56f2237a61f 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1653,7 +1653,7 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c } -static short bevelinside(BevList *bl1, BevList *bl2) +static bool bevelinside(BevList *bl1, BevList *bl2) { /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */ /* returns '1' if correct hole */ @@ -1701,9 +1701,7 @@ static short bevelinside(BevList *bl1, BevList *bl2) bevp++; } - if ( (links & 1) && (rechts & 1) ) - return 1; - return 0; + return (links & 1) && (rechts & 1); } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 0b55c732ade..9a012f9c009 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -1540,7 +1540,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } if (bottom_capbase.first) { - BKE_displist_fill(&bottom_capbase, dispbase, 1); + BKE_displist_fill(&bottom_capbase, dispbase, 0); BKE_displist_fill(&top_capbase, dispbase, 0); BKE_displist_free(&bottom_capbase); BKE_displist_free(&top_capbase); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 26651d76f68..c9034cfe7bb 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -3430,3 +3430,15 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame) return pixels; } + +int BKE_image_sequence_guess_offset(Image *image) +{ + unsigned short numlen; + char head[FILE_MAX], tail[FILE_MAX]; + char num[FILE_MAX] = {0}; + + BLI_stringdec(image->name, head, tail, &numlen); + BLI_strncpy(num, image->name + strlen(head), numlen + 1); + + return atoi(num); +} diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 1c1102d91ba..7fcbc14a593 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -126,11 +126,11 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node) /* initialize the node name with the node label. * note: do this after the initfunc so nodes get their data set which may be used in naming * (node groups for example) */ - /* XXX Do not use nodeLabel() here, it returns translated content, which should *only* be used - * in UI, *never* in data... + /* XXX Do not use nodeLabel() here, it returns translated content for UI, which should *only* be used + * in UI, *never* in data... Data have their own translation option! * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler - * than adding a "no translate" flag to this func (and labelfunc() as well). */ - BLI_strncpy(node->name, ntype->ui_name, NODE_MAXSTR); + * than adding "do_translate" flags to this func (and labelfunc() as well). */ + BLI_strncpy(node->name, DATA_(ntype->ui_name), NODE_MAXSTR); nodeUniqueName(ntree, node); node_add_sockets_from_type(ntree, node, ntype); @@ -816,7 +816,7 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) NODE_TYPES_BEGIN(ntype) if (ntype->type == type) { - idname = ntype->idname; + idname = DATA_(ntype->idname); break; } NODE_TYPES_END @@ -3593,3 +3593,56 @@ void clear_scene_in_nodes(Main *bmain, Scene *sce) } } } + + +/* -------------------------------------------------------------------- */ +/* NodeTree Iterator Helpers (FOREACH_NODETREE) */ + +void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain) +{ + ntreeiter->ngroup = bmain->nodetree.first; + ntreeiter->scene = bmain->scene.first; + ntreeiter->mat = bmain->mat.first; + ntreeiter->tex = bmain->tex.first; + ntreeiter->lamp = bmain->lamp.first; + ntreeiter->world = bmain->world.first; +} +bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, + bNodeTree **r_nodetree, struct ID **r_id) +{ + if (ntreeiter->ngroup) { + *r_nodetree = ntreeiter->ngroup; + *r_id = (ID *)ntreeiter->ngroup; + ntreeiter->ngroup = ntreeiter->ngroup->id.next; + } + else if (ntreeiter->scene) { + *r_nodetree = ntreeiter->scene->nodetree; + *r_id = (ID *)ntreeiter->scene; + ntreeiter->scene = ntreeiter->scene->id.next; + } + else if (ntreeiter->mat) { + *r_nodetree = ntreeiter->mat->nodetree; + *r_id = (ID *)ntreeiter->mat; + ntreeiter->mat = ntreeiter->mat->id.next; + } + else if (ntreeiter->tex) { + *r_nodetree = ntreeiter->tex->nodetree; + *r_id = (ID *)ntreeiter->tex; + ntreeiter->tex = ntreeiter->tex->id.next; + } + else if (ntreeiter->lamp) { + *r_nodetree = ntreeiter->lamp->nodetree; + *r_id = (ID *)ntreeiter->lamp; + ntreeiter->lamp = ntreeiter->lamp->id.next; + } + else if (ntreeiter->world) { + *r_nodetree = ntreeiter->world->nodetree; + *r_id = (ID *)ntreeiter->world; + ntreeiter->world = ntreeiter->world->id.next; + } + else { + return false; + } + + return true; +} diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 5a02d929b76..af67ada7765 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -263,7 +263,7 @@ void packAll(Main *bmain, ReportList *reports) } if (tot == 0) - BKE_report(reports, RPT_INFO, "No files have been packed"); + BKE_report(reports, RPT_INFO, "No new files have been packed"); else BKE_reportf(reports, RPT_INFO, "Packed %d files", tot); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index bccc6f9a93b..eaf385fbfcf 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1001,26 +1001,26 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o /* get effectors present in the group specified by effector_weights */ effectors = pdInitEffectors(scene, ob, NULL, effector_weights); if (effectors) { - float force[3] = {0.0f, 0.0f, 0.0f}; - float loc[3], vel[3]; + float eff_force[3] = {0.0f, 0.0f, 0.0f}; + float eff_loc[3], eff_vel[3]; /* create dummy 'point' which represents last known position of object as result of sim */ // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals? - RB_body_get_position(rbo->physics_object, loc); - RB_body_get_linear_velocity(rbo->physics_object, vel); + RB_body_get_position(rbo->physics_object, eff_loc); + RB_body_get_linear_velocity(rbo->physics_object, eff_vel); - pd_point_from_loc(scene, loc, vel, 0, &epoint); + pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint); /* calculate net force of effectors, and apply to sim object * - we use 'central force' since apply force requires a "relative position" which we don't have... */ - pdDoEffectors(effectors, NULL, effector_weights, &epoint, force, NULL); + pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL); if (G.f & G_DEBUG) - printf("\tapplying force (%f,%f,%f) to '%s'\n", force[0], force[1], force[2], ob->id.name + 2); + printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2); /* activate object in case it is deactivated */ - if (!is_zero_v3(force)) + if (!is_zero_v3(eff_force)) RB_body_activate(rbo->physics_object); - RB_body_apply_central_force(rbo->physics_object, force); + RB_body_apply_central_force(rbo->physics_object, eff_force); } else if (G.f & G_DEBUG) printf("\tno forces to apply to '%s'\n", ob->id.name + 2); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index af9d21d8cbc..feff8f95fd7 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -172,7 +172,7 @@ void sound_force_device(int device) void sound_init_once(void) { AUD_initOnce(); - atexit(sound_exit); + atexit(sound_exit_once); } void sound_init(struct Main *bmain) @@ -221,6 +221,12 @@ void sound_exit(void) AUD_exit(); } +void sound_exit_once(void) +{ + AUD_exit(); + AUD_exitOnce(); +} + // XXX unused currently #if 0 bSound *sound_new_buffer(struct Main *bmain, bSound *source) @@ -766,6 +772,11 @@ float sound_get_length(bSound *sound) return info.length; } +int sound_is_jack_supported(void) +{ + return AUD_isJackSupported(); +} + #else // WITH_AUDASPACE #include "BLI_utildefines.h" @@ -775,6 +786,7 @@ void sound_force_device(int UNUSED(device)) {} void sound_init_once(void) {} void sound_init(struct Main *UNUSED(bmain)) {} void sound_exit(void) {} +void sound_exit_once(void) {} void sound_cache(struct bSound *UNUSED(sound)) { } void sound_delete_cache(struct bSound *UNUSED(sound)) {} void sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {} @@ -807,4 +819,5 @@ void sound_set_scene_sound_pan(void *handle, float pan, char animated) { (void)h void sound_set_scene_volume(struct Scene *scene, float volume) { (void)scene; (void)volume; } void sound_set_scene_sound_pitch(void *handle, float pitch, char animated) { (void)handle; (void)pitch; (void)animated; } float sound_get_length(struct bSound *sound) { (void)sound; return 0; } +int sound_is_jack_supported(void) { return 0; } #endif // WITH_AUDASPACE diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 3936c533a41..29f16775598 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -804,7 +804,7 @@ int txt_utf8_offset_to_column(const char *str, int offset) int txt_utf8_column_to_offset(const char *str, int column) { int offset = 0, pos = 0, col; - while (pos < column) { + while (*(str + offset) && pos < column) { col = BLI_str_utf8_char_width_safe(str + offset); if (pos + col > column) break; @@ -827,17 +827,6 @@ static int txt_utf8_len(const char *src) return len; } -static int txt_utf8_width(const char *src) -{ - int col = 0; - - for (; *src; src += BLI_str_utf8_size(src)) { - col += BLI_str_utf8_char_width(src); - } - - return col; -} - void txt_move_up(Text *text, short sel) { TextLine **linep; @@ -851,8 +840,7 @@ void txt_move_up(Text *text, short sel) if ((*linep)->prev) { int column = txt_utf8_offset_to_column((*linep)->line, *charp); *linep = (*linep)->prev; - if (column > txt_utf8_width((*linep)->line)) *charp = (*linep)->len; - else *charp = txt_utf8_column_to_offset((*linep)->line, column); + *charp = txt_utf8_column_to_offset((*linep)->line, column); } else { @@ -875,8 +863,7 @@ void txt_move_down(Text *text, short sel) if ((*linep)->next) { int column = txt_utf8_offset_to_column((*linep)->line, *charp); *linep = (*linep)->next; - if (column > txt_utf8_width((*linep)->line)) *charp = (*linep)->len; - else *charp = txt_utf8_column_to_offset((*linep)->line, column); + *charp = txt_utf8_column_to_offset((*linep)->line, column); } else { txt_move_eol(text, sel); diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index bcba2715740..6b9b371a4f3 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -135,7 +135,10 @@ int BLI_stringdec(const char *string, char *head, char *tail, unsigned short *nu else { if (tail) strcpy(tail, string + name_end); if (head) { - BLI_strncpy(head, string, name_end); + /* name_end points to last character of head, + * make it +1 so null-terminator is nicely placed + */ + BLI_strncpy(head, string, name_end + 1); } if (numlen) *numlen = 0; return 0; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a425928130d..a6dc4d242e9 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4775,11 +4775,14 @@ static void direct_link_object(FileData *fd, Object *ob) /* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */ ob->flag &= ~OB_FROMGROUP; - + /* loading saved files with editmode enabled works, but for undo we like - * to stay in object mode during undo presses so keep editmode disabled */ - if (fd->memfile) + * to stay in object mode during undo presses so keep editmode disabled. + * + * Also when linking in a file don't allow editmode: [#34776] */ + if (fd->memfile || (ob->id.flag & (LIB_EXTERN | LIB_INDIRECT))) { ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT); + } ob->disp.first = ob->disp.last = NULL; @@ -8876,7 +8879,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* Fix for bug #32982, internal_links list could get corrupted from r51630 onward. * Simply remove bad internal_links lists to avoid NULL pointers. */ - FOREACH_NODETREE(main, ntree, id) + FOREACH_NODETREE(main, ntree, id) { bNode *node; bNodeLink *link, *nextlink; @@ -8888,7 +8891,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } - FOREACH_NODETREE_END + } FOREACH_NODETREE_END } if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 6)) { diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index c21da46d678..fcf804c8f4f 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -45,6 +45,8 @@ set(SRC operators/bmo_create.c operators/bmo_dissolve.c operators/bmo_dupe.c + operators/bmo_edgeloop_fill.c + operators/bmo_edgenet.c operators/bmo_edgesplit.c operators/bmo_extrude.c operators/bmo_hull.c diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index fddb7b4bf2c..5599dd6bc28 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -171,7 +171,7 @@ void BM_face_copy_shared(BMesh *bm, BMFace *f) * #BM_face_create should be considered over this function as it * avoids some unnecessary work. */ -BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, const int create_flag) +BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, const int create_flag) { BMEdge **edges_sort = BLI_array_alloca(edges_sort, len); BMVert **verts_sort = BLI_array_alloca(verts_sort, len + 1); @@ -308,6 +308,72 @@ err: return NULL; } +/** + * Create an ngon from an array of sorted verts + * + * Special features this has over other functions. + * - Optionally calculate winding based on surrounding edges. + * - Optionally create edges between vertices. + * - Uses verts so no need to find edges (handy when you only have verts) + */ +BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, const int create_flag, + const bool calc_winding, const bool create_edges) +{ + BMEdge **edge_arr = BLI_array_alloca(edge_arr, len); + unsigned int winding[2] = {0, 0}; + int i, i_prev = len - 1; + + BLI_assert(len > 2); + + for (i = 0; i < len; i++) { + if (create_edges) { + edge_arr[i] = BM_edge_create(bm, vert_arr[i_prev], vert_arr[i], NULL, BM_CREATE_NO_DOUBLE); + } + else { + edge_arr[i] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]); + if (edge_arr[i] == NULL) { + return NULL; + } + } + + if (calc_winding) { + /* the edge may exist already and be attached to a face + * in this case we can find the best winding to use for the new face */ + if (edge_arr[i]->l) { + BMVert *test_v1, *test_v2; + /* we want to use the reverse winding to the existing order */ + BM_edge_ordered_verts(edge_arr[i], &test_v2, &test_v1); + winding[(vert_arr[i_prev] == test_v2)]++; + } + } + + i_prev = i; + } + + /* --- */ + + if (calc_winding) { + if (winding[0] < winding[1]) { + winding[0] = 1; + winding[1] = 0; + } + else { + winding[0] = 0; + winding[1] = 1; + } + } + else { + winding[0] = 0; + winding[1] = 1; + } + + /* --- */ + + /* create the face */ + return BM_face_create_ngon(bm, vert_arr[winding[0]], vert_arr[winding[1]], edge_arr, len, create_flag); +} + + typedef struct AngleIndexPair { float angle; int index; @@ -337,11 +403,11 @@ static int angle_index_pair_cmp(const void *e1, const void *e2) * * \note Since this is a vcloud there is no direction. */ -BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int totv, const int create_flag) +BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const int create_flag) { BMFace *f; - float totv_inv = 1.0f / (float)totv; + float totv_inv = 1.0f / (float)len; int i = 0; float cent[3], nor[3]; @@ -358,21 +424,17 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int totv, const AngleIndexPair *vang; BMVert **vert_arr_map; - BMEdge **edge_arr; - int i_prev; - - unsigned int winding[2] = {0, 0}; /* get the center point and collect vector array since we loop over these a lot */ zero_v3(cent); - for (i = 0; i < totv; i++) { + for (i = 0; i < len; i++) { madd_v3_v3fl(cent, vert_arr[i]->co, totv_inv); } /* find the far point from cent */ far_best = 0.0f; - for (i = 0; i < totv; i++) { + for (i = 0; i < len; i++) { far_dist = len_squared_v3v3(vert_arr[i]->co, cent); if (far_dist > far_best || far == NULL) { far = vert_arr[i]->co; @@ -387,7 +449,7 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int totv, const /* find a point 90deg about to compare with */ far_cross_best = 0.0f; - for (i = 0; i < totv; i++) { + for (i = 0; i < len; i++) { if (far == vert_arr[i]->co) { continue; @@ -422,9 +484,9 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int totv, const /* --- */ /* now calculate every points angle around the normal (signed) */ - vang = MEM_mallocN(sizeof(AngleIndexPair) * totv, __func__); + vang = MEM_mallocN(sizeof(AngleIndexPair) * len, __func__); - for (i = 0; i < totv; i++) { + for (i = 0; i < len; i++) { float co[3]; float proj_vec[3]; float angle; @@ -448,53 +510,20 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int totv, const } /* sort by angle and magic! - we have our ngon */ - qsort(vang, totv, sizeof(AngleIndexPair), angle_index_pair_cmp); + qsort(vang, len, sizeof(AngleIndexPair), angle_index_pair_cmp); /* --- */ /* create edges and find the winding (if faces are attached to any existing edges) */ - vert_arr_map = MEM_mallocN(sizeof(BMVert **) * totv, __func__); - edge_arr = MEM_mallocN(sizeof(BMEdge **) * totv, __func__); + vert_arr_map = MEM_mallocN(sizeof(BMVert **) * len, __func__); - for (i = 0; i < totv; i++) { + for (i = 0; i < len; i++) { vert_arr_map[i] = vert_arr[vang[i].index]; } MEM_freeN(vang); - i_prev = totv - 1; - for (i = 0; i < totv; i++) { - edge_arr[i] = BM_edge_create(bm, vert_arr_map[i_prev], vert_arr_map[i], NULL, BM_CREATE_NO_DOUBLE); - - /* the edge may exist already and be attached to a face - * in this case we can find the best winding to use for the new face */ - if (edge_arr[i]->l) { - BMVert *test_v1, *test_v2; - /* we want to use the reverse winding to the existing order */ - BM_edge_ordered_verts(edge_arr[i], &test_v2, &test_v1); - winding[(vert_arr_map[i_prev] == test_v2)]++; - - } - - i_prev = i; - } - - /* --- */ - - if (winding[0] < winding[1]) { - winding[0] = 1; - winding[1] = 0; - } - else { - winding[0] = 0; - winding[1] = 1; - } - - /* --- */ - - /* create the face */ - f = BM_face_create_ngon(bm, vert_arr_map[winding[0]], vert_arr_map[winding[1]], edge_arr, totv, create_flag); + f = BM_face_create_ngon_verts(bm, vert_arr_map, len, create_flag, true, true); - MEM_freeN(edge_arr); MEM_freeN(vert_arr_map); return f; diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 0f597dbb1d8..949366309b9 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -36,7 +36,9 @@ BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, B void BM_face_copy_shared(BMesh *bm, BMFace *f); -BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, const int create_flag); +BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, const int create_flag); +BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, const int create_flag, + const bool calc_winding, const bool create_edges); BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const int create_flag); diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index a11d45a7a5a..f46f73c5350 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -308,7 +308,13 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm, const eBMCreateFlag creat } /** - * \brief Main face creation function + * Main face creation function + * + * \param bm The mesh + * \param verts A sorted array of verts size of len + * \param edges A sorted array of edges size of len + * \param len Length of the face + * \param create_flag Options for creating the face */ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, const eBMCreateFlag create_flag) { diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index 44b76df7432..a1dde035224 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -170,7 +170,7 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons BMElem *ele; int count = 0; - for (ele = BM_iter_new(&iter, NULL, itype, data); ele; ele = BM_iter_step(&iter)) { + BM_ITER_ELEM (ele, &iter, data, itype) { if (BM_elem_flag_test_bool(ele, hflag) == value) { count++; } @@ -180,6 +180,30 @@ int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, cons } /** + * \brief Elem Iter Tool Flag Count + * + * Counts how many flagged / unflagged items are found in this element. + */ +int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, + const short oflag, const bool value) +{ + BMIter iter; + BMElemF *ele; + int count = 0; + + /* loops have no header flags */ + BLI_assert(bm_iter_itype_htype_map[itype] != BM_LOOP); + + BM_ITER_ELEM (ele, &iter, data, itype) { + if (BMO_elem_flag_test_bool(bm, ele, oflag) == value) { + count++; + } + } + return count; +} + + +/** * \brief Mesh Iter Flag Count * * Counts how many flagged / unflagged items are found in this mesh. @@ -190,7 +214,7 @@ int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const BMElem *ele; int count = 0; - for (ele = BM_iter_new(&iter, bm, itype, NULL); ele; ele = BM_iter_step(&iter)) { + BM_ITER_MESH (ele, &iter, bm, itype) { if (BM_elem_flag_test_bool(ele, hflag) == value) { count++; } diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h index 3b795a253bd..5fb226ae11d 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.h +++ b/source/blender/bmesh/intern/bmesh_iterators.h @@ -132,6 +132,7 @@ __attribute__((warn_unused_result)) #endif ; int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value); +int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value); int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value); /* private for bmesh_iterators_inline.c */ diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 869c894b66c..7583332c4db 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -527,6 +527,30 @@ static BMOpDefine bmo_bridge_loops_def = { }; /* + * Edge Loop Fill. + * + * Create faces defined by one or more non overlapping edge loops. + */ +static BMOpDefine bmo_edgeloop_fill_def = { + "edgeloop_fill", + /* slots_in */ + {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ + /* restricts edges to groups. maps edges to integer */ + {"mat_nr", BMO_OP_SLOT_INT}, /* material to use */ + {"use_smooth", BMO_OP_SLOT_BOOL}, /* smooth state to use */ + {{'\0'}}, + }, + /* slots_out */ + /* maps new faces to the group numbers they came from */ + {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* new faces */ + {{'\0'}}, + }, + bmo_edgeloop_fill_exec, + 0, +}; + + +/* * Edge Net Fill. * * Create faces defined by enclosed edges. @@ -541,7 +565,7 @@ static BMOpDefine bmo_edgenet_fill_def = { {"use_fill_check", BMO_OP_SLOT_BOOL}, {"exclude_faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* list of faces to ignore for manifold check */ {"mat_nr", BMO_OP_SLOT_INT}, /* material to use */ - {"use_smooth", BMO_OP_SLOT_BOOL}, /* material to use */ + {"use_smooth", BMO_OP_SLOT_BOOL}, /* smooth state to use */ {{'\0'}}, }, /* slots_out */ @@ -1615,6 +1639,7 @@ const BMOpDefine *bmo_opdefines[] = { &bmo_dissolve_limit_def, &bmo_dissolve_verts_def, &bmo_duplicate_def, + &bmo_edgeloop_fill_def, &bmo_edgenet_fill_def, &bmo_edgenet_prepare_def, &bmo_extrude_discrete_faces_def, diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index 978aec0c610..180bc53c2e3 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -83,7 +83,7 @@ struct GHashIterator; #define BMO_elem_flag_toggle( bm, ele, oflag) _bmo_elem_flag_toggle (bm, (ele)->oflags, oflag) BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, BMFlagLayer *oflags, const short oflag); -BLI_INLINE short _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag); +BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_enable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_disable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_set( BMesh *bm, BMFlagLayer *oflags, const short oflag, int val); @@ -391,10 +391,6 @@ int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data, const int len); -/* Counts the number of edges with tool flag toolflag around - */ -int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag); - /* flags all elements in a mapping. note that the mapping must only have * bmesh elements in it.*/ void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h index 0e1d4fec4d3..724ddcf3b04 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h +++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h @@ -43,7 +43,7 @@ BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short return oflags[bm->stackdepth - 1].f & oflag; } -BLI_INLINE short _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag) +BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag) { return (oflags[bm->stackdepth - 1].f & oflag) != 0; } diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index f52dd7f2be9..a358623834f 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -1075,25 +1075,6 @@ void BMO_slot_buffer_hflag_disable(BMesh *bm, } } -int BMO_vert_edge_flags_count(BMesh *bm, BMVert *v, const short oflag) -{ - int count = 0; - - if (v->e) { - BMEdge *curedge; - const int len = bmesh_disk_count(v); - int i; - - for (i = 0, curedge = v->e; i < len; i++) { - if (BMO_elem_flag_test(bm, curedge, oflag)) - count++; - curedge = bmesh_disk_edge_next(curedge, v); - } - } - - return count; -} - /** * \brief BMO_FLAG_BUFFER * diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h index 1aa4383d761..79e688bd5ff 100644 --- a/source/blender/bmesh/intern/bmesh_operators_private.h +++ b/source/blender/bmesh/intern/bmesh_operators_private.h @@ -57,6 +57,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op); void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op); void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op); void bmo_duplicate_exec(BMesh *bm, BMOperator *op); +void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op); void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op); void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op); void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op); diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index 9fab89f8e0a..86904155cd3 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -27,1247 +27,13 @@ #include "MEM_guardedalloc.h" #include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_array.h" -#include "BLI_smallhash.h" -#include "BLI_rand.h" -#include "BLI_heap.h" #include "bmesh.h" #include "intern/bmesh_operators_private.h" /* own include */ -#define EDGE_MARK 1 -#define EDGE_VIS 2 - -#define FACE_NEW 1 - #define ELE_NEW 1 #define ELE_OUT 2 -#define ELE_ORIG 4 - -#define FACE_IGNORE 16 - -typedef struct EPathNode { - struct EPathNode *next, *prev; - BMVert *v; - BMEdge *e; - BMEdge *cure; -} EPathNode; - -typedef struct EPath { - ListBase nodes; - float weight; - int group; -} EPath; - -typedef struct PathBase { - BLI_mempool *nodepool, *pathpool; -} PathBase; - -typedef struct EdgeData { - int tag; - int ftag; - BMDiskLink v1_disk_link, v2_disk_link; -} EdgeData; - -typedef struct VertData { - BMEdge *e; - float no[3], offco[3], sco[3]; /* offco is vertex coordinate slightly offset randomly */ - int tag; -} VertData; - -static int count_edge_faces(BMesh *bm, BMEdge *e); - -/**** rotation system code * */ - -BLI_INLINE BMDiskLink *rs_edge_link_get(BMEdge *e, BMVert *v, EdgeData *e_data) -{ - return v == ((BMEdge *)e)->v1 ? &(((EdgeData *)e_data)->v1_disk_link) : - &(((EdgeData *)e_data)->v2_disk_link); -} - -static bool rotsys_append_edge(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *vdata) -{ - EdgeData *ed = &edata[BM_elem_index_get(e)]; - VertData *vd = &vdata[BM_elem_index_get(v)]; - - if (!vd->e) { - Link *e1 = (Link *)rs_edge_link_get(e, v, ed); - - vd->e = e; - e1->next = e1->prev = (Link *)e; - } - else { - BMDiskLink *dl1, *dl2, *dl3; - EdgeData *ved = &edata[BM_elem_index_get(vd->e)]; - - dl1 = rs_edge_link_get(e, v, ed); - dl2 = rs_edge_link_get(vd->e, v, ved); - dl3 = dl2->prev ? rs_edge_link_get(dl2->prev, v, &edata[BM_elem_index_get(dl2->prev)]) : NULL; - - dl1->next = vd->e; - dl1->prev = dl2->prev; - - dl2->prev = e; - if (dl3) { - dl3->next = e; - } - } - - return true; -} - -static void UNUSED_FUNCTION(rotsys_remove_edge)(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *vdata) -{ - EdgeData *ed = edata + BM_elem_index_get(e); - VertData *vd = vdata + BM_elem_index_get(v); - BMDiskLink *e1, *e2; - - e1 = rs_edge_link_get(e, v, ed); - if (e1->prev) { - e2 = rs_edge_link_get(e1->prev, v, ed); - e2->next = e1->next; - } - - if (e1->next) { - e2 = rs_edge_link_get(e1->next, v, ed); - e2->prev = e1->prev; - } - - if (vd->e == e) - vd->e = (e != e1->next) ? e1->next : NULL; - - e1->next = e1->prev = NULL; -} - -static BMEdge *rotsys_nextedge(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *UNUSED(vdata)) -{ - if (v == e->v1) - return edata[BM_elem_index_get(e)].v1_disk_link.next; - if (v == e->v2) - return edata[BM_elem_index_get(e)].v2_disk_link.next; - return NULL; -} - -static BMEdge *rotsys_prevedge(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *UNUSED(vdata)) -{ - if (v == e->v1) - return edata[BM_elem_index_get(e)].v1_disk_link.prev; - if (v == e->v2) - return edata[BM_elem_index_get(e)].v2_disk_link.prev; - return NULL; -} - -static void rotsys_reverse(BMEdge *UNUSED(e), BMVert *v, EdgeData *edata, VertData *vdata) -{ - BMEdge **edges = NULL; - BMEdge *e_first; - BMEdge *e; - BLI_array_staticdeclare(edges, BM_DEFAULT_NGON_STACK_SIZE); - int i, totedge; - - e = e_first = vdata[BM_elem_index_get(v)].e; - do { - BLI_array_append(edges, e); - e = rotsys_nextedge(e, v, edata, vdata); - } while (e != e_first); - - totedge = BLI_array_count(edges); - for (i = 0; i < totedge / 2; i++) { - SWAP(BMEdge *, edges[i], edges[totedge - 1 - i]); - } - - vdata[BM_elem_index_get(v)].e = NULL; - for (i = 0; i < totedge; i++) { - rotsys_append_edge(edges[i], v, edata, vdata); - } - - BLI_array_free(edges); -} - -static int UNUSED_FUNCTION(rotsys_count)(BMVert *v, EdgeData *edata, VertData *vdata) -{ - BMEdge *e = vdata[BM_elem_index_get(v)].e; - int i = 0; - - if (!e) - return 0; - - do { - if (!e) - return 0; - e = rotsys_nextedge(e, v, edata, vdata); - - if (i >= (1 << 20)) { - printf("bmesh error: infinite loop in disk cycle!\n"); - return 0; - } - - i += 1; - } while (e != vdata[BM_elem_index_get(v)].e); - - return i; -} - -static int UNUSED_FUNCTION(rotsys_fill_faces)(BMesh *bm, EdgeData *edata, VertData *vdata) -{ - BMIter iter; - BMEdge *e, **edges = NULL; - BLI_array_declare(edges); - BMVert *v, **verts = NULL; - BMFace *f; - BLI_array_declare(verts); - SmallHash visithash, *hash = &visithash; - int i; - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BMEdge *e2, *starte; - BMVert *startv; - int rad, ok; - - rad = count_edge_faces(bm, e); - - if (rad < 2) { - starte = e; - } - else { - continue; - } - - /* do two passes, going forward then backward */ - for (i = 0; i < 2; i++) { - BLI_smallhash_init(hash); - - BLI_array_empty(verts); - BLI_array_empty(edges); - - startv = v = starte->v1; - e2 = starte; - ok = 1; - if (!v || !e2) - continue; - - do { - if (BLI_smallhash_haskey(hash, (intptr_t)e2) || - BLI_smallhash_haskey(hash, (intptr_t)v)) - { - ok = 0; - break; - } - - BLI_array_append(verts, v); - BLI_array_append(edges, e2); - - BLI_smallhash_insert(hash, (intptr_t)e2, NULL); - - v = BM_edge_other_vert(e2, v); - e2 = i ? rotsys_prevedge(e2, v, edata, vdata) : rotsys_nextedge(e2, v, edata, vdata); - } while (e2 != starte && v != startv); - - BLI_smallhash_release(hash); - - if (!ok || BLI_array_count(edges) < 3) - continue; - - f = BM_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), BM_CREATE_NO_DOUBLE); - if (UNLIKELY(f == NULL)) { - continue; - } - } - } - - return 0; -} - -static void rotsys_make_consistent(BMesh *bm, EdgeData *edata, VertData *vdata) -{ - BMIter iter; - BMEdge *e; - BMVert *v, **stack = NULL; - BLI_array_declare(stack); - int i; - - for (i = 0; i < bm->totvert; i++) { - vdata[i].tag = 0; - } - - while (1) { - VertData *vd; - BMVert *startv = NULL; - float dis; - - v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); - for (i = 0; i < bm->totvert; i++, BM_iter_step(&iter)) { - vd = vdata + BM_elem_index_get(v); - - if (vd->tag) - continue; - - if (!startv || dot_v3v3(vd->offco, vd->offco) > dis) { - dis = dot_v3v3(vd->offco, vd->offco); - startv = v; - } - } - - if (!startv) - break; - - vd = vdata + BM_elem_index_get(startv); - - BLI_array_empty(stack); - BLI_array_append(stack, startv); - - vd->tag = 1; - - while (BLI_array_count(stack)) { - v = BLI_array_pop(stack); - vd = vdata + BM_elem_index_get(v); - - if (!vd->e) - continue; - - e = vd->e; - do { - BMVert *v2 = BM_edge_other_vert(e, v); - VertData *vd2 = vdata + BM_elem_index_get(v2); - - if (dot_v3v3(vd->no, vd2->no) < 0.0f + FLT_EPSILON * 2) { - rotsys_reverse(e, v2, edata, vdata); - mul_v3_fl(vd2->no, -1.0f); - } - - if (!vd2->tag) { - BLI_array_append(stack, v2); - vd2->tag = 1; - } - - e = rotsys_nextedge(e, v, edata, vdata); - } while (e != vd->e); - } - } - - BLI_array_free(stack); -} - -static void init_rotsys(BMesh *bm, EdgeData *edata, VertData *vdata) -{ - BMIter iter; - BMEdge *e; - BMEdge **edges = NULL; - BLI_array_staticdeclare(edges, BM_DEFAULT_NGON_STACK_SIZE); - BMVert *v; - /* BMVert **verts = NULL; */ - /* BLI_array_staticdeclare(verts, BM_DEFAULT_NGON_STACK_SIZE); */ /* UNUSE */ - int i; - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMIter eiter; - float no[3], cent[3]; - int j, k = 0, totedge = 0; - - if (BM_elem_index_get(v) == -1) - continue; - - BLI_array_empty(edges); - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { - BLI_array_append(edges, e); - totedge++; - } - } - - copy_v3_v3(cent, v->co); - - zero_v3(no); - for (i = 0; i < totedge; i++) { - BMEdge *e1, *e2; - float cno[3], vec1[3], vec2[3]; - - e1 = edges[i]; - e2 = edges[(i + 1) % totedge]; - - sub_v3_v3v3(vec1, (BM_edge_other_vert(e1, v))->co, v->co); - sub_v3_v3v3(vec2, (BM_edge_other_vert(e2, v))->co, v->co); - - cross_v3_v3v3(cno, vec1, vec2); - normalize_v3(cno); - - if (i && dot_v3v3(cno, no) < 0.0f + FLT_EPSILON * 10) - mul_v3_fl(cno, -1.0f); - - add_v3_v3(no, cno); - normalize_v3(no); - } - - /* generate plane-flattened coordinates */ - for (i = 0; i < totedge; i++) { - BMEdge *e1; - BMVert *v2; - float cvec[3], vec1[3]; - - e1 = edges[i]; - v2 = BM_edge_other_vert(e1, v); - - sub_v3_v3v3(vec1, v2->co, v->co); - - cross_v3_v3v3(cvec, vec1, no); - cross_v3_v3v3(vec1, cvec, no); - normalize_v3(vec1); - - mul_v3_fl(vec1, len_v3v3(v2->co, v->co)); - add_v3_v3(vec1, v->co); - - copy_v3_v3(vdata[BM_elem_index_get(v2)].sco, vec1); - } - - BLI_srandom(0); - - /* first, ensure no 0 or 180 angles between adjacent - * (and that adjacent's adjacent) edges */ - for (i = 0, k = 0; i < totedge; i++) { - BMEdge *e1, *e2, *e3 = NULL; - BMVert *v1, *v2, *v3; - VertData *vd1, *vd2, *vd3; - float vec1[3], vec2[3], vec3[3], size; - int s1, s2, s3; - - if (totedge < 3) - continue; - - e1 = edges[(i + totedge - 1) % totedge]; - e2 = edges[i]; - e3 = edges[(i + 1) % totedge]; - - v1 = BM_edge_other_vert(e1, v); - v2 = BM_edge_other_vert(e2, v); - v3 = BM_edge_other_vert(e3, v); - - vd1 = vdata + BM_elem_index_get(v1); - vd2 = vdata + BM_elem_index_get(v2); - vd3 = vdata + BM_elem_index_get(v3); - - sub_v3_v3v3(vec1, vd1->sco, cent); - sub_v3_v3v3(vec2, vd2->sco, cent); - sub_v3_v3v3(vec3, vd3->sco, cent); - - size = (len_v3(vec1) + len_v3(vec3)) * 0.01f; - normalize_v3(vec1); normalize_v3(vec2); normalize_v3(vec3); - -#ifdef STRAIGHT -#undef STRAIGHT -#endif -#define STRAIGHT(vec11, vec22) (fabsf(dot_v3v3((vec11), (vec22))) > 1.0f - ((float)FLT_EPSILON * 1000.0f)) - - s1 = STRAIGHT(vec1, vec2); s2 = STRAIGHT(vec2, vec3); s3 = STRAIGHT(vec1, vec3); - - if (s1 || s2 || s3) { - copy_v3_v3(cent, v->co); - - for (j = 0; j < 3; j++) { - float fac = (BLI_frand() - 0.5f) * size; - cent[j] += fac; - } - - if (k < 2000) { - i = 0; - k++; - continue; - } - else { - k++; - continue; - } - - } - } - - copy_v3_v3(vdata[BM_elem_index_get(v)].offco, cent); - //copy_v3_v3(v->co, cent); - - /* now, sort edges so the triangle fan of all edges - * has a consistent normal. this is the same as - * sorting by polar coordinates along a group normal */ - for (j = 0; j < totedge; j++) { - for (i = 0; i < totedge; i++) { - BMEdge *e1, *e2, *e3 = NULL; - BMVert *v1, *v2, *v3; - VertData *vd1, *vd2, *vd3; - float vec1[3], vec2[3], vec3[3], n1[3], n2[3], n3[3]; - - e1 = edges[(i + totedge - 1) % totedge]; - e2 = edges[i]; - e3 = edges[(i + 1) % totedge]; - - v1 = BM_edge_other_vert(e1, v); - v2 = BM_edge_other_vert(e2, v); - v3 = BM_edge_other_vert(e3, v); - - vd1 = vdata + BM_elem_index_get(v1); - vd2 = vdata + BM_elem_index_get(v2); - vd3 = vdata + BM_elem_index_get(v3); - - sub_v3_v3v3(vec1, vd1->sco, cent); - sub_v3_v3v3(vec2, vd2->sco, cent); - sub_v3_v3v3(vec3, vd3->sco, cent); - - cross_v3_v3v3(n1, vec1, vec2); - cross_v3_v3v3(n2, vec2, vec3); - cross_v3_v3v3(n3, vec1, vec3); - - /* this case happens often enough and probably not worth bothering users with, - * maybe enable for debugging code but not for everyday use - campbell */ -#if 0 - /* Other way to determine if two vectors approach are (nearly) parallel: the - * cross product of the two vectors will approach zero */ - { - int s1, s2, s3; - s1 = (dot_v3v3(n1, n1) < (0.0f + FLT_EPSILON * 10)); - s2 = (dot_v3v3(n2, n2) < (0.0f + FLT_EPSILON * 10)); - s3 = (totedge < 3) ? 0 : (dot_v3v3(n3, n3) < (0.0f + FLT_EPSILON * 10)); - - if (s1 || s2 || s3) { - fprintf(stderr, "%s: s1: %d, s2: %d, s3: %dx (bmesh internal error)\n", __func__, s1, s2, s3); - } - } -#endif - - normalize_v3(n1); normalize_v3(n2); normalize_v3(n3); - - - if (dot_v3v3(n1, n2) < 0.0f) { - if (dot_v3v3(n1, n3) >= 0.0f + FLT_EPSILON * 10) { - SWAP(BMEdge *, edges[i], edges[(i + 1) % totedge]); - } - else { - SWAP(BMEdge *, edges[(i + totedge - 1) % totedge], edges[(i + 1) % totedge]); - SWAP(BMEdge *, edges[i], edges[(i + 1) % totedge]); - } - } - } - } - -#undef STRAIGHT - - zero_v3(no); - - /* yay, edges are sorted */ - for (i = 0; i < totedge; i++) { - BMEdge *e1 = edges[i], *e2 = edges[(i + 1) % totedge]; - float eno[3]; - - normal_tri_v3(eno, BM_edge_other_vert(e1, v)->co, v->co, BM_edge_other_vert(e2, v)->co); - add_v3_v3(no, eno); - - rotsys_append_edge(edges[i], v, edata, vdata); - } - - normalize_v3(no); - copy_v3_v3(vdata[BM_elem_index_get(v)].no, no); - } - - /* now, make sure rotation system is topologically consistent - * (e.g. vert normals consistently point either inside or outside) */ - rotsys_make_consistent(bm, edata, vdata); - - //rotsys_fill_faces(bm, edata, vdata); - -#if 0 - /* create visualizing geometry */ - BMVert *lastv; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMVert *v2; - BMFace *f; - int totedge = BM_vert_edge_count(v); - - if (BM_elem_index_get(v) == -1) - continue; - - //cv = BM_vert_create(bm, cent, v); - //BM_elem_index_set(cv, -1); /* set_dirty! */ - i = 0; - e = vdata[BM_elem_index_get(v)].e; - lastv = NULL; - do { - BMEdge *e2; - BMVert *v2; - float f = ((float)i / (float)totedge) * 0.35 + 0.05; - float co[3]; - - if (!e) - break; - - if (!BM_edge_other_vert(e, v)) - continue; - - sub_v3_v3v3(co, (BM_edge_other_vert(e, v))->co, vdata[BM_elem_index_get(v)].offco); - mul_v3_fl(co, f); - add_v3_v3(co, vdata[BM_elem_index_get(v)].offco); - - v2 = BM_vert_create(bm, co, NULL); - BM_elem_index_set(v2, -1); /* set_dirty! */ - //BM_edge_create(bm, cv, v2, NULL, 0); - - BM_vert_select_set(bm, v2, true); - if (lastv) { - e2 = BM_edge_create(bm, lastv, v2, NULL, 0); - BM_edge_select_set(bm, e2, true); - } - - lastv = v2; - - e = rotsys_nextedge(e, v, edata, vdata); - i++; - } while (e != vdata[BM_elem_index_get(v)].e); - } -#endif - - BLI_array_free(edges); -} - -static PathBase *edge_pathbase_new(void) -{ - PathBase *pb = MEM_callocN(sizeof(PathBase), "PathBase"); - - pb->nodepool = BLI_mempool_create(sizeof(EPathNode), 1, 512, BLI_MEMPOOL_SYSMALLOC); - pb->pathpool = BLI_mempool_create(sizeof(EPath), 1, 512, BLI_MEMPOOL_SYSMALLOC); - - return pb; -} - -static void edge_pathbase_free(PathBase *pathbase) -{ - BLI_mempool_destroy(pathbase->nodepool); - BLI_mempool_destroy(pathbase->pathpool); - MEM_freeN(pathbase); -} - -static EPath *edge_copy_add_path(PathBase *pb, EPath *path, BMVert *appendv, BMEdge *e) -{ - EPath *path2; - EPathNode *node, *node2; - - path2 = BLI_mempool_alloc(pb->pathpool); - path2->nodes.first = path2->nodes.last = NULL; - path2->weight = 0.0f; - path2->group = path->group; - - for (node = path->nodes.first; node; node = node->next) { - node2 = BLI_mempool_alloc(pb->nodepool); - *node2 = *node; - BLI_addtail(&path2->nodes, node2); - } - - node2 = BLI_mempool_alloc(pb->nodepool); - node2->v = appendv; - node2->e = e; - node2->cure = NULL; - - BLI_addtail(&path2->nodes, node2); - - return path2; -} - -static EPath *edge_path_new(PathBase *pb, BMVert *start, BMEdge *starte) -{ - EPath *path; - EPathNode *node; - - path = BLI_mempool_alloc(pb->pathpool); - node = BLI_mempool_alloc(pb->nodepool); - - path->nodes.first = path->nodes.last = NULL; - - node->v = start; - node->e = starte; - node->cure = NULL; - - BLI_addtail(&path->nodes, node); - path->weight = 0.0f; - - return path; -} - -static float edge_weight_path(EPath *path, EdgeData *edata, VertData *UNUSED(vdata)) -{ - EPathNode *node, *first = path->nodes.first; - float w = 0.0; - - for (node = path->nodes.first; node; node = node->next) { - if (node->e && node != path->nodes.first) { - w += edata[BM_elem_index_get(node->e)].ftag; - if (node->prev) { - /* BMESH_TOD */ - (void)first; - //w += len_v3v3(node->v->co, first->e->v1->co) * 0.0001f; - //w += len_v3v3(node->v->co, first->e->v2->co) * 0.0001f; - } - } - - w += 1.0f; - } - - return w; -} - - -static void edge_free_path(PathBase *pathbase, EPath *path) -{ - EPathNode *node, *next; - - for (node = path->nodes.first; node; node = next) { - next = node->next; - BLI_mempool_free(pathbase->nodepool, node); - } - - BLI_mempool_free(pathbase->pathpool, path); -} - -static EPath *edge_find_shortest_path(BMesh *bm, BMOperator *op, BMEdge *edge, EdgeData *edata, - VertData *vdata, PathBase *pathbase, int group) -{ - BMEdge *e; - GHash *gh = BLI_ghash_ptr_new("createops find shortest path"); - BMVert *v1, *v2; - BMVert **verts = NULL; - BLI_array_staticdeclare(verts, 1024); - Heap *heap = BLI_heap_new(); - EPath *path = NULL, *path2; - BMVert *startv; - BMVert *endv; - EPathNode *node; - int i; - const bool use_restrict = BMO_slot_bool_get(op->slots_in, "use_restrict"); - BMOpSlot *slot_restrict = BMO_slot_get(op->slots_in, "restrict"); - - - startv = edata[BM_elem_index_get(edge)].ftag ? edge->v2 : edge->v1; - endv = edata[BM_elem_index_get(edge)].ftag ? edge->v1 : edge->v2; - - path = edge_path_new(pathbase, startv, edge); - BLI_ghash_insert(gh, startv, NULL); - BLI_heap_insert(heap, path->weight, path); - path->group = group; - - while (BLI_heap_size(heap)) { - VertData *vd; - EPathNode *last; - BMFace *f = NULL; - - path = BLI_heap_popmin(heap); - last = path->nodes.last; - v1 = last->v; - - if (v1 == endv) { - /* make sure this path loop doesn't already exists */ - i = 0; - BLI_array_empty(verts); - for (i = 0, node = path->nodes.first; node; node = node->next, i++) { - BLI_array_grow_one(verts); - verts[i] = node->v; - } - - if (BM_face_exists(verts, i, &f)) { - if (!BMO_elem_flag_test(bm, f, FACE_IGNORE)) { - BLI_ghash_remove(gh, endv, NULL, NULL); - continue; - } - } - break; - } - - vd = vdata + BM_elem_index_get(v1); - if (!vd->e) - continue; - - v2 = NULL; - while (1) { - if (!last->cure) { - last->cure = e = vdata[BM_elem_index_get(last->v)].e; - } - else { - last->cure = e = rotsys_nextedge(last->cure, last->v, edata, vdata); - if (last->cure == vdata[BM_elem_index_get(last->v)].e) { - v2 = NULL; - break; - } - } - - if (e == edge || !BMO_elem_flag_test(bm, e, EDGE_MARK)) { - continue; - } - - v2 = BM_edge_other_vert(e, last->v); - - if (BLI_ghash_haskey(gh, v2)) { - v2 = NULL; - continue; - } - - if (use_restrict) { - int *group_flag = (int *)BMO_slot_map_data_get(slot_restrict, e); - if (group_flag) { - if (!(*group_flag & path->group)) { - v2 = NULL; - continue; - } - } - } - - break; - } - - if (!v2) { - if (path) { - edge_free_path(pathbase, path); - path = NULL; - } - continue; - } - - /* add path back into heap */ - BLI_heap_insert(heap, path->weight, path); - - /* put v2 in gh ma */ - BLI_ghash_insert(gh, v2, NULL); - - path2 = edge_copy_add_path(pathbase, path, v2, e); - path2->weight = edge_weight_path(path2, edata, vdata); - - BLI_heap_insert(heap, path2->weight, path2); - } - - if (path && ((EPathNode *)path->nodes.last)->v != endv) { - edge_free_path(pathbase, path); - path = NULL; - } - - BLI_array_free(verts); - BLI_heap_free(heap, NULL); - BLI_ghash_free(gh, NULL, NULL); - - return path; -} - -static int count_edge_faces(BMesh *bm, BMEdge *e) -{ - int i = 0; - BMLoop *l = e->l; - - if (!l) { - return 0; - } - - do { - if (!BMO_elem_flag_test(bm, l->f, FACE_IGNORE)) { - i++; - } - - l = l->radial_next; - } while (l != e->l); - - return i; -} - -BLI_INLINE void vote_on_winding(BMEdge *edge, EPathNode *node, unsigned int winding[2]) -{ - BMVert *test_v1, *test_v2; - /* we want to use the reverse winding to the existing order */ - BM_edge_ordered_verts(edge, &test_v2, &test_v1); - - /* edges vote on which winding wins out */ - winding[(test_v1 == node->v)]++; -} - -void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op) -{ - BMIter iter; - BMOIter siter; - BMFace *f; - BMEdge *e, *edge; - BMVert **verts = NULL; - BLI_array_declare(verts); - EPath *path; - EPathNode *node; - EdgeData *edata; - VertData *vdata; - BMEdge **edges = NULL; - PathBase *pathbase; - BLI_array_declare(edges); - const bool use_restrict = BMO_slot_bool_get(op->slots_in, "use_restrict"); - const bool use_fill_check = BMO_slot_bool_get(op->slots_in, "use_fill_check"); - const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); - const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); - int i, j, group = 0; - unsigned int winding[2]; /* accumulte winding directions for each edge which has a face */ - BMOpSlot *slot_restrict = BMO_slot_get(op->slots_in, "restrict"); - BMOpSlot *slot_face_groupmap_out = BMO_slot_get(op->slots_out, "face_groupmap.out"); - - if (!bm->totvert || !bm->totedge) - return; - - pathbase = edge_pathbase_new(); - - edata = MEM_callocN(sizeof(EdgeData) * bm->totedge, "EdgeData"); - vdata = MEM_callocN(sizeof(VertData) * bm->totvert, "VertData"); - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - BMO_slot_buffer_flag_enable(bm, op->slots_in, "exclude_faces", BM_FACE, FACE_IGNORE); - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMO_elem_flag_enable(bm, f, ELE_ORIG); - } - - BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { - BM_elem_index_set(e, i); /* set_inline */ - - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) { - edata[i].tag = 2; - } - } - bm->elem_index_dirty &= ~BM_EDGE; - - init_rotsys(bm, edata, vdata); - - while (1) { - edge = NULL; - group = 0; - - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - /* if restrict is on, only start on faces in the restrict map */ - if (use_restrict && !BMO_slot_map_contains(slot_restrict, e)) - continue; - - if (edata[BM_elem_index_get(e)].tag < 2) { - edge = e; - - if (use_restrict) { - int i = 0, j = 0, gi = 0; - - group = BMO_slot_map_int_get(slot_restrict, e); - - for (i = 0; i < 30; i++) { - if (group & (1 << i)) { - j++; - gi = i; - - if (j - 1 == edata[BM_elem_index_get(e)].tag) { - break; - } - } - } - - group = (1 << gi); - } - - break; - } - } - - if (!edge) - break; - - edata[BM_elem_index_get(edge)].tag += 1; - - path = edge_find_shortest_path(bm, op, edge, edata, vdata, pathbase, group); - if (!path) - continue; - - winding[0] = winding[1] = 0; - - BLI_array_empty(edges); - BLI_array_empty(verts); - i = 0; - for (node = path->nodes.first; node; node = node->next) { - if (!node->next) - continue; - - e = BM_edge_exists(node->v, node->next->v); - - /* this should never happe */ - if (!e) - break; - - /* check on the winding */ - if (e->l) { - vote_on_winding(e, node, winding); - } - - edata[BM_elem_index_get(e)].ftag++; - BLI_array_grow_one(edges); - edges[i++] = e; - - BLI_array_append(verts, node->v); - } - - if (edge->l) { - vote_on_winding(edge, path->nodes.last, winding); - } - - BLI_array_grow_one(edges); - edges[i++] = edge; - edata[BM_elem_index_get(edge)].ftag++; - - for (j = 0; j < i; j++) { - if (count_edge_faces(bm, edges[j]) >= 2) { - edge_free_path(pathbase, path); - break; - } - } - - if (j != i) { - continue; - } - - if (i) { - BMVert *v1, *v2; - - /* to define the winding order must select first edge, - * otherwise we could leave this as-is */ - edge = edges[0]; - - /* if these are even it doesn't really matter what to do, - * with consistent geometry one will be zero, the choice is clear */ - if (winding[0] < winding[1]) { - v1 = verts[0]; - v2 = verts[1]; - } - else { - v1 = verts[1]; - v2 = verts[0]; - } - - if ((use_fill_check == false) || - /* fairly expensive check - see if there are already faces filling this area */ - (BM_face_exists_multi_edge(edges, i) == false)) - { - f = BM_face_create_ngon(bm, v1, v2, edges, i, BM_CREATE_NO_DOUBLE); - if (f && !BMO_elem_flag_test(bm, f, ELE_ORIG)) { - BMO_elem_flag_enable(bm, f, FACE_NEW); - f->mat_nr = mat_nr; - if (use_smooth) { - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - } - } - - if (use_restrict) { - BMO_slot_map_int_insert(op, slot_face_groupmap_out, f, path->group); - } - } - } - - edge_free_path(pathbase, path); - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_NEW); - - BLI_array_free(edges); - BLI_array_free(verts); - edge_pathbase_free(pathbase); - MEM_freeN(edata); - MEM_freeN(vdata); -} - -static BMEdge *edge_next(BMesh *bm, BMEdge *e) -{ - BMIter iter; - BMEdge *e2; - int i; - - for (i = 0; i < 2; i++) { - BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) { - if ((BMO_elem_flag_test(bm, e2, EDGE_MARK)) && - (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) && - (e2 != e)) - { - return e2; - } - } - } - - return NULL; -} - -void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) -{ - BMOIter siter; - BMEdge *e; - BMEdge **edges1 = NULL, **edges2 = NULL, **edges; - BLI_array_declare(edges1); - BLI_array_declare(edges2); - BLI_array_declare(edges); - int ok = 1; - int i, count; - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - - /* validate that each edge has at most one other tagged edge in the - * disk cycle around each of it's vertices */ - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - for (i = 0; i < 2; i++) { - count = BMO_vert_edge_flags_count(bm, i ? e->v2 : e->v1, EDGE_MARK); - if (count > 2) { - ok = 0; - break; - } - } - - if (!ok) { - break; - } - } - - /* we don't have valid edge layouts, retur */ - if (!ok) { - return; - } - - /* find connected loops within the input edge */ - count = 0; - while (1) { - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) { - if (BMO_vert_edge_flags_count(bm, e->v1, EDGE_MARK) == 1 || - BMO_vert_edge_flags_count(bm, e->v2, EDGE_MARK) == 1) - { - break; - } - } - } - - if (!e) { - break; - } - - if (!count) { - edges = edges1; - } - else if (count == 1) { - edges = edges2; - } - else { - break; - } - - i = 0; - while (e) { - BMO_elem_flag_enable(bm, e, EDGE_VIS); - BLI_array_grow_one(edges); - edges[i] = e; - - e = edge_next(bm, e); - i++; - } - - if (!count) { - edges1 = edges; - BLI_array_length_set(edges1, BLI_array_count(edges)); - } - else { - edges2 = edges; - BLI_array_length_set(edges2, BLI_array_count(edges)); - } - - BLI_array_empty(edges); - count++; - } - - if (edges1 && BLI_array_count(edges1) > 2 && - BM_edge_share_vert_check(edges1[0], edges1[BLI_array_count(edges1) - 1])) - { - if (edges2 && BLI_array_count(edges2) > 2 && - BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) - { - BLI_array_free(edges1); - BLI_array_free(edges2); - return; - } - else { - edges1 = edges2; - edges2 = NULL; - } - } - - if (edges2 && BLI_array_count(edges2) > 2 && - BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) - { - edges2 = NULL; - } - - /* two unconnected loops, connect the */ - if (edges1 && edges2) { - BMVert *v1, *v2, *v3, *v4; - float dvec1[3]; - float dvec2[3]; - - if (BLI_array_count(edges1) == 1) { - v1 = edges1[0]->v1; - v2 = edges1[0]->v2; - } - else { - v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; - i = BLI_array_count(edges1) - 1; - v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; - } - - if (BLI_array_count(edges2) == 1) { - v3 = edges2[0]->v1; - v4 = edges2[0]->v2; - } - else { - v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1; - i = BLI_array_count(edges2) - 1; - v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1; - } - - /* if there is ever bow-tie quads between two edges the problem is here! [#30367] */ -#if 0 - normal_tri_v3(dvec1, v1->co, v2->co, v4->co); - normal_tri_v3(dvec2, v1->co, v4->co, v3->co); -#else - { - /* save some CPU cycles and skip the sqrt and 1 subtraction */ - float a1[3], a2[3], a3[3]; - sub_v3_v3v3(a1, v1->co, v2->co); - sub_v3_v3v3(a2, v1->co, v4->co); - sub_v3_v3v3(a3, v1->co, v3->co); - cross_v3_v3v3(dvec1, a1, a2); - cross_v3_v3v3(dvec2, a2, a3); - } -#endif - if (dot_v3v3(dvec1, dvec2) < 0.0f) { - SWAP(BMVert *, v3, v4); - } - - e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); - e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); - } - else if (edges1) { - BMVert *v1, *v2; - - if (BLI_array_count(edges1) > 1) { - v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; - i = BLI_array_count(edges1) - 1; - v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; - e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); - } - } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW); - - BLI_array_free(edges1); - BLI_array_free(edges2); -} /* This is what runs when pressing the F key * doing the best thing here isn't always easy create vs dissolve, its nice to support @@ -1361,11 +127,15 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE); BMO_elem_flag_enable(bm, e, ELE_NEW); + tote += 2; } } /* --- end special case support, continue as normal --- */ - /* call edgenet create */ + + /* -------------------------------------------------------------------- */ + /* EdgeNet Create */ + /* call edgenet prepare op so additional face creation cases wore */ BMO_op_initf(bm, &op2, op->flag, "edgenet_prepare edges=%fe", ELE_NEW); BMO_op_exec(bm, &op2); @@ -1387,8 +157,10 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) } BMO_op_finish(bm, &op2); - - /* now call dissolve face */ + + + /* -------------------------------------------------------------------- */ + /* Dissolve Face */ BMO_op_initf(bm, &op2, op->flag, "dissolve_faces faces=%ff", ELE_NEW); BMO_op_exec(bm, &op2); @@ -1402,6 +174,32 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMO_op_finish(bm, &op2); + + /* -------------------------------------------------------------------- */ + /* Fill EdgeLoop's - fills isolated loops, different from edgenet */ + + /* note: in most cases 'edgenet_fill' will handle this case since in common cases + * users fill in empty spaces, however its possible to have an edge selection around + * existing geometry that makes 'edgenet_fill' fail. */ + BMO_op_initf(bm, &op2, op->flag, "edgeloop_fill edges=%fe", ELE_NEW); + BMO_op_exec(bm, &op2); + + /* return if edge loop fill did something */ + if (BMO_slot_buffer_count(op2.slots_out, "faces.out")) { + BMO_slot_copy(&op2, slots_out, "faces.out", + op, slots_out, "faces.out"); + BMO_op_finish(bm, &op2); + return; + } + + BMO_op_finish(bm, &op2); + + + + /* -------------------------------------------------------------------- */ + /* Continue with ad-hoc fill methods since operators fail, + * edge, vcloud... may add more */ + /* now, count how many verts we have */ amount = 0; BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -1419,6 +217,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* create edge */ e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE); BMO_elem_flag_enable(bm, e, ELE_OUT); + tote += 1; BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT); } else if (0) { /* nice feature but perhaps it should be a different tool? */ @@ -1469,8 +268,9 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* done creating edges */ } else if (amount > 2) { - /* TODO, all these verts may be connected by edges. - * we should check on this before assuming they are a random set of verts */ + /* TODO, some of these vertes may be connected by edges, + * this connectivity could be used rather then treating + * them as a bunch of isolated verts. */ BMVert **vert_arr = MEM_mallocN(sizeof(BMVert **) * totv, __func__); int i = 0; @@ -1493,4 +293,6 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) MEM_freeN(vert_arr); } + + (void)tote; } diff --git a/source/blender/bmesh/operators/bmo_edgeloop_fill.c b/source/blender/bmesh/operators/bmo_edgeloop_fill.c new file mode 100644 index 00000000000..3818f449a15 --- /dev/null +++ b/source/blender/bmesh/operators/bmo_edgeloop_fill.c @@ -0,0 +1,157 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_edgeloop_fill.c + * \ingroup bmesh + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +#define VERT_USED 1 +#define EDGE_MARK 2 +#define ELE_OUT 4 + +void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) +{ + /* first collect an array of unique from the edges */ + const int tote = BMO_slot_buffer_count(op->slots_in, "edges"); + const int totv = tote; /* these should be the same */ + BMVert **verts = MEM_mallocN(sizeof(*verts) * totv, __func__); + + BMVert *v; + BMEdge *e; + int i; + bool ok = true; + + BMOIter oiter; + + const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + + /* 'VERT_USED' will be disabled, so enable and fill the array */ + BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { + BMIter viter; + BMO_elem_flag_enable(bm, e, EDGE_MARK); + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + if (BMO_elem_flag_test(bm, v, VERT_USED) == false) { + BMO_elem_flag_enable(bm, v, VERT_USED); + verts[i++] = v; + if (i > tote) { + break; + } + } + } + if (i > tote) { + break; + } + } + + /* we have a different number of verts to edges */ + if (i != tote) { + MEM_freeN(verts); + return; + } + + /* loop over connected flagged edges and fill in faces, this is made slightly more + * complicated because there may be multiple disconnected loops to fill. */ + + /* sanity check - that each vertex has 2 edge users */ + for (i = 0; i < totv; i++) { + v = verts[i]; + /* count how many flagged edges this vertex uses */ + if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, EDGE_MARK, true) != 2) { + ok = false; + break; + } + } + + if (ok) { + /* note: in the case of multiple loops, this over-allocs (which is fine) */ + BMVert **f_verts = MEM_mallocN(sizeof(*verts) * totv, __func__); + BMIter eiter; + + /* build array of connected verts and edges */ + BMEdge *e_prev = NULL; + BMEdge *e_next = NULL; + int totv_used = 0; + + while (totv_used < totv) { + for (i = 0; i < totv; i++) { + v = verts[i]; + if (BMO_elem_flag_test(bm, v, VERT_USED)) { + break; + } + } + + /* this should never fail, as long as (totv_used < totv) + * we should have marked verts available */ + BLI_assert(BMO_elem_flag_test(bm, v, VERT_USED)); + + /* watch it, 'i' is used for final face length */ + i = 0; + do { + /* we know that there are 2 edges per vertex so no need to check */ + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (e != e_prev) { + e_next = e; + break; + } + } + } + + /* fill in the array */ + f_verts[i] = v; + BMO_elem_flag_disable(bm, v, VERT_USED); + totv_used++; + + /* step over the edges */ + v = BM_edge_other_vert(e_next, v); + e_prev = e_next; + i++; + } while ((v != f_verts[0])); + + if (BM_face_exists(f_verts, i, NULL) == false) { + BMFace *f; + + /* don't use calc_edges option because we already have the edges */ + f = BM_face_create_ngon_verts(bm, f_verts, i, 0, true, false); + BMO_elem_flag_enable(bm, f, ELE_OUT); + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } + } + } + MEM_freeN(f_verts); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT); + } + + MEM_freeN(verts); +} diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c new file mode 100644 index 00000000000..cf91dfd0f15 --- /dev/null +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -0,0 +1,1270 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Joseph Eagar. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_edgenet.c + * \ingroup bmesh + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_array.h" +#include "BLI_smallhash.h" +#include "BLI_rand.h" +#include "BLI_heap.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +#define EDGE_MARK 1 +#define EDGE_VIS 2 + +#define FACE_NEW 1 + +#define ELE_NEW 1 +#define ELE_OUT 2 +#define ELE_ORIG 4 + +#define FACE_IGNORE 16 + +typedef struct EPathNode { + struct EPathNode *next, *prev; + BMVert *v; + BMEdge *e; + BMEdge *cure; +} EPathNode; + +typedef struct EPath { + ListBase nodes; + float weight; + int group; +} EPath; + +typedef struct PathBase { + BLI_mempool *nodepool, *pathpool; +} PathBase; + +typedef struct EdgeData { + int tag; + int ftag; + BMDiskLink v1_disk_link, v2_disk_link; +} EdgeData; + +typedef struct VertData { + BMEdge *e; + float no[3], offco[3], sco[3]; /* offco is vertex coordinate slightly offset randomly */ + int tag; +} VertData; + +static int count_edge_faces(BMesh *bm, BMEdge *e); + +/**** rotation system code * */ + +BLI_INLINE BMDiskLink *rs_edge_link_get(BMEdge *e, BMVert *v, EdgeData *e_data) +{ + return v == ((BMEdge *)e)->v1 ? &(((EdgeData *)e_data)->v1_disk_link) : + &(((EdgeData *)e_data)->v2_disk_link); +} + +static bool rotsys_append_edge(BMEdge *e, BMVert *v, + EdgeData *edata, VertData *vdata) +{ + EdgeData *ed = &edata[BM_elem_index_get(e)]; + VertData *vd = &vdata[BM_elem_index_get(v)]; + + if (!vd->e) { + Link *e1 = (Link *)rs_edge_link_get(e, v, ed); + + vd->e = e; + e1->next = e1->prev = (Link *)e; + } + else { + BMDiskLink *dl1, *dl2, *dl3; + EdgeData *ved = &edata[BM_elem_index_get(vd->e)]; + + dl1 = rs_edge_link_get(e, v, ed); + dl2 = rs_edge_link_get(vd->e, v, ved); + dl3 = dl2->prev ? rs_edge_link_get(dl2->prev, v, &edata[BM_elem_index_get(dl2->prev)]) : NULL; + + dl1->next = vd->e; + dl1->prev = dl2->prev; + + dl2->prev = e; + if (dl3) { + dl3->next = e; + } + } + + return true; +} + +static void UNUSED_FUNCTION(rotsys_remove_edge)(BMEdge *e, BMVert *v, + EdgeData *edata, VertData *vdata) +{ + EdgeData *ed = edata + BM_elem_index_get(e); + VertData *vd = vdata + BM_elem_index_get(v); + BMDiskLink *e1, *e2; + + e1 = rs_edge_link_get(e, v, ed); + if (e1->prev) { + e2 = rs_edge_link_get(e1->prev, v, ed); + e2->next = e1->next; + } + + if (e1->next) { + e2 = rs_edge_link_get(e1->next, v, ed); + e2->prev = e1->prev; + } + + if (vd->e == e) + vd->e = (e != e1->next) ? e1->next : NULL; + + e1->next = e1->prev = NULL; +} + +static BMEdge *rotsys_nextedge(BMEdge *e, BMVert *v, + EdgeData *edata, VertData *UNUSED(vdata)) +{ + if (v == e->v1) + return edata[BM_elem_index_get(e)].v1_disk_link.next; + if (v == e->v2) + return edata[BM_elem_index_get(e)].v2_disk_link.next; + return NULL; +} + +static BMEdge *rotsys_prevedge(BMEdge *e, BMVert *v, + EdgeData *edata, VertData *UNUSED(vdata)) +{ + if (v == e->v1) + return edata[BM_elem_index_get(e)].v1_disk_link.prev; + if (v == e->v2) + return edata[BM_elem_index_get(e)].v2_disk_link.prev; + return NULL; +} + +static void rotsys_reverse(BMEdge *UNUSED(e), BMVert *v, EdgeData *edata, VertData *vdata) +{ + BMEdge **edges = NULL; + BMEdge *e_first; + BMEdge *e; + BLI_array_staticdeclare(edges, BM_DEFAULT_NGON_STACK_SIZE); + int i, totedge; + + e = e_first = vdata[BM_elem_index_get(v)].e; + do { + BLI_array_append(edges, e); + e = rotsys_nextedge(e, v, edata, vdata); + } while (e != e_first); + + totedge = BLI_array_count(edges); + for (i = 0; i < totedge / 2; i++) { + SWAP(BMEdge *, edges[i], edges[totedge - 1 - i]); + } + + vdata[BM_elem_index_get(v)].e = NULL; + for (i = 0; i < totedge; i++) { + rotsys_append_edge(edges[i], v, edata, vdata); + } + + BLI_array_free(edges); +} + +static int UNUSED_FUNCTION(rotsys_count)(BMVert *v, EdgeData *edata, VertData *vdata) +{ + BMEdge *e = vdata[BM_elem_index_get(v)].e; + int i = 0; + + if (!e) + return 0; + + do { + if (!e) + return 0; + e = rotsys_nextedge(e, v, edata, vdata); + + if (i >= (1 << 20)) { + printf("bmesh error: infinite loop in disk cycle!\n"); + return 0; + } + + i += 1; + } while (e != vdata[BM_elem_index_get(v)].e); + + return i; +} + +static int UNUSED_FUNCTION(rotsys_fill_faces)(BMesh *bm, EdgeData *edata, VertData *vdata) +{ + BMIter iter; + BMEdge *e, **edges = NULL; + BLI_array_declare(edges); + BMVert *v, **verts = NULL; + BMFace *f; + BLI_array_declare(verts); + SmallHash visithash, *hash = &visithash; + int i; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BMEdge *e2, *starte; + BMVert *startv; + int rad, ok; + + rad = count_edge_faces(bm, e); + + if (rad < 2) { + starte = e; + } + else { + continue; + } + + /* do two passes, going forward then backward */ + for (i = 0; i < 2; i++) { + BLI_smallhash_init(hash); + + BLI_array_empty(verts); + BLI_array_empty(edges); + + startv = v = starte->v1; + e2 = starte; + ok = 1; + if (!v || !e2) + continue; + + do { + if (BLI_smallhash_haskey(hash, (intptr_t)e2) || + BLI_smallhash_haskey(hash, (intptr_t)v)) + { + ok = 0; + break; + } + + BLI_array_append(verts, v); + BLI_array_append(edges, e2); + + BLI_smallhash_insert(hash, (intptr_t)e2, NULL); + + v = BM_edge_other_vert(e2, v); + e2 = i ? rotsys_prevedge(e2, v, edata, vdata) : rotsys_nextedge(e2, v, edata, vdata); + } while (e2 != starte && v != startv); + + BLI_smallhash_release(hash); + + if (!ok || BLI_array_count(edges) < 3) + continue; + + f = BM_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), BM_CREATE_NO_DOUBLE); + if (UNLIKELY(f == NULL)) { + continue; + } + } + } + + return 0; +} + +static void rotsys_make_consistent(BMesh *bm, EdgeData *edata, VertData *vdata) +{ + BMIter iter; + BMEdge *e; + BMVert *v, **stack = NULL; + BLI_array_declare(stack); + int i; + + for (i = 0; i < bm->totvert; i++) { + vdata[i].tag = 0; + } + + while (1) { + VertData *vd; + BMVert *startv = NULL; + float dis; + + v = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i = 0; i < bm->totvert; i++, BM_iter_step(&iter)) { + vd = vdata + BM_elem_index_get(v); + + if (vd->tag) + continue; + + if (!startv || dot_v3v3(vd->offco, vd->offco) > dis) { + dis = dot_v3v3(vd->offco, vd->offco); + startv = v; + } + } + + if (!startv) + break; + + vd = vdata + BM_elem_index_get(startv); + + BLI_array_empty(stack); + BLI_array_append(stack, startv); + + vd->tag = 1; + + while (BLI_array_count(stack)) { + v = BLI_array_pop(stack); + vd = vdata + BM_elem_index_get(v); + + if (!vd->e) + continue; + + e = vd->e; + do { + BMVert *v2 = BM_edge_other_vert(e, v); + VertData *vd2 = vdata + BM_elem_index_get(v2); + + if (dot_v3v3(vd->no, vd2->no) < 0.0f + FLT_EPSILON * 2) { + rotsys_reverse(e, v2, edata, vdata); + mul_v3_fl(vd2->no, -1.0f); + } + + if (!vd2->tag) { + BLI_array_append(stack, v2); + vd2->tag = 1; + } + + e = rotsys_nextedge(e, v, edata, vdata); + } while (e != vd->e); + } + } + + BLI_array_free(stack); +} + +static void init_rotsys(BMesh *bm, EdgeData *edata, VertData *vdata) +{ + BMIter iter; + BMEdge *e; + BMEdge **edges = NULL; + BLI_array_staticdeclare(edges, BM_DEFAULT_NGON_STACK_SIZE); + BMVert *v; + /* BMVert **verts = NULL; */ + /* BLI_array_staticdeclare(verts, BM_DEFAULT_NGON_STACK_SIZE); */ /* UNUSE */ + int i; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMIter eiter; + float no[3], cent[3]; + int j, k = 0, totedge = 0; + + if (BM_elem_index_get(v) == -1) + continue; + + BLI_array_empty(edges); + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + BLI_array_append(edges, e); + totedge++; + } + } + + copy_v3_v3(cent, v->co); + + zero_v3(no); + for (i = 0; i < totedge; i++) { + BMEdge *e1, *e2; + float cno[3], vec1[3], vec2[3]; + + e1 = edges[i]; + e2 = edges[(i + 1) % totedge]; + + sub_v3_v3v3(vec1, (BM_edge_other_vert(e1, v))->co, v->co); + sub_v3_v3v3(vec2, (BM_edge_other_vert(e2, v))->co, v->co); + + cross_v3_v3v3(cno, vec1, vec2); + normalize_v3(cno); + + if (i && dot_v3v3(cno, no) < 0.0f + FLT_EPSILON * 10) + mul_v3_fl(cno, -1.0f); + + add_v3_v3(no, cno); + normalize_v3(no); + } + + /* generate plane-flattened coordinates */ + for (i = 0; i < totedge; i++) { + BMEdge *e1; + BMVert *v2; + float cvec[3], vec1[3]; + + e1 = edges[i]; + v2 = BM_edge_other_vert(e1, v); + + sub_v3_v3v3(vec1, v2->co, v->co); + + cross_v3_v3v3(cvec, vec1, no); + cross_v3_v3v3(vec1, cvec, no); + normalize_v3(vec1); + + mul_v3_fl(vec1, len_v3v3(v2->co, v->co)); + add_v3_v3(vec1, v->co); + + copy_v3_v3(vdata[BM_elem_index_get(v2)].sco, vec1); + } + + BLI_srandom(0); + + /* first, ensure no 0 or 180 angles between adjacent + * (and that adjacent's adjacent) edges */ + for (i = 0, k = 0; i < totedge; i++) { + BMEdge *e1, *e2, *e3 = NULL; + BMVert *v1, *v2, *v3; + VertData *vd1, *vd2, *vd3; + float vec1[3], vec2[3], vec3[3], size; + int s1, s2, s3; + + if (totedge < 3) + continue; + + e1 = edges[(i + totedge - 1) % totedge]; + e2 = edges[i]; + e3 = edges[(i + 1) % totedge]; + + v1 = BM_edge_other_vert(e1, v); + v2 = BM_edge_other_vert(e2, v); + v3 = BM_edge_other_vert(e3, v); + + vd1 = vdata + BM_elem_index_get(v1); + vd2 = vdata + BM_elem_index_get(v2); + vd3 = vdata + BM_elem_index_get(v3); + + sub_v3_v3v3(vec1, vd1->sco, cent); + sub_v3_v3v3(vec2, vd2->sco, cent); + sub_v3_v3v3(vec3, vd3->sco, cent); + + size = (len_v3(vec1) + len_v3(vec3)) * 0.01f; + normalize_v3(vec1); normalize_v3(vec2); normalize_v3(vec3); + +#ifdef STRAIGHT +#undef STRAIGHT +#endif +#define STRAIGHT(vec11, vec22) (fabsf(dot_v3v3((vec11), (vec22))) > 1.0f - ((float)FLT_EPSILON * 1000.0f)) + + s1 = STRAIGHT(vec1, vec2); s2 = STRAIGHT(vec2, vec3); s3 = STRAIGHT(vec1, vec3); + + if (s1 || s2 || s3) { + copy_v3_v3(cent, v->co); + + for (j = 0; j < 3; j++) { + float fac = (BLI_frand() - 0.5f) * size; + cent[j] += fac; + } + + if (k < 2000) { + i = 0; + k++; + continue; + } + else { + k++; + continue; + } + + } + } + + copy_v3_v3(vdata[BM_elem_index_get(v)].offco, cent); + //copy_v3_v3(v->co, cent); + + /* now, sort edges so the triangle fan of all edges + * has a consistent normal. this is the same as + * sorting by polar coordinates along a group normal */ + for (j = 0; j < totedge; j++) { + for (i = 0; i < totedge; i++) { + BMEdge *e1, *e2, *e3 = NULL; + BMVert *v1, *v2, *v3; + VertData *vd1, *vd2, *vd3; + float vec1[3], vec2[3], vec3[3], n1[3], n2[3], n3[3]; + + e1 = edges[(i + totedge - 1) % totedge]; + e2 = edges[i]; + e3 = edges[(i + 1) % totedge]; + + v1 = BM_edge_other_vert(e1, v); + v2 = BM_edge_other_vert(e2, v); + v3 = BM_edge_other_vert(e3, v); + + vd1 = vdata + BM_elem_index_get(v1); + vd2 = vdata + BM_elem_index_get(v2); + vd3 = vdata + BM_elem_index_get(v3); + + sub_v3_v3v3(vec1, vd1->sco, cent); + sub_v3_v3v3(vec2, vd2->sco, cent); + sub_v3_v3v3(vec3, vd3->sco, cent); + + cross_v3_v3v3(n1, vec1, vec2); + cross_v3_v3v3(n2, vec2, vec3); + cross_v3_v3v3(n3, vec1, vec3); + + /* this case happens often enough and probably not worth bothering users with, + * maybe enable for debugging code but not for everyday use - campbell */ +#if 0 + /* Other way to determine if two vectors approach are (nearly) parallel: the + * cross product of the two vectors will approach zero */ + { + int s1, s2, s3; + s1 = (dot_v3v3(n1, n1) < (0.0f + FLT_EPSILON * 10)); + s2 = (dot_v3v3(n2, n2) < (0.0f + FLT_EPSILON * 10)); + s3 = (totedge < 3) ? 0 : (dot_v3v3(n3, n3) < (0.0f + FLT_EPSILON * 10)); + + if (s1 || s2 || s3) { + fprintf(stderr, "%s: s1: %d, s2: %d, s3: %dx (bmesh internal error)\n", __func__, s1, s2, s3); + } + } +#endif + + normalize_v3(n1); normalize_v3(n2); normalize_v3(n3); + + + if (dot_v3v3(n1, n2) < 0.0f) { + if (dot_v3v3(n1, n3) >= 0.0f + FLT_EPSILON * 10) { + SWAP(BMEdge *, edges[i], edges[(i + 1) % totedge]); + } + else { + SWAP(BMEdge *, edges[(i + totedge - 1) % totedge], edges[(i + 1) % totedge]); + SWAP(BMEdge *, edges[i], edges[(i + 1) % totedge]); + } + } + } + } + +#undef STRAIGHT + + zero_v3(no); + + /* yay, edges are sorted */ + for (i = 0; i < totedge; i++) { + BMEdge *e1 = edges[i], *e2 = edges[(i + 1) % totedge]; + float eno[3]; + + normal_tri_v3(eno, BM_edge_other_vert(e1, v)->co, v->co, BM_edge_other_vert(e2, v)->co); + add_v3_v3(no, eno); + + rotsys_append_edge(edges[i], v, edata, vdata); + } + + normalize_v3(no); + copy_v3_v3(vdata[BM_elem_index_get(v)].no, no); + } + + /* now, make sure rotation system is topologically consistent + * (e.g. vert normals consistently point either inside or outside) */ + rotsys_make_consistent(bm, edata, vdata); + + //rotsys_fill_faces(bm, edata, vdata); + +#if 0 + /* create visualizing geometry */ + BMVert *lastv; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMVert *v2; + BMFace *f; + int totedge = BM_vert_edge_count(v); + + if (BM_elem_index_get(v) == -1) + continue; + + //cv = BM_vert_create(bm, cent, v); + //BM_elem_index_set(cv, -1); /* set_dirty! */ + i = 0; + e = vdata[BM_elem_index_get(v)].e; + lastv = NULL; + do { + BMEdge *e2; + BMVert *v2; + float f = ((float)i / (float)totedge) * 0.35 + 0.05; + float co[3]; + + if (!e) + break; + + if (!BM_edge_other_vert(e, v)) + continue; + + sub_v3_v3v3(co, (BM_edge_other_vert(e, v))->co, vdata[BM_elem_index_get(v)].offco); + mul_v3_fl(co, f); + add_v3_v3(co, vdata[BM_elem_index_get(v)].offco); + + v2 = BM_vert_create(bm, co, NULL); + BM_elem_index_set(v2, -1); /* set_dirty! */ + //BM_edge_create(bm, cv, v2, NULL, 0); + + BM_vert_select_set(bm, v2, true); + if (lastv) { + e2 = BM_edge_create(bm, lastv, v2, NULL, 0); + BM_edge_select_set(bm, e2, true); + } + + lastv = v2; + + e = rotsys_nextedge(e, v, edata, vdata); + i++; + } while (e != vdata[BM_elem_index_get(v)].e); + } +#endif + + BLI_array_free(edges); +} + +static PathBase *edge_pathbase_new(void) +{ + PathBase *pb = MEM_callocN(sizeof(PathBase), "PathBase"); + + pb->nodepool = BLI_mempool_create(sizeof(EPathNode), 1, 512, BLI_MEMPOOL_SYSMALLOC); + pb->pathpool = BLI_mempool_create(sizeof(EPath), 1, 512, BLI_MEMPOOL_SYSMALLOC); + + return pb; +} + +static void edge_pathbase_free(PathBase *pathbase) +{ + BLI_mempool_destroy(pathbase->nodepool); + BLI_mempool_destroy(pathbase->pathpool); + MEM_freeN(pathbase); +} + +static EPath *edge_copy_add_path(PathBase *pb, EPath *path, BMVert *appendv, BMEdge *e) +{ + EPath *path2; + EPathNode *node, *node2; + + path2 = BLI_mempool_alloc(pb->pathpool); + path2->nodes.first = path2->nodes.last = NULL; + path2->weight = 0.0f; + path2->group = path->group; + + for (node = path->nodes.first; node; node = node->next) { + node2 = BLI_mempool_alloc(pb->nodepool); + *node2 = *node; + BLI_addtail(&path2->nodes, node2); + } + + node2 = BLI_mempool_alloc(pb->nodepool); + node2->v = appendv; + node2->e = e; + node2->cure = NULL; + + BLI_addtail(&path2->nodes, node2); + + return path2; +} + +static EPath *edge_path_new(PathBase *pb, BMVert *start, BMEdge *starte) +{ + EPath *path; + EPathNode *node; + + path = BLI_mempool_alloc(pb->pathpool); + node = BLI_mempool_alloc(pb->nodepool); + + path->nodes.first = path->nodes.last = NULL; + + node->v = start; + node->e = starte; + node->cure = NULL; + + BLI_addtail(&path->nodes, node); + path->weight = 0.0f; + + return path; +} + +static float edge_weight_path(EPath *path, EdgeData *edata, VertData *UNUSED(vdata)) +{ + EPathNode *node, *first = path->nodes.first; + float w = 0.0; + + for (node = path->nodes.first; node; node = node->next) { + if (node->e && node != path->nodes.first) { + w += edata[BM_elem_index_get(node->e)].ftag; + if (node->prev) { + /* BMESH_TOD */ + (void)first; + //w += len_v3v3(node->v->co, first->e->v1->co) * 0.0001f; + //w += len_v3v3(node->v->co, first->e->v2->co) * 0.0001f; + } + } + + w += 1.0f; + } + + return w; +} + + +static void edge_free_path(PathBase *pathbase, EPath *path) +{ + EPathNode *node, *next; + + for (node = path->nodes.first; node; node = next) { + next = node->next; + BLI_mempool_free(pathbase->nodepool, node); + } + + BLI_mempool_free(pathbase->pathpool, path); +} + +static EPath *edge_find_shortest_path(BMesh *bm, BMOperator *op, BMEdge *edge, EdgeData *edata, + VertData *vdata, PathBase *pathbase, int group) +{ + BMEdge *e; + GHash *gh = BLI_ghash_ptr_new("createops find shortest path"); + BMVert *v1, *v2; + BMVert **verts = NULL; + BLI_array_staticdeclare(verts, 1024); + Heap *heap = BLI_heap_new(); + EPath *path = NULL, *path2; + BMVert *startv; + BMVert *endv; + EPathNode *node; + int i; + const bool use_restrict = BMO_slot_bool_get(op->slots_in, "use_restrict"); + BMOpSlot *slot_restrict = BMO_slot_get(op->slots_in, "restrict"); + + + startv = edata[BM_elem_index_get(edge)].ftag ? edge->v2 : edge->v1; + endv = edata[BM_elem_index_get(edge)].ftag ? edge->v1 : edge->v2; + + path = edge_path_new(pathbase, startv, edge); + BLI_ghash_insert(gh, startv, NULL); + BLI_heap_insert(heap, path->weight, path); + path->group = group; + + while (BLI_heap_size(heap)) { + VertData *vd; + EPathNode *last; + BMFace *f = NULL; + + path = BLI_heap_popmin(heap); + last = path->nodes.last; + v1 = last->v; + + if (v1 == endv) { + /* make sure this path loop doesn't already exists */ + i = 0; + BLI_array_empty(verts); + for (i = 0, node = path->nodes.first; node; node = node->next, i++) { + BLI_array_grow_one(verts); + verts[i] = node->v; + } + + if (BM_face_exists(verts, i, &f)) { + if (!BMO_elem_flag_test(bm, f, FACE_IGNORE)) { + BLI_ghash_remove(gh, endv, NULL, NULL); + continue; + } + } + break; + } + + vd = vdata + BM_elem_index_get(v1); + if (!vd->e) + continue; + + v2 = NULL; + while (1) { + if (!last->cure) { + last->cure = e = vdata[BM_elem_index_get(last->v)].e; + } + else { + last->cure = e = rotsys_nextedge(last->cure, last->v, edata, vdata); + if (last->cure == vdata[BM_elem_index_get(last->v)].e) { + v2 = NULL; + break; + } + } + + if (e == edge || !BMO_elem_flag_test(bm, e, EDGE_MARK)) { + continue; + } + + v2 = BM_edge_other_vert(e, last->v); + + if (BLI_ghash_haskey(gh, v2)) { + v2 = NULL; + continue; + } + + if (use_restrict) { + int *group_flag = (int *)BMO_slot_map_data_get(slot_restrict, e); + if (group_flag) { + if (!(*group_flag & path->group)) { + v2 = NULL; + continue; + } + } + } + + break; + } + + if (!v2) { + if (path) { + edge_free_path(pathbase, path); + path = NULL; + } + continue; + } + + /* add path back into heap */ + BLI_heap_insert(heap, path->weight, path); + + /* put v2 in gh ma */ + BLI_ghash_insert(gh, v2, NULL); + + path2 = edge_copy_add_path(pathbase, path, v2, e); + path2->weight = edge_weight_path(path2, edata, vdata); + + BLI_heap_insert(heap, path2->weight, path2); + } + + if (path && ((EPathNode *)path->nodes.last)->v != endv) { + edge_free_path(pathbase, path); + path = NULL; + } + + BLI_array_free(verts); + BLI_heap_free(heap, NULL); + BLI_ghash_free(gh, NULL, NULL); + + return path; +} + +static int count_edge_faces(BMesh *bm, BMEdge *e) +{ + int i = 0; + BMLoop *l = e->l; + + if (!l) { + return 0; + } + + do { + if (!BMO_elem_flag_test(bm, l->f, FACE_IGNORE)) { + i++; + } + + l = l->radial_next; + } while (l != e->l); + + return i; +} + +BLI_INLINE void vote_on_winding(BMEdge *edge, EPathNode *node, unsigned int winding[2]) +{ + BMVert *test_v1, *test_v2; + /* we want to use the reverse winding to the existing order */ + BM_edge_ordered_verts(edge, &test_v2, &test_v1); + + /* edges vote on which winding wins out */ + winding[(test_v1 == node->v)]++; +} + +void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op) +{ + BMIter iter; + BMOIter siter; + BMFace *f; + BMEdge *e; + BMVert **verts = NULL; + BLI_array_declare(verts); + EPath *path; + EPathNode *node; + EdgeData *edata; + VertData *vdata; + BMEdge **edges = NULL; + PathBase *pathbase; + BLI_array_declare(edges); + const bool use_restrict = BMO_slot_bool_get(op->slots_in, "use_restrict"); + const bool use_fill_check = BMO_slot_bool_get(op->slots_in, "use_fill_check"); + const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + int i, j; + unsigned int winding[2]; /* accumulte winding directions for each edge which has a face */ + BMOpSlot *slot_restrict = BMO_slot_get(op->slots_in, "restrict"); + BMOpSlot *slot_face_groupmap_out = BMO_slot_get(op->slots_out, "face_groupmap.out"); + + if (!bm->totvert || !bm->totedge) + return; + + pathbase = edge_pathbase_new(); + + edata = MEM_callocN(sizeof(EdgeData) * bm->totedge, "EdgeData"); + vdata = MEM_callocN(sizeof(VertData) * bm->totvert, "VertData"); + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "exclude_faces", BM_FACE, FACE_IGNORE); + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BMO_elem_flag_enable(bm, f, ELE_ORIG); + } + + BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { + BM_elem_index_set(e, i); /* set_inline */ + + if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) { + edata[i].tag = 2; + } + } + bm->elem_index_dirty &= ~BM_EDGE; + + init_rotsys(bm, edata, vdata); + + while (1) { + BMEdge *edge = NULL; + int group = 0; + + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + /* if restrict is on, only start on faces in the restrict map */ + if (use_restrict && !BMO_slot_map_contains(slot_restrict, e)) + continue; + + if (edata[BM_elem_index_get(e)].tag < 2) { + edge = e; + + if (use_restrict) { + int gi_iter = 0, gi_count = 0, gi = 0; + + group = BMO_slot_map_int_get(slot_restrict, e); + + for (gi_iter = 0; gi_iter < 30; gi_iter++) { + if (group & (1 << gi_iter)) { + gi_count++; + gi = gi_iter; + + if (gi_count - 1 == edata[BM_elem_index_get(e)].tag) { + break; + } + } + } + + group = (1 << gi); + } + + break; + } + } + + if (!edge) + break; + + edata[BM_elem_index_get(edge)].tag += 1; + + path = edge_find_shortest_path(bm, op, edge, edata, vdata, pathbase, group); + if (!path) + continue; + + winding[0] = winding[1] = 0; + + BLI_array_empty(edges); + BLI_array_empty(verts); + i = 0; + for (node = path->nodes.first; node; node = node->next) { + if (!node->next) + continue; + + e = BM_edge_exists(node->v, node->next->v); + + /* this should never happe */ + if (!e) + break; + + /* check on the winding */ + if (e->l) { + vote_on_winding(e, node, winding); + } + + edata[BM_elem_index_get(e)].ftag++; + BLI_array_grow_one(edges); + edges[i++] = e; + + BLI_array_append(verts, node->v); + } + + if (edge->l) { + vote_on_winding(edge, path->nodes.last, winding); + } + + BLI_array_grow_one(edges); + edges[i++] = edge; + edata[BM_elem_index_get(edge)].ftag++; + + for (j = 0; j < i; j++) { + if (count_edge_faces(bm, edges[j]) >= 2) { + edge_free_path(pathbase, path); + break; + } + } + + if (j != i) { + continue; + } + + if (i) { + BMVert *v1, *v2; + + /* to define the winding order must select first edge, + * otherwise we could leave this as-is */ + edge = edges[0]; + + /* if these are even it doesn't really matter what to do, + * with consistent geometry one will be zero, the choice is clear */ + if (winding[0] < winding[1]) { + v1 = verts[0]; + v2 = verts[1]; + } + else { + v1 = verts[1]; + v2 = verts[0]; + } + + if ((use_fill_check == false) || + /* fairly expensive check - see if there are already faces filling this area */ + (BM_face_exists_multi_edge(edges, i) == false)) + { + f = BM_face_create_ngon(bm, v1, v2, edges, i, BM_CREATE_NO_DOUBLE); + if (f && !BMO_elem_flag_test(bm, f, ELE_ORIG)) { + BMO_elem_flag_enable(bm, f, FACE_NEW); + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } + } + + if (use_restrict) { + BMO_slot_map_int_insert(op, slot_face_groupmap_out, f, path->group); + } + } + } + + edge_free_path(pathbase, path); + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_NEW); + + BLI_array_free(edges); + BLI_array_free(verts); + edge_pathbase_free(pathbase); + MEM_freeN(edata); + MEM_freeN(vdata); +} + +static BMEdge *edge_next(BMesh *bm, BMEdge *e) +{ + BMIter iter; + BMEdge *e2; + int i; + + for (i = 0; i < 2; i++) { + BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) { + if ((BMO_elem_flag_test(bm, e2, EDGE_MARK)) && + (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) && + (e2 != e)) + { + return e2; + } + } + } + + return NULL; +} + +void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) +{ + BMOIter siter; + BMEdge *e; + BMEdge **edges1 = NULL, **edges2 = NULL, **edges; + BLI_array_declare(edges1); + BLI_array_declare(edges2); + BLI_array_declare(edges); + int ok = 1; + int i, count; + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); + + /* validate that each edge has at most one other tagged edge in the + * disk cycle around each of it's vertices */ + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + for (i = 0; i < 2; i++) { + count = BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, (i ? e->v2 : e->v1), EDGE_MARK, true); + if (count > 2) { + ok = 0; + break; + } + } + + if (!ok) { + break; + } + } + + /* we don't have valid edge layouts, retur */ + if (!ok) { + return; + } + + /* find connected loops within the input edge */ + count = 0; + while (1) { + BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) { + if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 || + BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1) + { + break; + } + } + } + + if (!e) { + break; + } + + if (!count) { + edges = edges1; + } + else if (count == 1) { + edges = edges2; + } + else { + break; + } + + i = 0; + while (e) { + BMO_elem_flag_enable(bm, e, EDGE_VIS); + BLI_array_grow_one(edges); + edges[i] = e; + + e = edge_next(bm, e); + i++; + } + + if (!count) { + edges1 = edges; + BLI_array_length_set(edges1, BLI_array_count(edges)); + } + else { + edges2 = edges; + BLI_array_length_set(edges2, BLI_array_count(edges)); + } + + BLI_array_empty(edges); + count++; + } + + if (edges1 && BLI_array_count(edges1) > 2 && + BM_edge_share_vert_check(edges1[0], edges1[BLI_array_count(edges1) - 1])) + { + if (edges2 && BLI_array_count(edges2) > 2 && + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) + { + BLI_array_free(edges1); + BLI_array_free(edges2); + return; + } + else { + edges1 = edges2; + edges2 = NULL; + } + } + + if (edges2 && BLI_array_count(edges2) > 2 && + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) + { + edges2 = NULL; + } + + /* two unconnected loops, connect the */ + if (edges1 && edges2) { + BMVert *v1, *v2, *v3, *v4; + float dvec1[3]; + float dvec2[3]; + + if (BLI_array_count(edges1) == 1) { + v1 = edges1[0]->v1; + v2 = edges1[0]->v2; + } + else { + v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; + i = BLI_array_count(edges1) - 1; + v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; + } + + if (BLI_array_count(edges2) == 1) { + v3 = edges2[0]->v1; + v4 = edges2[0]->v2; + } + else { + v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1; + i = BLI_array_count(edges2) - 1; + v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1; + } + + /* if there is ever bow-tie quads between two edges the problem is here! [#30367] */ +#if 0 + normal_tri_v3(dvec1, v1->co, v2->co, v4->co); + normal_tri_v3(dvec2, v1->co, v4->co, v3->co); +#else + { + /* save some CPU cycles and skip the sqrt and 1 subtraction */ + float a1[3], a2[3], a3[3]; + sub_v3_v3v3(a1, v1->co, v2->co); + sub_v3_v3v3(a2, v1->co, v4->co); + sub_v3_v3v3(a3, v1->co, v3->co); + cross_v3_v3v3(dvec1, a1, a2); + cross_v3_v3v3(dvec2, a2, a3); + } +#endif + if (dot_v3v3(dvec1, dvec2) < 0.0f) { + SWAP(BMVert *, v3, v4); + } + + e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE); + BMO_elem_flag_enable(bm, e, ELE_NEW); + e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE); + BMO_elem_flag_enable(bm, e, ELE_NEW); + } + else if (edges1) { + BMVert *v1, *v2; + + if (BLI_array_count(edges1) > 1) { + v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; + i = BLI_array_count(edges1) - 1; + v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; + e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); + BMO_elem_flag_enable(bm, e, ELE_NEW); + } + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW); + + BLI_array_free(edges1); + BLI_array_free(edges2); +} diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index e4c7a1edbcb..ad32c5fcccf 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -43,6 +43,8 @@ #include "BLI_rand.h" #include "BLI_utildefines.h" +#include "BLF_translation.h" + #include "DNA_anim_types.h" #include "DNA_curve_types.h" #include "DNA_object_types.h" @@ -229,7 +231,7 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) bGPdata *gpd = (*gpd_ptr); id_us_min(&gpd->id); - *gpd_ptr = gpencil_data_addnew("GPencil"); + *gpd_ptr = gpencil_data_addnew(DATA_("GPencil")); } /* notifiers */ @@ -312,10 +314,10 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } if (*gpd_ptr == NULL) - *gpd_ptr = gpencil_data_addnew("GPencil"); - + *gpd_ptr = gpencil_data_addnew(DATA_("GPencil")); + /* add new layer now */ - gpencil_layer_addnew(*gpd_ptr, "GP_Layer", 1); + gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1); /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index b858d715cfe..f628b2bb210 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -75,4 +75,8 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + blender_add_lib(bf_editor_render "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript index 25af8080d51..4c5da4dc78a 100644 --- a/source/blender/editors/render/SConscript +++ b/source/blender/editors/render/SConscript @@ -35,6 +35,8 @@ incs += ' ../../gpu' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' incs += ' ../../blenloader ../../bmesh ../../blenfont' +defs = [] + if env['OURPLATFORM'] == 'linux': cflags='-pthread' incs += ' ../../../extern/binreloc/include' @@ -57,4 +59,7 @@ if env['OURPLATFORM'] == 'darwin': if env['WITH_BF_OPENMP']: env.Append(CFLAGS=['-DPARALLEL=1']) -env.BlenderLib ( 'bf_editors_render', sources, Split(incs), [], libtype=['core'], priority=[45]) +if env['WITH_BF_INTERNATIONAL']: + defs.append('WITH_INTERNATIONAL') + +env.BlenderLib('bf_editors_render', sources, Split(incs), defs, libtype=['core'], priority=[45]) diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 87d83f820c9..5652d4c4b71 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -435,10 +435,12 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) PropertyRNA *prop; /* add or copy texture */ - if (tex) + if (tex) { tex = BKE_texture_copy(tex); - else + } + else { tex = add_texture(bmain, DATA_("Texture")); + } /* hook into UI */ uiIDContextProperty(C, &ptr, &prop); @@ -487,7 +489,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) wo = BKE_world_copy(wo); } else { - wo = add_world(bmain, "World"); + wo = add_world(bmain, DATA_("World")); if (BKE_scene_use_new_shading_nodes(scene)) { ED_node_shader_default(C, &wo->id); diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 9bc232c6a61..a45209de643 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -345,6 +345,7 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po const int diameter = 2 * BKE_brush_size_get(scene, brush); const float alpha = BKE_brush_alpha_get(scene, brush); const bool do_tiled = ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_3D); + const bool do_random = brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM; float rotation = -mtex->rot; if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { @@ -354,7 +355,8 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po if (diameter != cache->lastsize || alpha != cache->lastalpha || brush->jitter != cache->lastjitter || - rotation != cache->last_rotation) + rotation != cache->last_rotation || + do_random) { if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index d7e2d010f03..ca48524096a 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -188,13 +188,10 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, ups->brush_rotation = 0.0f; } - if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) { - ups->tex_mouse[0] = BLI_frand() * stroke->vc.ar->sizex; - ups->tex_mouse[1] = BLI_frand() * stroke->vc.ar->sizey;; - } - else { + if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) + BKE_brush_randomize_texture_coordinates(ups); + else copy_v2_v2(ups->tex_mouse, mouse); - } } if (brush->flag & BRUSH_ANCHORED) { diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 95d43fd334e..072ea504b9f 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -1073,6 +1073,7 @@ void buttons_context_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context"); strcpy(pt->idname, "BUTTONS_PT_context"); strcpy(pt->label, N_("Context")); /* XXX C panels are not available through RNA (bpy.types)! */ + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = buttons_panel_context; pt->flag = PNL_NO_HEADER; BLI_addtail(&art->paneltypes, pt); diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index 9409ce42d3a..8d863193b76 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -79,7 +79,8 @@ void ED_clip_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype clip panel gpencil"); strcpy(pt->idname, "CLIP_PT_gpencil"); - strcpy(pt->label, "Grease Pencil"); + strcpy(pt->label, N_("Grease Pencil")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw_header = gpencil_panel_standard_header; pt->draw = gpencil_panel_standard; pt->flag |= PNL_DEFAULT_CLOSED; diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 05e05b95967..b00cc564a99 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -1142,6 +1142,9 @@ static bool prefetch_check_early_out(const bContext *C) if ((user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) == 0) return true; } + else { + return true; + } } clip_len = BKE_movieclip_get_duration(clip); diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c index 10175d07300..42300f88a4f 100644 --- a/source/blender/editors/space_clip/clip_toolbar.c +++ b/source/blender/editors/space_clip/clip_toolbar.c @@ -257,7 +257,8 @@ void ED_clip_tool_props_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype clip panel last operator"); strcpy(pt->idname, "CLIP_PT_last_operator"); - strcpy(pt->label, "Operator"); + strcpy(pt->label, N_("Operator")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw_header = clip_panel_operator_redo_header; pt->draw = clip_panel_operator_redo; BLI_addtail(&art->paneltypes, pt); diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 9a7f528be78..35179511563 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -219,30 +219,35 @@ void file_panels_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype file system directories"); strcpy(pt->idname, "FILE_PT_system"); strcpy(pt->label, N_("System")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = file_panel_system; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype file system bookmarks"); strcpy(pt->idname, "FILE_PT_system_bookmarks"); strcpy(pt->label, N_("System Bookmarks")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = file_panel_system_bookmarks; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype file bookmarks"); strcpy(pt->idname, "FILE_PT_bookmarks"); strcpy(pt->label, N_("Bookmarks")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = file_panel_bookmarks; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype file recent directories"); strcpy(pt->idname, "FILE_PT_recent"); strcpy(pt->label, N_("Recent")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = file_panel_recent; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype file operator properties"); strcpy(pt->idname, "FILE_PT_operator"); strcpy(pt->label, N_("Operator")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->poll = file_panel_operator_poll; pt->draw_header = file_panel_operator_header; pt->draw = file_panel_operator; diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index f1501857b13..f7ec8e8682d 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -803,6 +803,7 @@ void graph_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view"); strcpy(pt->idname, "GRAPH_PT_view"); strcpy(pt->label, N_("View Properties")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = graph_panel_view; pt->flag |= PNL_DEFAULT_CLOSED; BLI_addtail(&art->paneltypes, pt); @@ -810,6 +811,7 @@ void graph_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties"); strcpy(pt->idname, "GRAPH_PT_properties"); strcpy(pt->label, N_("Active F-Curve")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = graph_panel_properties; pt->poll = graph_panel_poll; BLI_addtail(&art->paneltypes, pt); @@ -817,6 +819,7 @@ void graph_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties"); strcpy(pt->idname, "GRAPH_PT_key_properties"); strcpy(pt->label, N_("Active Keyframe")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = graph_panel_key_properties; pt->poll = graph_panel_poll; BLI_addtail(&art->paneltypes, pt); @@ -825,6 +828,7 @@ void graph_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers"); strcpy(pt->idname, "GRAPH_PT_drivers"); strcpy(pt->label, N_("Drivers")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = graph_panel_drivers; pt->poll = graph_panel_drivers_poll; BLI_addtail(&art->paneltypes, pt); @@ -832,6 +836,7 @@ void graph_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers"); strcpy(pt->idname, "GRAPH_PT_modifiers"); strcpy(pt->label, N_("Modifiers")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = graph_panel_modifiers; pt->poll = graph_panel_poll; BLI_addtail(&art->paneltypes, pt); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 70001b59528..5398f886396 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -880,7 +880,8 @@ void image_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype image panel gpencil"); strcpy(pt->idname, "IMAGE_PT_gpencil"); - strcpy(pt->label, "Grease Pencil"); + strcpy(pt->label, N_("Grease Pencil")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw_header = gpencil_panel_standard_header; pt->draw = gpencil_panel_standard; BLI_addtail(&art->paneltypes, pt); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 7e0767bfcfb..4a78c54e9c0 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1707,6 +1707,7 @@ void IMAGE_OT_reload(wmOperatorType *ot) } /********************** new image operator *********************/ +#define IMA_DEF_NAME N_("Untitled") static int image_new_exec(bContext *C, wmOperator *op) { @@ -1717,7 +1718,8 @@ static int image_new_exec(bContext *C, wmOperator *op) Main *bmain; PointerRNA ptr, idptr; PropertyRNA *prop; - char name[MAX_ID_NAME - 2]; + char _name[MAX_ID_NAME - 2]; + char *name = _name; float color[4]; int width, height, floatbuf, gen_type, alpha; @@ -1727,7 +1729,12 @@ static int image_new_exec(bContext *C, wmOperator *op) obedit = CTX_data_edit_object(C); bmain = CTX_data_main(C); - RNA_string_get(op->ptr, "name", name); + prop = RNA_struct_find_property(op->ptr, "name"); + RNA_property_string_get(op->ptr, prop, name); + if (!RNA_property_is_set(op->ptr, prop)) { + /* Default value, we can translate! */ + name = (char *)DATA_(name); + } width = RNA_int_get(op->ptr, "width"); height = RNA_int_get(op->ptr, "height"); floatbuf = RNA_boolean_get(op->ptr, "float"); @@ -1775,8 +1782,9 @@ static int image_new_exec(bContext *C, wmOperator *op) /* XXX Note: the WM_operator_props_dialog_popup() doesn't work for uiIDContextProperty(), image is not being that way */ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { + /* Better for user feedback. */ + RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME)); return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y); - } void IMAGE_OT_new(wmOperatorType *ot) @@ -1797,7 +1805,7 @@ void IMAGE_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - RNA_def_string(ot->srna, "name", "untitled", MAX_ID_NAME - 2, "Name", "Image datablock name"); + RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name"); RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384); RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384); prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f); @@ -1809,6 +1817,8 @@ void IMAGE_OT_new(wmOperatorType *ot) RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); } +#undef IMA_DEF_NAME + /********************* invert operators *********************/ static int image_invert_poll(bContext *C) diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index 1577ac338e7..a3eb7c06876 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -300,6 +300,7 @@ static void recent_files_menu_register(void) mt = MEM_callocN(sizeof(MenuType), "spacetype info menu recent files"); strcpy(mt->idname, "INFO_MT_file_open_recent"); strcpy(mt->label, N_("Open Recent...")); + strcpy(mt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); mt->draw = recent_files_menu_draw; WM_menutype_add(mt); } diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index b26d1662f6c..3a9336e7acc 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -502,7 +502,8 @@ void nla_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata"); strcpy(pt->idname, "NLA_PT_animdata"); - strcpy(pt->label, "Animation Data"); + strcpy(pt->label, N_("Animation Data")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_animdata; pt->poll = nla_animdata_panel_poll; pt->flag = PNL_DEFAULT_CLOSED; @@ -510,35 +511,40 @@ void nla_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track"); strcpy(pt->idname, "NLA_PT_track"); - strcpy(pt->label, "Active Track"); + strcpy(pt->label, N_("Active Track")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_track; pt->poll = nla_track_panel_poll; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_properties"); - strcpy(pt->label, "Active Strip"); + strcpy(pt->label, N_("Active Strip")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_properties; pt->poll = nla_strip_panel_poll; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_actionclip"); - strcpy(pt->label, "Action Clip"); + strcpy(pt->label, N_("Action Clip")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_actclip; pt->poll = nla_strip_actclip_panel_poll; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation"); strcpy(pt->idname, "NLA_PT_evaluation"); - strcpy(pt->label, "Evaluation"); + strcpy(pt->label, N_("Evaluation")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_evaluation; pt->poll = nla_strip_eval_panel_poll; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers"); strcpy(pt->idname, "NLA_PT_modifiers"); - strcpy(pt->label, "Modifiers"); + strcpy(pt->label, N_("Modifiers")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_modifiers; pt->poll = nla_strip_eval_panel_poll; BLI_addtail(&art->paneltypes, pt); diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index fb9e1221c38..0201071ada4 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -83,7 +83,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx /* generics */ node->locx = locx; - node->locy = locy + 60.0f; // arbitrary.. so its visible, (0,0) is top of node + node->locy = locy + 60.0f; /* arbitrary... so its visible, (0,0) is top of node */ nodeSetSelected(node, TRUE); /* node location is mapped */ @@ -436,7 +436,8 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) PointerRNA ptr, idptr; PropertyRNA *prop; const char *idname; - char treename[MAX_ID_NAME - 2] = "NodeTree"; + char _treename[MAX_ID_NAME - 2]; + char *treename = _treename; if (RNA_struct_property_is_set(op->ptr, "type")) { prop = RNA_struct_find_property(op->ptr, "type"); @@ -445,8 +446,12 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) else if (snode) idname = snode->tree_idname; - if (RNA_struct_property_is_set(op->ptr, "name")) + if (RNA_struct_property_is_set(op->ptr, "name")) { RNA_string_get(op->ptr, "name", treename); + } + else { + treename = (char *)DATA_("NodeTree"); + } if (!ntreeTypeFind(idname)) { BKE_reportf(op->reports, RPT_ERROR, "Node tree type %s undefined", idname); diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index efdb7c0d85d..d0a77e273f0 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -211,13 +211,13 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa) split = uiLayoutRow(row, TRUE); col = uiLayoutColumn(split, TRUE); - uiItemL(col, "Inputs:", ICON_NONE); + uiItemL(col, IFACE_("Inputs:"), ICON_NONE); uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "", &ptr, "inputs", &ptr, "active_input", 0, 0, 0); opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_IN); col = uiLayoutColumn(split, TRUE); - uiItemL(col, "Outputs:", ICON_NONE); + uiItemL(col, IFACE_("Outputs:"), ICON_NONE); uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "", &ptr, "outputs", &ptr, "active_output", 0, 0, 0); opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_OUT); @@ -248,14 +248,16 @@ void node_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype node panel active node"); strcpy(pt->idname, "NODE_PT_item"); - strcpy(pt->label, IFACE_("Active Node")); + strcpy(pt->label, N_("Active Node")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = active_node_panel; pt->poll = active_node_poll; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype node panel node sockets"); strcpy(pt->idname, "NODE_PT_sockets"); - strcpy(pt->label, "Sockets"); + strcpy(pt->label, N_("Sockets")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = node_sockets_panel; pt->poll = node_sockets_poll; pt->flag |= PNL_DEFAULT_CLOSED; @@ -263,14 +265,16 @@ void node_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype node panel tree interface"); strcpy(pt->idname, "NODE_PT_node_tree_interface"); - strcpy(pt->label, "Interface"); + strcpy(pt->label, N_("Interface")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = node_tree_interface_panel; pt->poll = node_tree_interface_poll; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil"); strcpy(pt->idname, "NODE_PT_gpencil"); - strcpy(pt->label, "Grease Pencil"); + strcpy(pt->label, N_("Grease Pencil")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw_header = gpencil_panel_standard_header; pt->draw = gpencil_panel_standard; pt->poll = active_nodetree_poll; diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c index 175bbce756e..8de2daf9e42 100644 --- a/source/blender/editors/space_node/node_header.c +++ b/source/blender/editors/space_node/node_header.c @@ -81,7 +81,8 @@ void node_menus_register(void) mt = MEM_callocN(sizeof(MenuType), "spacetype node menu add"); strcpy(mt->idname, "NODE_MT_add"); - strcpy(mt->label, "Add"); + strcpy(mt->label, N_("Add")); + strcpy(mt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); mt->draw = node_menu_add; WM_menutype_add(mt); } diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 48051014c58..7e4397a6cb0 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -121,10 +121,11 @@ void NODE_OT_select_linked_from(struct wmOperatorType *ot); void NODE_OT_select_border(struct wmOperatorType *ot); void NODE_OT_select_lasso(struct wmOperatorType *ot); void NODE_OT_select_same_type(struct wmOperatorType *ot); -void NODE_OT_select_same_type_next(struct wmOperatorType *ot); -void NODE_OT_select_same_type_prev(struct wmOperatorType *ot); +void NODE_OT_select_same_type_step(struct wmOperatorType *ot); /* node_view.c */ +int space_node_view_flag(struct bContext *C, SpaceNode *snode, ARegion *ar, const int node_flag); + void NODE_OT_view_all(struct wmOperatorType *ot); void NODE_OT_view_selected(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 1e4e02b6ae1..4d229c6fe18 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -58,9 +58,8 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_select_border); WM_operatortype_append(NODE_OT_select_lasso); WM_operatortype_append(NODE_OT_select_same_type); - WM_operatortype_append(NODE_OT_select_same_type_next); - WM_operatortype_append(NODE_OT_select_same_type_prev); - + WM_operatortype_append(NODE_OT_select_same_type_step); + WM_operatortype_append(NODE_OT_view_all); WM_operatortype_append(NODE_OT_view_selected); @@ -318,9 +317,12 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "NODE_OT_select_linked_to", LKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "NODE_OT_select_linked_from", LKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_select_same_type", GKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "NODE_OT_select_same_type_next", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "NODE_OT_select_same_type_prev", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); + kmi = WM_keymap_add_item(keymap, "NODE_OT_select_same_type_step", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "prev", FALSE); + kmi = WM_keymap_add_item(keymap, "NODE_OT_select_same_type_step", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "prev", TRUE); + node_group_operators(keymap, "ShaderNodeGroup"); node_group_operators(keymap, "CompositorNodeGroup"); node_group_operators(keymap, "TextureNodeGroup"); diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index faebeabdbba..cdb89a66867 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -762,57 +762,93 @@ void NODE_OT_select_same_type(wmOperatorType *ot) /* ****** Select The Next/Prev Node Of The Same Type ****** */ -static int node_select_same_type_next_exec(bContext *C, wmOperator *UNUSED(op)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - node_select_same_type_np(snode, 0); +/* ************************** */ - ED_node_sort(snode->edittree); - - WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); - return OPERATOR_FINISHED; -} - -void NODE_OT_select_same_type_next(wmOperatorType *ot) +static int node_select_same_type_step_exec(bContext *C, wmOperator *op) { - /* identifiers */ - ot->name = "Select Same Type Next"; - ot->description = "Select the next node of the same type"; - ot->idname = "NODE_OT_select_same_type_next"; + SpaceNode *snode = CTX_wm_space_node(C); + ARegion *ar = CTX_wm_region(C); + bNode **node_array; + bNode *active = nodeGetActive(snode->edittree); + int totnodes; + int revert = RNA_boolean_get(op->ptr, "prev"); + int same_type = 1; - /* api callbacks */ - ot->exec = node_select_same_type_next_exec; - ot->poll = ED_operator_node_active; + ntreeGetDependencyList(snode->edittree, &node_array, &totnodes); - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int node_select_same_type_prev_exec(bContext *C, wmOperator *UNUSED(op)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - node_select_same_type_np(snode, 1); + if (totnodes > 1) { + int a; + + for (a = 0; a < totnodes; a++) { + if (node_array[a] == active) + break; + } + + if (same_type) { + bNode *node = NULL; + + while (node == NULL) { + if (revert) a--; + else a++; + + if (a < 0 || a >= totnodes) + break; + + node = node_array[a]; + + if (node->type == active->type) + break; + else node = NULL; + } + if (node) + active = node; + } + else { + if (revert) { + if (a == 0) + active = node_array[totnodes - 1]; + else + active = node_array[a - 1]; + } + else { + if (a == totnodes - 1) + active = node_array[0]; + else + active = node_array[a + 1]; + } + } + + node_select_single(C, active); - ED_node_sort(snode->edittree); + /* is note outside view? */ + if (active->totr.xmax < ar->v2d.cur.xmin || active->totr.xmin > ar->v2d.cur.xmax || + active->totr.ymax < ar->v2d.cur.ymin || active->totr.ymin > ar->v2d.cur.ymax) + space_node_view_flag(C, snode, CTX_wm_region(C), NODE_SELECT); - WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); + } + + if (node_array) + MEM_freeN(node_array); + return OPERATOR_FINISHED; } -void NODE_OT_select_same_type_prev(wmOperatorType *ot) +void NODE_OT_select_same_type_step(wmOperatorType *ot) { /* identifiers */ - ot->name = "Select Same Type Prev"; - ot->description = "Select the prev node of the same type"; - ot->idname = "NODE_OT_select_same_type_prev"; + ot->name = "Activate Same Type Next/Prev"; + ot->description = "Activate and view same node type, step by step"; + ot->idname = "NODE_OT_select_same_type_step"; /* api callbacks */ - ot->exec = node_select_same_type_prev_exec; + ot->exec = node_select_same_type_step_exec; ot->poll = ED_operator_node_active; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "prev", 0, "Previous", ""); + } + diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 293913dff11..eed8a10a1db 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -66,7 +66,7 @@ /* **************** View All Operator ************** */ -static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, const int node_flag) +int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, const int node_flag) { bNode *node; rctf cur_new; diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c index 21128408a97..197cc64dea4 100644 --- a/source/blender/editors/space_sequencer/sequencer_buttons.c +++ b/source/blender/editors/space_sequencer/sequencer_buttons.c @@ -67,6 +67,7 @@ void sequencer_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype sequencer panel gpencil"); strcpy(pt->idname, "SEQUENCER_PT_gpencil"); strcpy(pt->label, N_("Grease Pencil")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw_header = gpencil_panel_standard_header; pt->draw = gpencil_panel_standard; pt->poll = sequencer_grease_pencil_panel_poll; diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 7ebe04f666b..1a4d461c3c1 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -1061,9 +1061,12 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer); - if (sseq->flag & SEQ_USE_ALPHA) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + /* only draw alpha for main buffer */ + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + if (sseq->flag & SEQ_USE_ALPHA) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } } glBegin(GL_QUADS); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index f0ed8d4107d..135fddfd348 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -866,11 +866,11 @@ static int cut_seq_list(Scene *scene, ListBase *slist, int cutframe, return (seq_first_new != NULL); } -static int insert_gap(Scene *scene, int gap, int cfra) +static bool insert_gap(Scene *scene, int gap, int cfra) { Sequence *seq; Editing *ed = BKE_sequencer_editing_get(scene, FALSE); - int done = FALSE; + bool done = false; /* all strips >= cfra are shifted */ @@ -881,7 +881,7 @@ static int insert_gap(Scene *scene, int gap, int cfra) if (seq->startdisp >= cfra) { seq->start += gap; BKE_sequence_calc(scene, seq); - done = TRUE; + done = true; } } SEQ_END @@ -988,30 +988,99 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene) } -static void UNUSED_FUNCTION(no_gaps) (Scene *scene) +static int sequencer_gap_remove_exec(bContext *C, wmOperator *op) { - Editing *ed = BKE_sequencer_editing_get(scene, FALSE); - int cfra, first = 0, done; - + Scene *scene = CTX_data_scene(C); + rctf rectf; + int cfra, efra, sfra; + bool first = false, done; + bool do_all = RNA_boolean_get(op->ptr, "all"); + + /* get first and last frame */ + boundbox_seq(scene, &rectf); + sfra = (int)rectf.xmin; + efra = (int)rectf.xmax; + + /* first check if the current frame has a gap already */ + for (cfra = CFRA; cfra >= sfra; cfra--) { + if (BKE_sequencer_evaluate_frame(scene, cfra)) { + first = true; + break; + } + } - if (ed == NULL) return; - - for (cfra = CFRA; cfra <= EFRA; cfra++) { - if (first == 0) { - if (BKE_sequencer_evaluate_frame(scene, cfra) ) first = 1; + for ( ; cfra < efra; cfra++) { + /* first == 0 means there's still no strip to remove a gap for */ + if (first == false) { + if (BKE_sequencer_evaluate_frame(scene, cfra) ) first = true; } - else { - done = TRUE; + else if (BKE_sequencer_evaluate_frame(scene, cfra) == 0) { + done = true; while (BKE_sequencer_evaluate_frame(scene, cfra) == 0) { done = insert_gap(scene, -1, cfra); - if (done == 0) break; + if (done == false) break; } - if (done == 0) break; + if (done == false || do_all == false) break; } } + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + + return OPERATOR_FINISHED; + +} + + +void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Gaps"; + ot->idname = "SEQUENCER_OT_gap_remove"; + ot->description = "Remove gap at current frame to first strip at the right, independent of selection or locked state of strips"; + + /* api callbacks */ +// ot->invoke = sequencer_snap_invoke; + ot->exec = sequencer_gap_remove_exec; + ot->poll = sequencer_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "all", 0, "All Gaps", "Do all gaps to right of current frame"); } +static int sequencer_gap_insert_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + int frames = RNA_int_get(op->ptr, "frames"); + + insert_gap(scene, frames, CFRA); + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + + return OPERATOR_FINISHED; + +} + +void SEQUENCER_OT_gap_insert(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Insert Gaps"; + ot->idname = "SEQUENCER_OT_gap_insert"; + ot->description = "Insert gap at current frame to first strips at the right, independent of selection or locked state of strips"; + + /* api callbacks */ + // ot->invoke = sequencer_snap_invoke; + ot->exec = sequencer_gap_insert_exec; + ot->poll = sequencer_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_int(ot->srna, "frames", 10, 0, INT_MAX, "Frames", "Frames to insert after current strip", 0, 1000); +} + + #if 0 static int seq_get_snaplimit(View2D *v2d) { @@ -2259,6 +2328,7 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) View2D *v2d = UI_view2d_fromcontext(C); ARegion *ar = CTX_wm_region(C); Editing *ed = BKE_sequencer_editing_get(scene, FALSE); + Sequence *last_seq = BKE_sequencer_active_get(scene); Sequence *seq; rctf cur_new = v2d->cur; @@ -2275,7 +2345,7 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if (seq->flag & SELECT) { + if ((seq->flag & SELECT) || (seq == last_seq)) { xmin = min_ii(xmin, seq->startdisp); xmax = max_ii(xmax, seq->enddisp); diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index cd79c43eac2..32a6c49da89 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -97,7 +97,11 @@ void SEQUENCER_OT_images_separate(struct wmOperatorType *ot); void SEQUENCER_OT_meta_toggle(struct wmOperatorType *ot); void SEQUENCER_OT_meta_make(struct wmOperatorType *ot); void SEQUENCER_OT_meta_separate(struct wmOperatorType *ot); + +void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot); +void SEQUENCER_OT_gap_insert(struct wmOperatorType *ot); void SEQUENCER_OT_snap(struct wmOperatorType *ot); + void SEQUENCER_OT_strip_jump(struct wmOperatorType *ot); void SEQUENCER_OT_swap(struct wmOperatorType *ot); void SEQUENCER_OT_swap_data(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index 70b288a59e6..a236a97a803 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -72,6 +72,9 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_meta_toggle); WM_operatortype_append(SEQUENCER_OT_meta_make); WM_operatortype_append(SEQUENCER_OT_meta_separate); + + WM_operatortype_append(SEQUENCER_OT_gap_remove); + WM_operatortype_append(SEQUENCER_OT_gap_insert); WM_operatortype_append(SEQUENCER_OT_snap); WM_operatortype_append(SEQUENCER_OT_strip_jump); WM_operatortype_append(SEQUENCER_OT_swap); @@ -213,6 +216,10 @@ void sequencer_keymap(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_swap", LEFTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "side", SEQ_SIDE_LEFT); RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_swap", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "side", SEQ_SIDE_RIGHT); + RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_gap_remove", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "all", FALSE); + RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_gap_remove", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "all", TRUE); + WM_keymap_add_item(keymap, "SEQUENCER_OT_gap_insert", EQUALKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "SEQUENCER_OT_swap_inputs", SKEY, KM_PRESS, KM_ALT, 0); diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index 6ed34a79510..c8b70c0ce4a 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -107,20 +107,20 @@ static void wform_put_border(unsigned char *tgt, int w, int h) for (x = 0; x < w; x++) { unsigned char *p = tgt + 4 * x; - p[1] = p[3] = 255.0; - p[4 * w + 1] = p[4 * w + 3] = 255.0; + p[1] = p[3] = 155; + p[4 * w + 1] = p[4 * w + 3] = 155; p = tgt + 4 * (w * (h - 1) + x); - p[1] = p[3] = 255.0; - p[-4 * w + 1] = p[-4 * w + 3] = 255.0; + p[1] = p[3] = 155; + p[-4 * w + 1] = p[-4 * w + 3] = 155; } for (y = 0; y < h; y++) { unsigned char *p = tgt + 4 * w * y; - p[1] = p[3] = 255.0; - p[4 + 1] = p[4 + 3] = 255.0; + p[1] = p[3] = 155; + p[4 + 1] = p[4 + 3] = 155; p = tgt + 4 * (w * y + w - 1); - p[1] = p[3] = 255.0; - p[-4 + 1] = p[-4 + 3] = 255.0; + p[1] = p[3] = 155; + p[-4 + 1] = p[-4 + 3] = 155; } } @@ -156,7 +156,8 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) unsigned char wtable[256]; wform_put_grid(tgt, w, h); - + wform_put_border(tgt, w, h); + for (x = 0; x < 256; x++) { wtable[x] = (unsigned char) (pow(((float) x + 1) / 256, waveform_gamma) * 255); } @@ -181,8 +182,6 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf) } } - wform_put_border(tgt, w, h); - return rval; } @@ -454,8 +453,8 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col) static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) { ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect); - int c, x, y; - unsigned int n; + int x, y; + unsigned int nr, ng, nb; unsigned char *src = (unsigned char *) ibuf->rect; unsigned int bins[3][HIS_STEPS]; @@ -487,19 +486,28 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) } } - n = 0; - for (c = 0; c < 3; c++) { - for (x = 0; x < HIS_STEPS; x++) { - if (bins[c][x] > n) { - n = bins[c][x]; - } - } + nr = nb = ng = 0; + for (x = 0; x < HIS_STEPS; x++) { + if (bins[0][x] > nr) + nr = bins[0][x]; + if (bins[1][x] > ng) + ng = bins[1][x]; + if (bins[2][x] > nb) + nb = bins[2][x]; } - for (c = 0; c < 3; c++) { - for (x = 0; x < HIS_STEPS; x++) { - draw_histogram_bar(rval, x * 2 + 1, ((float) bins[c][x]) / n, c); - draw_histogram_bar(rval, x * 2 + 2, ((float) bins[c][x]) / n, c); + for (x = 0; x < HIS_STEPS; x++) { + if (nr) { + draw_histogram_bar(rval, x * 2 + 1, ((float) bins[0][x]) / nr, 0); + draw_histogram_bar(rval, x * 2 + 2, ((float) bins[0][x]) / nr, 0); + } + if (ng) { + draw_histogram_bar(rval, x * 2 + 1, ((float) bins[1][x]) / ng, 1); + draw_histogram_bar(rval, x * 2 + 2, ((float) bins[1][x]) / ng, 1); + } + if (nb) { + draw_histogram_bar(rval, x * 2 + 1, ((float) bins[2][x]) / nb, 2); + draw_histogram_bar(rval, x * 2 + 2, ((float) bins[2][x]) / nb, 2); } } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 533bb30d8d1..a439b5b5b87 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1270,12 +1270,14 @@ void view3d_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object"); strcpy(pt->idname, "VIEW3D_PT_object"); strcpy(pt->label, N_("Transform")); /* XXX C panels not available through RNA (bpy.types)! */ + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = view3d_panel_object; BLI_addtail(&art->paneltypes, pt); pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel gpencil"); strcpy(pt->idname, "VIEW3D_PT_gpencil"); strcpy(pt->label, N_("Grease Pencil")); /* XXX C panels are not available through RNA (bpy.types)! */ + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw_header = gpencil_panel_standard_header; pt->draw = gpencil_panel_standard; BLI_addtail(&art->paneltypes, pt); @@ -1283,6 +1285,7 @@ void view3d_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup"); strcpy(pt->idname, "VIEW3D_PT_vgroup"); strcpy(pt->label, N_("Vertex Groups")); /* XXX C panels are not available through RNA (bpy.types)! */ + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = view3d_panel_vgroup; pt->poll = view3d_panel_vgroup_poll; BLI_addtail(&art->paneltypes, pt); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index d3bf8a30792..603d9a1595c 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -238,7 +238,8 @@ void view3d_toolshelf_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel tools"); strcpy(pt->idname, "VIEW3D_PT_tool_shelf"); - strcpy(pt->label, "Tool Shelf"); + strcpy(pt->label, N_("Tool Shelf")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = view3d_panel_tool_shelf; BLI_addtail(&art->paneltypes, pt); } @@ -249,7 +250,8 @@ void view3d_tool_props_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel last operator"); strcpy(pt->idname, "VIEW3D_PT_last_operator"); - strcpy(pt->label, "Operator"); + strcpy(pt->label, N_("Operator")); + strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw_header = view3d_panel_operator_redo_header; pt->draw = view3d_panel_operator_redo; BLI_addtail(&art->paneltypes, pt); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index cf960c953c3..f84c967711c 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -6469,7 +6469,7 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } - else { + else if (t->obedit) { createTransUVs(C, t); if (t->data && (t->flag & T_PROP_EDIT)) { sort_trans_data(t); // makes selected become first in array diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 2a3b0bc8726..3d3b8009c99 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1160,7 +1160,7 @@ int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even t->options |= CTX_MASK; } else { - BLI_assert(0); + /* image not in uv edit, nor in mask mode, can happen for some tools */ } } else if (t->spacetype == SPACE_NODE) { diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 778795bb3a1..60b0c655691 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -721,7 +721,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_view3d_active; + ot->poll = ED_operator_screenactive; RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index b80862d4db5..ba8b26c9083 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1339,8 +1339,14 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) } } else if (camera) { - struct ProjCameraInfo *uci = BLI_uvproject_camera_info(v3d->camera, obedit->obmat, scene->r.xsch, scene->r.ysch); + const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds"); + struct ProjCameraInfo *uci = BLI_uvproject_camera_info(v3d->camera, obedit->obmat, + camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f, + camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f); + + // BLI_uvproject_camera_info_scale + if (uci) { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) @@ -1401,7 +1407,10 @@ void UV_OT_project_from_view(wmOperatorType *ot) ot->poll = uv_from_view_poll; /* properties */ - RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection"); + RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", + "Use orthographic projection"); + RNA_def_boolean(ot->srna, "camera_bounds", 1, "Camera Bounds", + "Map UVs to the camera region taking resolution and aspect into account"); uv_map_clip_correct_properties(ot); } diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index c7a421a49fc..c455e8f7642 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -402,7 +402,7 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in } else { glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, - format, type, NULL); + format, type, NULL); if (fpixels) { glTexSubImage2D(tex->target, 0, 0, 0, w, h, @@ -677,7 +677,7 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) /* Now we tweak some of the settings */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, size, size, 0, GL_RG, GL_FLOAT, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, size, size, 0, GL_RG, GL_FLOAT, NULL); GPU_texture_unbind(tex); } diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index 3b6745de470..62a7cb674fc 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -97,6 +97,15 @@ if env['WITH_BF_OCEANSIM']: if env['WITH_BF_CYCLES']: defs.append('WITH_CYCLES') +if env['WITH_BF_SDL']: + defs.append('WITH_SDL') + +if env['WITH_BF_OPENAL']: + defs.append('WITH_OPENAL') + +if env['WITH_BF_JACK']: + defs.append('WITH_JACK') + if env['OURPLATFORM'] == 'linux': cflags='-pthread' incs += ' ../../../extern/binreloc/include' diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index c9a9cca3147..b118f5bc970 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -58,6 +58,20 @@ static EnumPropertyItem compute_device_type_items[] = { }; #endif +static EnumPropertyItem audio_device_items[] = { + {0, "NONE", 0, "None", "Null device - there will be no audio output"}, +#ifdef WITH_SDL + {1, "SDL", 0, "SDL", "SDL device - simple direct media layer, recommended for sequencer usage"}, +#endif +#ifdef WITH_OPENAL + {2, "OPENAL", 0, "OpenAL", "OpenAL device - supports 3D audio, recommended for game engine usage"}, +#endif +#ifdef WITH_JACK + {3, "JACK", 0, "Jack", "JACK - Audio Connection Kit, recommended for pro audio users"}, +#endif + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include "DNA_object_types.h" @@ -434,6 +448,41 @@ static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), P } #endif +static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), int *free) +{ +#ifdef WITH_JACK + int jack_supported = sound_is_jack_supported(); + + if (jack_supported) { + return audio_device_items; + } + else { + int index = 0; + int totitem = 0; + EnumPropertyItem *item = NULL; + + /* NONE */ + RNA_enum_item_add(&item, &totitem, &audio_device_items[index++]); + +#ifdef WITH_SDL + RNA_enum_item_add(&item, &totitem, &audio_device_items[index++]); +#endif + +#ifdef WITH_OPENAL + RNA_enum_item_add(&item, &totitem, &audio_device_items[index++]); +#endif + + RNA_enum_item_end(&item, &totitem); + *free = 1; + + return item; + } +#else + return audio_device_items; +#endif +} + #ifdef WITH_INTERNATIONAL static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) @@ -3244,20 +3293,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static EnumPropertyItem audio_device_items[] = { - {0, "NONE", 0, "None", "Null device - there will be no audio output"}, -#ifdef WITH_SDL - {1, "SDL", 0, "SDL", "SDL device - simple direct media layer, recommended for sequencer usage"}, -#endif -#ifdef WITH_OPENAL - {2, "OPENAL", 0, "OpenAL", "OpenAL device - supports 3D audio, recommended for game engine usage"}, -#endif -#ifdef WITH_JACK - {3, "JACK", 0, "Jack", "JACK - Audio Connection Kit, recommended for pro audio users"}, -#endif - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem audio_rate_items[] = { /* {8000, "RATE_8000", 0, "8 kHz", "Set audio sampling rate to 8000 samples per second"}, */ /* {11025, "RATE_11025", 0, "11.025 kHz", "Set audio sampling rate to 11025 samples per second"}, */ @@ -3534,6 +3569,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "audio_device", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "audiodevice"); RNA_def_property_enum_items(prop, audio_device_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_audio_device_itemf"); RNA_def_property_ui_text(prop, "Audio Device", "Audio output device"); RNA_def_property_update(prop, 0, "rna_UserDef_audio_update"); diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index c09903ad6c5..9b0a435f9a9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -174,11 +174,24 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node) { Image *ima= (Image *)node->id; if (ima) { - ImageUser *iuser= node->storage; + ImageUser *iuser = node->storage; + ImageUser load_iuser = {NULL}; ImBuf *ibuf; - + int offset = BKE_image_sequence_guess_offset(ima); + + /* It is possible that image user in this node is not + * properly updated yet. In this case loading image will + * fail and sockets detection will go wrong. + * + * So we manually construct image user to be sure first + * image from sequence (that one which is set as fileanme + * for image datablock) is used for sockets detection + */ + load_iuser.ok = 1; + load_iuser.framenr = offset; + /* make sure ima->type is correct */ - ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); + ibuf = BKE_image_acquire_ibuf(ima, &load_iuser, NULL); if (ima->rr) { RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 721bfa01a92..1450af4ff83 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2373,6 +2373,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie char name[FILE_MAX]; RenderResult rres; Object *camera = RE_GetCamera(re); + double render_time; int ok = 1; RE_AcquireResultImage(re, &rres); @@ -2456,11 +2457,17 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie RE_ReleaseResultImage(re); + render_time = re->i.lastframetime; + re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; + BLI_timestr(re->i.lastframetime, name); printf(" Time: %s", name); - + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_RENDER_STATS); + BLI_timestr(re->i.lastframetime - render_time, name); + printf(" (Saving: %s)\n", name); + fputc('\n', stdout); fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */ diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index e2fb9573129..b96d25e04d9 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -199,7 +199,7 @@ void KX_Dome::CreateGLImages(void) for (int j=0;j<m_numfaces;j++) { glBindTexture(GL_TEXTURE_2D, domefacesId[j]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_imagesize, m_imagesize, 0, GL_RGB8, - GL_UNSIGNED_BYTE, 0); + GL_UNSIGNED_BYTE, NULL); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, m_imagesize, m_imagesize, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -209,7 +209,7 @@ void KX_Dome::CreateGLImages(void) if (warp.usemesh) { glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, warp.imagesize, warp.imagesize, 0, GL_RGB8, - GL_UNSIGNED_BYTE, 0); + GL_UNSIGNED_BYTE, NULL); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, warp.imagesize, warp.imagesize, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |