diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index d628fa04f92..90278f215c0 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -462,6 +462,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri mesh->name = ustring(b_ob_data.name().c_str()); if(render_layer.use_surfaces || render_layer.use_hair) { + if(preview) + b_ob.update_from_editmode(); + BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed); if(b_mesh) { diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 572cfae45cd..b509134512b 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -223,7 +223,7 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int float3 f = make_float3(in[0], in[1], in[2]); float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]); - f = safe_divide_color(f*exposure, f_divide); + f = safe_divide_even_color(f*exposure, f_divide); pixels[0] = f.x; pixels[1] = f.y; diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 14ebf311a4b..cde547cd77c 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -1100,6 +1100,42 @@ __device_inline float3 safe_divide_color(float3 a, float3 b) return make_float3(x, y, z); } +__device_inline float3 safe_divide_even_color(float3 a, float3 b) +{ + float x, y, z; + + x = (b.x != 0.0f)? a.x/b.x: 0.0f; + y = (b.y != 0.0f)? a.y/b.y: 0.0f; + z = (b.z != 0.0f)? a.z/b.z: 0.0f; + + /* try to get grey even if b is zero */ + if(b.x == 0.0f) { + if(b.y == 0.0f) { + x = z; + y = z; + } + else if(b.z == 0.0f) { + x = y; + z = y; + } + else + x = 0.5f*(y + z); + } + else if(b.y == 0.0f) { + if(b.z == 0.0f) { + y = x; + z = x; + } + else + y = 0.5f*(x + z); + } + else if(b.z == 0.0f) { + z = 0.5f*(x + y); + } + + return make_float3(x, y, z); +} + /* Rotation of point around axis and angle */ __device_inline float3 rotate_around_axis(float3 p, float3 axis, float angle) diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/modules/rna_keymap_ui.py similarity index 100% rename from release/scripts/startup/bl_ui/space_userpref_keymap.py rename to release/scripts/modules/rna_keymap_ui.py diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index a5e4b6e10bf..3e281e08983 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1052,7 +1052,7 @@ class USERPREF_PT_input(Panel): row.separator() def draw(self, context): - from bl_ui.space_userpref_keymap import draw_keymaps + from rna_keymap_ui import draw_keymaps layout = self.layout diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 34f34bb9951..61f665be586 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -75,7 +75,17 @@ struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob); void BKE_scene_base_unlink(struct Scene *sce, struct Base *base); void BKE_scene_base_deselect_all(struct Scene *sce); void BKE_scene_base_select(struct Scene *sce, struct Base *selbase); -int BKE_scene_base_iter_next(struct Scene **scene, int val, struct Base **base, struct Object **ob); + +/* Scene base iteration function. + * Define struct here, so no need to bother with alloc/free it. + */ +typedef struct SceneBaseIter { + struct ListBase *duplilist; + struct DupliObject *dupob; + int fase; +} SceneBaseIter; + +int BKE_scene_base_iter_next(struct SceneBaseIter *iter, struct Scene **scene, int val, struct Base **base, struct Object **ob); void BKE_scene_base_flag_to_objects(struct Scene *scene); void BKE_scene_base_flag_from_objects(struct Scene *scene); diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index ffcb7d3e265..e10dbe7f41b 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -486,14 +486,15 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) MetaBall *active_mball = (MetaBall *)active_object->data; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; - + SceneBaseIter iter; + BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(&sce_iter, 0, NULL, NULL)) + if (F_ERROR == BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL)) return; - while (BKE_scene_base_iter_next(&sce_iter, 1, &base, &ob)) { + while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob != active_object) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); @@ -530,14 +531,15 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis) Object *ob, *bob = basis; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; + SceneBaseIter iter; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(&sce_iter, 0, NULL, NULL)) + if (F_ERROR == BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL)) return NULL; - while (BKE_scene_base_iter_next(&sce_iter, 1, &base, &ob)) { + while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob != bob) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); @@ -1656,7 +1658,8 @@ static float init_meta(PROCESS *process, Scene *scene, Object *ob) /* return //float max = 0.0f; int a, obnr, zero_size = 0; char obname[MAX_ID_NAME]; - + SceneBaseIter iter; + copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */ invert_m4_m4(obinv, ob->obmat); a = 0; @@ -1664,8 +1667,8 @@ static float init_meta(PROCESS *process, Scene *scene, Object *ob) /* return BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); /* make main array */ - BKE_scene_base_iter_next(&sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(&sce_iter, 1, &base, &bob)) { + BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL); + while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &bob)) { if (bob->type == OB_MBALL) { zero_size = 0; @@ -2226,15 +2229,16 @@ static void mball_count(PROCESS *process, Scene *scene, Object *basis) MetaElem *ml = NULL; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; + SceneBaseIter iter; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); process->totelem = 0; /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(&sce_iter, 0, NULL, NULL)) + if (F_ERROR == BKE_scene_base_iter_next(&iter, &sce_iter, 0, NULL, NULL)) return; - while (BKE_scene_base_iter_next(&sce_iter, 1, &base, &ob)) { + while (BKE_scene_base_iter_next(&iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob == bob) { MetaBall *mb = ob->data; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 2951d90fec2..3ccd7b6e674 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -747,17 +747,16 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) /* used by metaballs * doesn't return the original duplicated object, only dupli's */ -int BKE_scene_base_iter_next(Scene **scene, int val, Base **base, Object **ob) +int BKE_scene_base_iter_next(SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) { - static ListBase *duplilist = NULL; - static DupliObject *dupob; - static int fase = F_START, in_next_object = 0; + static ThreadVariable int in_next_object = 0; int run_again = 1; /* init */ if (val == 0) { - fase = F_START; - dupob = NULL; + iter->fase = F_START; + iter->dupob = NULL; + iter->duplilist = NULL; /* XXX particle systems with metas+dupligroups call this recursively */ /* see bug #18725 */ @@ -775,11 +774,11 @@ int BKE_scene_base_iter_next(Scene **scene, int val, Base **base, Object **ob) run_again = 0; /* the first base */ - if (fase == F_START) { + if (iter->fase == F_START) { *base = (*scene)->base.first; if (*base) { *ob = (*base)->object; - fase = F_SCENE; + iter->fase = F_SCENE; } else { /* exception: empty scene */ @@ -788,20 +787,20 @@ int BKE_scene_base_iter_next(Scene **scene, int val, Base **base, Object **ob) if ((*scene)->base.first) { *base = (*scene)->base.first; *ob = (*base)->object; - fase = F_SCENE; + iter->fase = F_SCENE; break; } } } } else { - if (*base && fase != F_DUPLI) { + if (*base && iter->fase != F_DUPLI) { *base = (*base)->next; if (*base) { *ob = (*base)->object; } else { - if (fase == F_SCENE) { + if (iter->fase == F_SCENE) { /* (*scene) is finished, now do the set */ while ((*scene)->set) { (*scene) = (*scene)->set; @@ -817,45 +816,45 @@ int BKE_scene_base_iter_next(Scene **scene, int val, Base **base, Object **ob) } if (*base == NULL) { - fase = F_START; + iter->fase = F_START; } else { - if (fase != F_DUPLI) { + if (iter->fase != F_DUPLI) { if ( (*base)->object->transflag & OB_DUPLI) { /* groups cannot be duplicated for mballs yet, * this enters eternal loop because of * makeDispListMBall getting called inside of group_duplilist */ if ((*base)->object->dup_group == NULL) { - duplilist = object_duplilist((*scene), (*base)->object, FALSE); + iter->duplilist = object_duplilist((*scene), (*base)->object, FALSE); - dupob = duplilist->first; + iter->dupob = iter->duplilist->first; - if (!dupob) - free_object_duplilist(duplilist); + if (!iter->dupob) + free_object_duplilist(iter->duplilist); } } } /* handle dupli's */ - if (dupob) { + if (iter->dupob) { - copy_m4_m4(dupob->ob->obmat, dupob->mat); + copy_m4_m4(iter->dupob->ob->obmat, iter->dupob->mat); (*base)->flag |= OB_FROMDUPLI; - *ob = dupob->ob; - fase = F_DUPLI; + *ob = iter->dupob->ob; + iter->fase = F_DUPLI; - dupob = dupob->next; + iter->dupob = iter->dupob->next; } - else if (fase == F_DUPLI) { - fase = F_SCENE; + else if (iter->fase == F_DUPLI) { + iter->fase = F_SCENE; (*base)->flag &= ~OB_FROMDUPLI; - for (dupob = duplilist->first; dupob; dupob = dupob->next) { - copy_m4_m4(dupob->ob->obmat, dupob->omat); + for (iter->dupob = iter->duplilist->first; iter->dupob; iter->dupob = iter->dupob->next) { + copy_m4_m4(iter->dupob->ob->obmat, iter->dupob->omat); } - free_object_duplilist(duplilist); - duplilist = NULL; + free_object_duplilist(iter->duplilist); + iter->duplilist = NULL; run_again = 1; } } @@ -871,7 +870,7 @@ int BKE_scene_base_iter_next(Scene **scene, int val, Base **base, Object **ob) /* reset recursion test */ in_next_object = 0; - return fase; + return iter->fase; } Object *BKE_scene_camera_find(Scene *sc) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 296f25e303e..aec924e15b3 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -847,19 +847,6 @@ int txt_utf8_column_to_offset(const char *str, int column) return offset; } -/* returns the real number of characters in string */ -/* not the same as BLI_strlen_utf8, which returns length for wide characters */ -static int txt_utf8_len(const char *src) -{ - int len; - - for (len = 0; *src; len++) { - src += BLI_str_utf8_size(src); - } - - return len; -} - void txt_move_up(Text *text, short sel) { TextLine **linep; @@ -2059,7 +2046,7 @@ void txt_do_undo(Text *text) text->undo_pos--; } buf[i] = 0; - linep = txt_utf8_len(buf); + linep = BLI_strlen_utf8(buf); MEM_freeN(buf); /* skip over the length that was stored again */ diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index d20cbd2a91c..adef843d2cc 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -51,8 +51,10 @@ char *BLI_str_prev_char_utf8(const char *p); /* wchar_t functions, copied from blenders own font.c originally */ size_t BLI_wstrlen_utf8(const wchar_t *src); +size_t BLI_strlen_utf8_ex(const char *strc, int *r_len_bytes); size_t BLI_strlen_utf8(const char *strc); -size_t BLI_strnlen_utf8(const char *start, const size_t maxlen); +size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, int *r_len_bytes); +size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen); size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, const size_t maxcpy); size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst, const char *__restrict src, const size_t maxcpy); diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index a64745d1dfe..329cc2959ca 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -132,6 +132,18 @@ void BLI_rw_mutex_free(ThreadRWMutex *mutex); void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode); void BLI_rw_mutex_unlock(ThreadRWMutex *mutex); +/* Ticket Mutex Lock + * + * This is a 'fair' mutex in that it will grant the lock to the first thread + * that requests it. */ + +typedef struct TicketMutex TicketMutex; + +TicketMutex *BLI_ticket_mutex_alloc(void); +void BLI_ticket_mutex_free(TicketMutex *ticket); +void BLI_ticket_mutex_lock(TicketMutex *ticket); +void BLI_ticket_mutex_unlock(TicketMutex *ticket); + /* ThreadedWorker * * A simple tool for dispatching work to a limited number of threads @@ -181,6 +193,13 @@ void BLI_condition_notify_one(ThreadCondition *cond); void BLI_condition_notify_all(ThreadCondition *cond); void BLI_condition_end(ThreadCondition *cond); +/* Thread Local Storage */ +#ifdef _MSC_VER +# define ThreadVariable __declspec(thread) +#else +# define ThreadVariable __thread +#endif + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index b8dca95ae33..ab0073a7585 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -245,24 +245,16 @@ size_t BLI_wstrlen_utf8(const wchar_t *src) return len; } -/* this is very close to 'BLI_str_utf8_size' functionality, perhaps we should de-duplicate */ -/* size of UTF-8 character in bytes */ -static size_t strlen_utf8_char(const char *strc) +size_t BLI_strlen_utf8_ex(const char *strc, int *r_len_bytes) { - if ((*strc & 0xe0) == 0xc0) { - if ((strc[1] & 0x80) && (strc[1] & 0x40) == 0x00) - return 2; - } - else if ((*strc & 0xf0) == 0xe0) { - if ((strc[1] & strc[2] & 0x80) && ((strc[1] | strc[2]) & 0x40) == 0x00) - return 3; - } - else if ((*strc & 0xf8) == 0xf0) { - if ((strc[1] & strc[2] & strc[3] & 0x80) && ((strc[1] | strc[2] | strc[3]) & 0x40) == 0x00) - return 4; - } + size_t len; + const char *strc_orig = strc; - return 1; + for (len = 0; *strc; len++) + strc += BLI_str_utf8_size_safe(strc); + + *r_len_bytes = (strc - strc_orig); + return len; } size_t BLI_strlen_utf8(const char *strc) @@ -270,25 +262,37 @@ size_t BLI_strlen_utf8(const char *strc) size_t len; for (len = 0; *strc; len++) - strc += strlen_utf8_char(strc); + strc += BLI_str_utf8_size_safe(strc); return len; } +size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, int *r_len_bytes) +{ + size_t len; + const char *strc_orig = strc; + const char *strc_end = strc + maxlen; + + for (len = 0; *strc && strc < strc_end; len++) { + strc += BLI_str_utf8_size_safe(strc); + } + + *r_len_bytes = (strc - strc_orig); + return len; +} + /** * \param start the string to measure the length. * \param maxlen the string length (in bytes) * \return the unicode length (not in bytes!) */ -size_t BLI_strnlen_utf8(const char *start, const size_t maxlen) +size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen) { - const char *strc = start; - const char *strc_end = start + maxlen; - size_t len; + const char *strc_end = strc + maxlen; for (len = 0; *strc && strc < strc_end; len++) { - strc += strlen_utf8_char(strc); + strc += BLI_str_utf8_size_safe(strc); } return len; diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index cd3132682b6..033213dff5d 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -513,6 +513,52 @@ void BLI_rw_mutex_free(ThreadRWMutex *mutex) MEM_freeN(mutex); } +/* Ticket Mutex Lock */ + +struct TicketMutex { + pthread_cond_t cond; + pthread_mutex_t mutex; + unsigned int queue_head, queue_tail; +}; + +TicketMutex *BLI_ticket_mutex_alloc(void) +{ + TicketMutex *ticket = MEM_callocN(sizeof(TicketMutex), "TicketMutex"); + + pthread_cond_init(&ticket->cond, NULL); + pthread_mutex_init(&ticket->mutex, NULL); + + return ticket; +} + +void BLI_ticket_mutex_free(TicketMutex *ticket) +{ + pthread_mutex_destroy(&ticket->mutex); + pthread_cond_destroy(&ticket->cond); + MEM_freeN(ticket); +} + +void BLI_ticket_mutex_lock(TicketMutex *ticket) +{ + unsigned int queue_me; + + pthread_mutex_lock(&ticket->mutex); + queue_me = ticket->queue_tail++; + + while (queue_me != ticket->queue_head) + pthread_cond_wait(&ticket->cond, &ticket->mutex); + + pthread_mutex_unlock(&ticket->mutex); +} + +void BLI_ticket_mutex_unlock(TicketMutex *ticket) +{ + pthread_mutex_lock(&ticket->mutex); + ticket->queue_head++; + pthread_cond_broadcast(&ticket->cond); + pthread_mutex_unlock(&ticket->mutex); +} + /* ************************************************ */ typedef struct ThreadedWorker { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b7a9ce092ef..5381bfebf2e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5707,8 +5707,9 @@ static void lib_link_screen(FileData *fd, Main *main) ntree = nodetree_from_id(snode->id); if (ntree) snode->nodetree = ntree; - else - snode->nodetree = newlibadr(fd, sc->id.lib, snode->nodetree); + else { + snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree); + } for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { @@ -5716,7 +5717,7 @@ static void lib_link_screen(FileData *fd, Main *main) path->nodetree = snode->nodetree; } else - path->nodetree = newlibadr(fd, sc->id.lib, path->nodetree); + path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree); if (!path->nodetree) break; @@ -6045,7 +6046,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc path->nodetree = snode->nodetree; } else - path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, 0); + path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, 2); if (!path->nodetree) break; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 9b6699f3f21..dd4361be1ff 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1642,13 +1642,6 @@ static void write_mballs(WriteData *wd, ListBase *idbase) } } -static int amount_of_chars(char *str) -{ - // Since the data is saved as UTF-8 to the cu->str - // The cu->len is not same as the strlen(cu->str) - return strlen(str); -} - static void write_curves(WriteData *wd, ListBase *idbase) { Curve *cu; @@ -1666,8 +1659,12 @@ static void write_curves(WriteData *wd, ListBase *idbase) if (cu->adt) write_animdata(wd, cu->adt); if (cu->vfont) { - writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str); - writestruct(wd, DATA, "CharInfo", cu->len+1, cu->strinfo); + /* TODO, sort out 'cu->len', in editmode its character, object mode its bytes */ + int len_bytes; + int len_chars = BLI_strlen_utf8_ex(cu->str, &len_bytes); + + writedata(wd, DATA, len_bytes + 1, cu->str); + writestruct(wd, DATA, "CharInfo", len_chars + 1, cu->strinfo); writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb); } else { diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index be186e0441b..a00bef0228b 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -1758,6 +1758,119 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed) return vol; } + +/** + * TODO (as we need) + * - option to walk over faces by verts. + * - option to walk over non manifold edges. + * + * \param bm the BMesh. + * \param r_groups_array Array of ints to fill in, length of bm->totface. + * \param r_group_index index, length pairs into \a r_groups_array, size of return value + * int pairs: (array_start, array_length). + * \return The number of groups found. + */ +int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], + void *user_data, bool (*filter_fn)(BMEdge *, void *user_data)) +{ +#ifdef DEBUG + int group_index_len = 1; +#else + int group_index_len = 32; +#endif + + int (*group_index)[2] = MEM_mallocN(sizeof(*group_index) * group_index_len, __func__); + + int *group_array = r_groups_array; + STACK_DECLARE(group_array); + + int group_curr = 0; + + const unsigned int tot_faces = bm->totface; + unsigned int tot_touch = 0; + + BMFace **fstack; + STACK_DECLARE(fstack); + + BMIter iter; + BMFace *f; + int i; + + STACK_INIT(group_array); + + /* init the array */ + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + BM_elem_index_set(f, i); /* set_inline */ + BM_elem_flag_disable(f, BM_ELEM_TAG); + } + bm->elem_index_dirty &= ~BM_FACE; + + /* detect groups */ + fstack = MEM_mallocN(sizeof(*fstack) * tot_faces, __func__); + + while (tot_touch != tot_faces) { + int *fg; + bool ok = false; + + BLI_assert(tot_touch < tot_faces); + + STACK_INIT(fstack); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG) == false) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + STACK_PUSH(fstack, f); + ok = true; + break; + } + } + + BLI_assert(ok == true); + + /* manage arrays */ + if (group_index_len == group_curr) { + group_index_len *= 2; + group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_index_len); + } + + fg = group_index[group_curr]; + fg[0] = STACK_SIZE(group_array); + fg[1] = 0; + + while ((f = STACK_POP(fstack))) { + BMLoop *l_iter, *l_first; + + /* add face */ + STACK_PUSH(group_array, BM_elem_index_get(f)); + tot_touch++; + fg[1]++; + /* done */ + + /* search for other faces */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMLoop *l_other = l_iter->radial_next; + if ((l_other != l_iter) && filter_fn(l_iter->e, user_data)) { + if (BM_elem_flag_test(l_other->f, BM_ELEM_TAG) == false) { + BM_elem_flag_enable(l_other->f, BM_ELEM_TAG); + STACK_PUSH(fstack, l_other->f); + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + group_curr++; + } + + MEM_freeN(fstack); + + /* reduce alloc to required size */ + group_index = MEM_reallocN(group_index, sizeof(*group_index) * group_curr); + *r_group_index = group_index; + + return group_curr; +} + float bmesh_subd_falloff_calc(const int falloff, float val) { switch (falloff) { diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 7d599a9c8af..94dae1d1d23 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -115,6 +115,8 @@ bool BM_face_is_any_vert_flag_test(BMFace *f, const char hflag); bool BM_face_is_any_edge_flag_test(BMFace *f, const char hflag); float BM_mesh_calc_volume(BMesh *bm, bool is_signed); +int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], + void *user_data, bool (*filter_fn)(BMEdge *, void *user_data)); /* not really any good place to put this */ float bmesh_subd_falloff_calc(const int falloff, float val); diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index 88a4d4478be..4291fc22793 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -36,8 +36,105 @@ /********* righthand faces implementation ****** */ -#define FACE_VIS 1 -#define FACE_FLAG 2 +#define FACE_FLAG (1 << 0) +#define FACE_FLIP (1 << 1) +#define FACE_TEMP (1 << 2) + +static bool bmo_recalc_normal_edge_filter_cb(BMEdge *e, void *UNUSED(user_data)) +{ + return BM_edge_is_manifold(e); +} + +/** + * Given an array of faces, recalcualte their normals. + * this functions assumes all faces in the array are connected by edges. + * + * \param bm + * \param faces Array of connected faces. + * \param faces_len Length of \a faces + * \param oflag Flag to check before doing the actual face flipping. + */ +static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int faces_len, const short oflag) +{ + float cent[3], tvec[3]; + float (*faces_center)[3] = MEM_mallocN(sizeof(*faces_center) * faces_len, __func__); + const float cent_fac = 1.0f / (float)faces_len; + int i, f_start_index; + const short oflag_flip = oflag | FACE_FLIP; + + float f_len_best; + BMFace *f; + + BMFace **fstack = MEM_mallocN(sizeof(*fstack) * faces_len, __func__); + STACK_DECLARE(fstack); + + zero_v3(cent); + + /* first calculate the center */ + for (i = 0; i < faces_len; i++) { + float *f_cent = faces_center[i]; + BM_face_calc_center_mean_weighted(faces[i], f_cent); + madd_v3_v3fl(cent, f_cent, cent_fac); + + BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0); + } + + f_len_best = -FLT_MAX; + + for (i = 0; i < faces_len; i++) { + float f_len_test; + + if ((f_len_test = len_squared_v3v3(faces_center[i], cent)) > f_len_best) { + f_len_best = f_len_test; + f_start_index = i; + } + } + + /* make sure the starting face has the correct winding */ + sub_v3_v3v3(tvec, faces_center[f_start_index], cent); + if (dot_v3v3(tvec, faces[f_start_index]->no) < 0.0f) { + BMO_elem_flag_enable(bm, faces[f_start_index], FACE_FLIP); + } + + MEM_freeN(faces_center); + + /* now that we've found our starting face, make all connected faces + * have the same winding. this is done recursively, using a manual + * stack (if we use simple function recursion, we'd end up overloading + * the stack on large meshes). */ + STACK_INIT(fstack); + + STACK_PUSH(fstack, faces[f_start_index]); + BMO_elem_flag_enable(bm, faces[f_start_index], FACE_TEMP); + + while ((f = STACK_POP(fstack))) { + const bool flip_state = BMO_elem_flag_test_bool(bm, f, FACE_FLIP); + BMLoop *l_iter, *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMLoop *l_other = l_iter->radial_next; + + if ((l_other != l_iter) && bmo_recalc_normal_edge_filter_cb(l_iter->e, NULL)) { + if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) { + BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP); + BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); + STACK_PUSH(fstack, l_other->f); + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + MEM_freeN(fstack); + + /* apply flipping to oflag'd faces */ + for (i = 0; i < faces_len; i++) { + if (BMO_elem_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { + BM_face_normal_flip(bm, faces[i]); + } + BMO_elem_flag_disable(bm, faces[i], FACE_TEMP); + } +} /* * put normal to the outside, and set the first direction flags in edges @@ -47,92 +144,44 @@ * * in case all faces were not done: start over with 'find the ultimate ...' */ -/* NOTE: BM_ELEM_TAG is used on faces to tell if they are flipped. */ - void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) { - BMFace **fstack; - STACK_DECLARE(fstack); - const unsigned int tot_faces = BMO_slot_buffer_count(op->slots_in, "faces"); - unsigned int tot_touch = 0; + int *groups_array = MEM_mallocN(sizeof(groups_array) * bm->totface, __func__); + int faces_len; + BMFace **faces_arr = BM_iter_as_arrayN(bm, BM_FACES_OF_MESH, NULL, &faces_len, NULL, 0); + BMFace **faces_grp = MEM_mallocN(sizeof(faces_grp) * bm->totface, __func__); + + int (*group_index)[2]; + const int group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index, + NULL, bmo_recalc_normal_edge_filter_cb); + int i; + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG); - fstack = MEM_mallocN(sizeof(*fstack) * tot_faces, __func__); + for (i = 0; i < group_tot; i++) { + const int fg_sta = group_index[i][0]; + const int fg_len = group_index[i][1]; + int j; + bool is_calc = false; - while (tot_touch != tot_faces) { - BMOIter siter; - float f_len_best = -FLT_MAX; - BMFace *f, *f_start = NULL; - float f_start_cent[3]; + for (j = 0; j < fg_len; j++) { + faces_grp[j] = faces_arr[groups_array[fg_sta + j]]; - /* find a starting face */ - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - float f_cent[3]; - float f_len_test; - - /* clear dirty flag */ - BM_elem_flag_disable(f, BM_ELEM_TAG); - - if (BMO_elem_flag_test(bm, f, FACE_VIS)) - continue; - - if (!f_start) f_start = f; - - BM_face_calc_center_bounds(f, f_cent); - - if ((f_len_test = len_squared_v3(f_cent)) > f_len_best) { - f_len_best = f_len_test; - f_start = f; - copy_v3_v3(f_start_cent, f_cent); + if (is_calc == false) { + is_calc = BMO_elem_flag_test_bool(bm, faces_grp[j], FACE_FLAG); } } - /* check sanity (while loop ensures) */ - BLI_assert(f_start != NULL); - - /* make sure the starting face has the correct winding */ - if (dot_v3v3(f_start_cent, f_start->no) < 0.0f) { - BM_face_normal_flip(bm, f_start); - } - - /* now that we've found our starting face, make all connected faces - * have the same winding. this is done recursively, using a manual - * stack (if we use simple function recursion, we'd end up overloading - * the stack on large meshes). */ - STACK_INIT(fstack); - - STACK_PUSH(fstack, f_start); - BMO_elem_flag_enable(bm, f_start, FACE_VIS); - tot_touch++; - - while ((f = STACK_POP(fstack))) { - BMIter liter; - BMLoop *l; - - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BMLoop *l_other = l->radial_next; - - if ((l_other == l) || l_other->radial_next != l) { - continue; - } - - if (BMO_elem_flag_test(bm, l_other->f, FACE_FLAG)) { - if (!BMO_elem_flag_test(bm, l_other->f, FACE_VIS)) { - BMO_elem_flag_enable(bm, l_other->f, FACE_VIS); - tot_touch++; - - - if (l_other->v == l->v) { - BM_face_normal_flip(bm, l_other->f); - } - - STACK_PUSH(fstack, l_other->f); - } - } - } + if (is_calc) { + bmo_recalc_face_normals_array(bm, faces_grp, fg_len, FACE_FLAG); } } - MEM_freeN(fstack); + + if (faces_arr) MEM_freeN(faces_arr); + MEM_freeN(faces_grp); + + MEM_freeN(groups_array); + MEM_freeN(group_index); } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index d7073ef61be..e0c11414e38 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -2223,6 +2223,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) BMVert *bmv1, *bmv2, *bmv3, *bmv4, *bmv1i, *bmv2i, *bmv3i, *bmv4i; VMesh *vm1, *vm2; EdgeHalf *e1, *e2; + BMEdge *bme1, *bme2; BMFace *f1, *f2, *f; int k, nseg, i1, i2, odd, mid; @@ -2294,6 +2295,13 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) bev_merge_end_uvs(bm, bv1, e1); if (!e2->is_seam && bv2->vmesh->mesh_kind == M_NONE) bev_merge_end_uvs(bm, bv2, e2); + + /* Copy edge data to first and last edge */ + bme1 = BM_edge_exists(bmv1, bmv2); + bme2 = BM_edge_exists(bmv3, bmv4); + BLI_assert(bme1 && bme2); + BM_elem_attrs_copy(bm, bm, bme, bme1); + BM_elem_attrs_copy(bm, bm, bme, bme2); } /* diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index c1ddd9a6294..e8e7643164f 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -52,6 +52,8 @@ void ED_render_engine_changed(struct Main *bmain); void ED_render_engine_area_exit(struct ScrArea *sa); void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated); +void ED_viewport_render_kill_jobs(const struct bContext *C); + /* render_preview.c */ /* stores rendered preview - is also used for icons */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 9ac499fc94b..c3bc87ac647 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2167,6 +2167,15 @@ static void ui_set_but_soft_range(uiBut *but) but->softmin = softmin; but->softmax = softmax; } + else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) { + float value = ui_get_but_val(but); + CLAMP(value, but->hardmin, but->hardmax); + but->softmin = min_ff(but->softmin, value); + but->softmax = max_ff(but->softmax, value); + } + else { + BLI_assert(0); + } } /* ******************* Free ********************/ @@ -2368,8 +2377,12 @@ void ui_check_but(uiBut *but) ui_check_but_select(but, &value); /* only update soft range while not editing */ - if (but->rnaprop && !(but->editval || but->editstr || but->editvec)) { - ui_set_but_soft_range(but); + if (!(but->editval || but->editstr || but->editvec)) { + if ((but->rnaprop != NULL) || + (but->poin && (but->pointype & UI_BUT_POIN_TYPES))) + { + ui_set_but_soft_range(but); + } } /* test for min and max, icon sliders, etc */ @@ -2757,13 +2770,10 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, uiBut *but; int slen; - BLI_assert(width >= 0); - BLI_assert(height >= 0); + BLI_assert(width >= 0 && height >= 0); /* we could do some more error checks here */ if ((type & BUTTYPE) == LABEL) { - if ((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f))) - printf("blah\n"); BLI_assert((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)) == FALSE); } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 9558baf0334..2e915d6357d 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2116,7 +2116,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper static char tip[50]; static char hexcol[128]; float rgb_gamma[3]; - float min, max, step, precision; + float softmin, softmax, hardmin, hardmax, step, precision; float *hsv = ui_block_hsv_get(block); int yco; @@ -2142,7 +2142,8 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper /* sneaky way to check for alpha */ rgba[3] = FLT_MAX; - RNA_property_float_ui_range(ptr, prop, &min, &max, &step, &precision); + RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision); + RNA_property_float_range(ptr, prop, &hardmin, &hardmax); RNA_property_float_get_array(ptr, prop, rgba); switch (U.color_picker_type) { @@ -2196,7 +2197,8 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv); bt = uiDefButF(block, NUMSLI, 0, IFACE_("S "), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 1, 0.0, 1.0, 10, 3, TIP_("Saturation")); uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv); - bt = uiDefButF(block, NUMSLI, 0, IFACE_("V "), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 2, 0.0, max, 10, 3, TIP_("Value")); + bt = uiDefButF(block, NUMSLI, 0, IFACE_("V "), 0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, hsv + 2, 0.0, softmax, 10, 3, TIP_("Value")); + bt->hardmax = hardmax; /* not common but rgb may be over 1.0 */ uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv); uiBlockEndAlign(block); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 699da98225a..8caa059d168 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3020,16 +3020,16 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title, /* recurse for nested properties */ if (RNA_property_type(prop) == PROP_POINTER) { PointerRNA propptr = RNA_property_pointer_get(ptr, prop); - const char *name = RNA_property_ui_name(prop); if (propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) { + const char *name = RNA_property_ui_name(prop); template_keymap_item_properties(layout, name, &propptr); continue; } } /* add property */ - uiItemR(flow, ptr, RNA_property_identifier(prop), 0, NULL, ICON_NONE); + uiItemFullR(flow, ptr, prop, -1, 0, 0, NULL, ICON_NONE); } RNA_STRUCT_END; } diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index b2c7846ab6c..6fd198d9ae6 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -95,9 +95,11 @@ void paintface_flush_flags(Object *ob) /* loop over tessfaces */ for (i = 0; i < totface; i++) { - /* Copy flags onto the original tessface from its original poly */ - mp_orig = me->mpoly + index_array[i]; - faces[i].flag = mp_orig->flag; + if (index_array[i] != ORIGINDEX_NONE) { + /* Copy flags onto the original tessface from its original poly */ + mp_orig = me->mpoly + index_array[i]; + faces[i].flag = mp_orig->flag; + } } } @@ -107,9 +109,11 @@ void paintface_flush_flags(Object *ob) /* loop over final derived polys */ for (i = 0; i < totpoly; i++) { - /* Copy flags onto the final derived poly from the original mesh poly */ - mp_orig = me->mpoly + index_array[i]; - polys[i].flag = mp_orig->flag; + if (index_array[i] != ORIGINDEX_NONE) { + /* Copy flags onto the final derived poly from the original mesh poly */ + mp_orig = me->mpoly + index_array[i]; + polys[i].flag = mp_orig->flag; + } } } @@ -120,9 +124,11 @@ void paintface_flush_flags(Object *ob) /* loop over tessfaces */ for (i = 0; i < totface; i++) { - /* Copy flags onto the final tessface from its final poly */ - mp_orig = polys + index_array[i]; - faces[i].flag = mp_orig->flag; + if (index_array[i] != ORIGINDEX_NONE) { + /* Copy flags onto the final tessface from its final poly */ + mp_orig = polys + index_array[i]; + faces[i].flag = mp_orig->flag; + } } } } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 2c721a0a9dc..77a79e57dbc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -4007,8 +4007,9 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op) } if (!EDBM_op_finish(em, &bmop, op, true)) { - return OPERATOR_CANCELLED; - + /* grr, need to return finished so the user can select different options */ + //return OPERATOR_CANCELLED; + return OPERATOR_FINISHED; } else { EDBM_update_generic(em, true, true); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 581c3d25730..5c5352f1671 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3000,7 +3000,7 @@ static int vertex_group_vert_select_unlocked_poll(bContext *C) return 0; } - if (ob->actdef != -1) { + if (ob->actdef != 0) { bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef - 1); if (dg) { return !(dg->flag & DG_LOCK_WEIGHT); diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index edd61bfc5c3..eb09606e57e 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -83,7 +83,7 @@ void TEXTURE_OT_envmap_clear_all(struct wmOperatorType *ot); /* render_internal.c */ void RENDER_OT_render(struct wmOperatorType *ot); -void render_view3d(struct RenderEngine *engine, const struct bContext *C); +void render_view3d_update(struct RenderEngine *engine, const struct bContext *C); void render_view3d_draw(struct RenderEngine *engine, const struct bContext *C); /* render_opengl.c uses this */ diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 563f416ead0..fbb8ceae607 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -759,11 +759,13 @@ void RENDER_OT_render(wmOperatorType *ot) #define PR_UPDATE_VIEW 1 #define PR_UPDATE_RENDERSIZE 2 #define PR_UPDATE_MATERIAL 4 +#define PR_UPDATE_DATABASE 8 typedef struct RenderPreview { /* from wmJob */ void *owner; short *stop, *do_update; + wmJob *job; Scene *scene; ScrArea *sa; @@ -774,8 +776,6 @@ typedef struct RenderPreview { RenderEngine *engine; float viewmat[4][4]; - - int keep_data; } RenderPreview; static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect) @@ -876,7 +876,13 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda float clipsta, clipend, pixsize; bool orth, restore = 0; char name[32]; - + int update_flag; + + update_flag = rp->engine->job_update_flag; + rp->engine->job_update_flag = 0; + + //printf("ma %d res %d view %d db %d\n", update_flag & PR_UPDATE_MATERIAL, update_flag & PR_UPDATE_RENDERSIZE, update_flag & PR_UPDATE_VIEW, update_flag & PR_UPDATE_DATABASE); + G.is_break = FALSE; if (false == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth)) @@ -891,13 +897,6 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda sprintf(name, "View3dPreview %p", (void *)rp->ar); re = rp->engine->re = RE_GetRender(name); - if (rp->engine->re == NULL) { - - re = rp->engine->re = RE_NewRender(name); - - rp->keep_data = 0; - } - /* set this always, rp is different for each job */ RE_test_break_cb(re, rp, render_view3d_break); RE_display_draw_cb(re, rp, render_view3d_draw_update); @@ -905,7 +904,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda rstats = RE_GetStats(re); - if (rp->keep_data == 0 || rstats->convertdone == 0 || (rp->keep_data & PR_UPDATE_RENDERSIZE)) { + if ((update_flag & (PR_UPDATE_RENDERSIZE|PR_UPDATE_DATABASE)) || rstats->convertdone == 0) { /* no osa, blur, seq, layers, etc for preview render */ rdata = rp->scene->r; rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA); @@ -931,11 +930,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda RE_SetPixelSize(re, pixsize); - /* database free can crash on a empty Render... */ - if (rp->keep_data == 0 && rstats->convertdone) - RE_Database_Free(re); - - if (rstats->convertdone == 0) { + if ((update_flag & PR_UPDATE_DATABASE) || rstats->convertdone == 0) { unsigned int lay = rp->scene->lay; /* allow localview render for objects with lights in normal layers */ @@ -944,8 +939,20 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda else lay = rp->v3d->lay; RE_SetView(re, rp->viewmat); - + + /* copying blender data while main thread is locked, to avoid crashes */ + WM_job_main_thread_lock_acquire(rp->job); + RE_Database_Free(re); RE_Database_FromScene(re, rp->bmain, rp->scene, lay, 0); // 0= dont use camera view + WM_job_main_thread_lock_release(rp->job); + + /* do preprocessing like building raytree, shadows, volumes, SSS */ + RE_Database_Preprocess(re); + + /* conversion not completed, need to do it again */ + if (!rstats->convertdone) + rp->engine->job_update_flag |= PR_UPDATE_DATABASE; + // printf("dbase update\n"); } else { @@ -963,8 +970,6 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda /* always rotate back */ if (restore) RE_DataBase_IncrementalView(re, rp->viewmat, 1); - - rp->engine->flag &= ~RE_ENGINE_DO_UPDATE; } } @@ -975,21 +980,99 @@ static void render_view3d_free(void *customdata) MEM_freeN(rp); } -static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_data) +static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C) +{ + RegionView3D *rv3d = CTX_wm_region_view3d(C); + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + Render *re; + rctf viewplane; + rcti disprect; + float clipsta, clipend; + bool orth; + int job_update_flag = 0; + char name[32]; + + /* ensure render engine exists */ + re = engine->re; + + if (!re) { + sprintf(name, "View3dPreview %p", (void *)ar); + re = engine->re = RE_GetRender(name); + if (!re) + re = engine->re = RE_NewRender(name); + + engine->update_flag |= RE_ENGINE_UPDATE_DATABASE; + } + + /* check update_flag */ + if (engine->update_flag & RE_ENGINE_UPDATE_MA) + job_update_flag |= PR_UPDATE_MATERIAL; + + if (engine->update_flag & RE_ENGINE_UPDATE_OTHER) + job_update_flag |= PR_UPDATE_MATERIAL; + + if (engine->update_flag & RE_ENGINE_UPDATE_DATABASE) { + job_update_flag |= PR_UPDATE_DATABASE; + + /* load editmesh */ + if (scene->obedit) + ED_object_editmode_load(scene->obedit); + } + + engine->update_flag = 0; + + /* check if viewport changed */ + if (engine->last_winx != ar->winx || engine->last_winy != ar->winy) { + engine->last_winx = ar->winx; + engine->last_winy = ar->winy; + job_update_flag |= PR_UPDATE_RENDERSIZE; + } + + if (compare_m4m4(engine->last_viewmat, rv3d->viewmat, 0.00001f) == 0) { + copy_m4_m4(engine->last_viewmat, rv3d->viewmat); + job_update_flag |= PR_UPDATE_VIEW; + } + + render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth); + + if (BLI_rctf_compare(&viewplane, &engine->last_viewplane, 0.00001f) == 0) { + engine->last_viewplane = viewplane; + job_update_flag |= PR_UPDATE_VIEW; + } + + render_view3d_disprect(scene, ar, v3d, rv3d, &disprect); + if (BLI_rcti_compare(&disprect, &engine->last_disprect) == 0) { + engine->last_disprect = disprect; + job_update_flag |= PR_UPDATE_RENDERSIZE; + } + + /* any changes? go ahead and rerender */ + if (job_update_flag) { + engine->job_update_flag |= job_update_flag; + return true; + } + + return false; +} + +static void render_view3d_do(RenderEngine *engine, const bContext *C) { wmJob *wm_job; RenderPreview *rp; Scene *scene = CTX_data_scene(C); - if (CTX_wm_window(C) == NULL) { - engine->flag |= RE_ENGINE_DO_UPDATE; + if (CTX_wm_window(C) == NULL) + return; + if (!render_view3d_flag_changed(engine, C)) return; - } wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); rp = MEM_callocN(sizeof(RenderPreview), "render preview"); - + rp->job = wm_job; + /* customdata for preview thread */ rp->scene = scene; rp->engine = engine; @@ -998,7 +1081,6 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_d rp->v3d = rp->sa->spacedata.first; rp->rv3d = CTX_wm_region_view3d(C); rp->bmain = CTX_data_main(C); - rp->keep_data = keep_data; copy_m4_m4(rp->viewmat, rp->rv3d->viewmat); /* dont alloc in threads */ @@ -1013,80 +1095,33 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_d WM_jobs_start(CTX_wm_manager(C), wm_job); engine->flag &= ~RE_ENGINE_DO_UPDATE; - } /* callback for render engine , on changes */ -void render_view3d(RenderEngine *engine, const bContext *C) +void render_view3d_update(RenderEngine *engine, const bContext *C) { - render_view3d_do(engine, C, 0); -} + /* this shouldn't be needed and causes too many database rebuilds, but we + * aren't actually tracking updates for all relevent datablocks so this is + * a catch-all for updates */ + engine->update_flag |= RE_ENGINE_UPDATE_DATABASE; -static int render_view3d_changed(RenderEngine *engine, const bContext *C) -{ - ARegion *ar = CTX_wm_region(C); - Render *re; - int update = 0; - char name[32]; - - sprintf(name, "View3dPreview %p", (void *)ar); - re = RE_GetRender(name); - - if (re) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - rctf viewplane, viewplane1; - rcti disprect, disprect1; - float mat[4][4]; - float clipsta, clipend; - bool orth; - - if (engine->update_flag & RE_ENGINE_UPDATE_MA) - update |= PR_UPDATE_MATERIAL; - - if (engine->update_flag & RE_ENGINE_UPDATE_OTHER) - update |= PR_UPDATE_MATERIAL; - - engine->update_flag = 0; - - if (engine->resolution_x != ar->winx || engine->resolution_y != ar->winy) - update |= PR_UPDATE_RENDERSIZE; - - RE_GetView(re, mat); - if (compare_m4m4(mat, rv3d->viewmat, 0.00001f) == 0) { - update |= PR_UPDATE_VIEW; - } - - render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth); - RE_GetViewPlane(re, &viewplane1, &disprect1); - - if (BLI_rctf_compare(&viewplane, &viewplane1, 0.00001f) == 0) - update |= PR_UPDATE_VIEW; - - render_view3d_disprect(scene, ar, v3d, rv3d, &disprect); - if (BLI_rcti_compare(&disprect, &disprect1) == 0) - update |= PR_UPDATE_RENDERSIZE; - - if (update) - engine->flag |= RE_ENGINE_DO_UPDATE; - //if (update) - // printf("changed ma %d res %d view %d\n", update & PR_UPDATE_MATERIAL, update & PR_UPDATE_RENDERSIZE, update & PR_UPDATE_VIEW); - } - - return update; + render_view3d_do(engine, C); } void render_view3d_draw(RenderEngine *engine, const bContext *C) { Render *re = engine->re; RenderResult rres; - int keep_data = render_view3d_changed(engine, C); + char name[32]; - if (engine->flag & RE_ENGINE_DO_UPDATE) - render_view3d_do(engine, C, keep_data); - - if (re == NULL) return; + render_view3d_do(engine, C); + + if (re == NULL) { + sprintf(name, "View3dPreview %p", (void *)CTX_wm_region(C)); + re = RE_GetRender(name); + + if (re == NULL) return; + } RE_AcquireResultImage(re, &rres); @@ -1136,3 +1171,52 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) RE_ReleaseResultImage(re); } + +void ED_viewport_render_kill_jobs(const bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + Main *bmain = CTX_data_main(C); + bScreen *sc; + ScrArea *sa; + ARegion *ar; + + if (!wm) + return; + + /* kill all actively running jobs */ + WM_jobs_kill(wm, NULL, render_view3d_startjob); + + /* loop over 3D view render engines */ + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->spacetype != SPACE_VIEW3D) + continue; + + for (ar = sa->regionbase.first; ar; ar = ar->next) { + RegionView3D *rv3d; + + if (ar->regiontype != RGN_TYPE_WINDOW) + continue; + + rv3d = ar->regiondata; + + if (rv3d->render_engine) { + /* free render database now before we change data, because + * RE_Database_Free will also loop over blender data */ + char name[32]; + Render *re; + + sprintf(name, "View3dPreview %p", (void *)ar); + re = RE_GetRender(name); + + if (re) + RE_Database_Free(re); + + /* tag render engine to update entire database */ + rv3d->render_engine->update_flag |= RE_ENGINE_UPDATE_DATABASE; + } + } + } + } +} + diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 436aef943e4..5f74bf6576a 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -539,7 +539,7 @@ void ED_render_internal_init(void) { RenderEngineType *ret = RE_engines_find("BLENDER_RENDER"); - ret->view_update = render_view3d; + ret->view_update = render_view3d_update; ret->view_draw = render_view3d_draw; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 4ddacc3254e..6c0d5ccd844 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -908,11 +908,19 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar) /* overlapping regions only in the following restricted cases */ static int region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar) { - if (U.uiflag2 & USER_REGION_OVERLAP) - if (WM_is_draw_triple(win)) - if (ELEM4(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP)) + if (U.uiflag2 & USER_REGION_OVERLAP) { + if (WM_is_draw_triple(win)) { + if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) { if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) return 1; + } + else if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) { + if (ELEM4(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW)) + return 1; + } + } + } + return 0; } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 553a5cbe9ac..017232d1856 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -245,7 +245,8 @@ typedef struct ProjPaintState { float normal_angle_inner; float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */ - short is_ortho; + bool do_face_sel; /* quick access to (me->editflag & ME_EDIT_PAINT_FACE_SEL) */ + bool is_ortho; bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */ bool is_texbrush; /* only to avoid running */ bool is_maskbrush; /* mask brush is applied before masking */ @@ -2809,22 +2810,28 @@ static void project_paint_begin(ProjPaintState *ps) Image *tpage_last = NULL, *tpage; /* Face vars */ + MPoly *mpoly_orig; MFace *mf; MTFace *tf; int a, i; /* generic looping vars */ int image_index = -1, face_index; + int *mpoly_origindex; MVert *mv; MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */ const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); + bool reset_threads = false; + /* ---- end defines ---- */ if (ps->source == PROJ_SRC_VIEW) ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */ + ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0); + /* paint onto the derived mesh */ /* Workaround for subsurf selection, try the display mesh first */ @@ -2833,12 +2840,17 @@ static void project_paint_begin(ProjPaintState *ps) ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); ps->dm_release = TRUE; } - else if (ps->ob->derivedFinal && CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE)) { + else if (ps->ob->derivedFinal && + CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE) && + (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX))) + { ps->dm = ps->ob->derivedFinal; ps->dm_release = FALSE; } else { - ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); + ps->dm = mesh_get_derived_final( + ps->scene, ps->ob, + ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0)); ps->dm_release = TRUE; } @@ -2858,6 +2870,15 @@ static void project_paint_begin(ProjPaintState *ps) ps->dm_totvert = ps->dm->getNumVerts(ps->dm); ps->dm_totface = ps->dm->getNumTessFaces(ps->dm); + if (ps->do_face_sel) { + mpoly_orig = ((Mesh *)ps->ob->data)->mpoly; + mpoly_origindex = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX); + } + else { + mpoly_orig = NULL; + mpoly_origindex = NULL; + } + /* use clone mtface? */ @@ -3064,6 +3085,10 @@ static void project_paint_begin(ProjPaintState *ps) /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */ + if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) { + reset_threads = true; + } + /* really high values could cause problems since it has to allocate a few * (ps->buckets_x*ps->buckets_y) sized arrays */ CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); @@ -3089,6 +3114,11 @@ static void project_paint_begin(ProjPaintState *ps) ps->thread_tot = BKE_scene_num_threads(ps->scene); + /* workaround for #35057, disable threading if diameter is less than is possible for + * optimum bucket number generation */ + if (reset_threads) + ps->thread_tot = 1; + for (a = 0; a < ps->thread_tot; a++) { ps->arena_mt[a] = BLI_memarena_new(1 << 16, "project paint arena"); } @@ -3118,8 +3148,8 @@ static void project_paint_begin(ProjPaintState *ps) } } - for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) { + bool is_face_sel; #ifndef PROJ_DEBUG_NOSEAMBLEED /* add face user if we have bleed enabled, set the UV seam flags later */ @@ -3134,10 +3164,21 @@ static void project_paint_begin(ProjPaintState *ps) } #endif - tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); - - if (tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) == 0 || mf->flag & ME_FACE_SEL)) { + if (ps->do_face_sel) { + int orig_index; + if (mpoly_origindex && ((orig_index = mpoly_origindex[face_index])) != ORIGINDEX_NONE) { + MPoly *mp = mpoly_orig + orig_index; + is_face_sel = ((mp->flag & ME_FACE_SEL) != 0); + } + else { + is_face_sel = ((mf->flag & ME_FACE_SEL) != 0); + } + } + else { + is_face_sel = true; + } + if (is_face_sel && (tpage = project_paint_face_image(ps, ps->dm_mtface, face_index))) { float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL; v1coSS = ps->screenCoords[mf->v1]; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index e10cba43d71..f8166456a2c 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -577,9 +577,10 @@ void snode_set_context(const bContext *C) if (!treetype || (treetype->poll && !treetype->poll(C, treetype))) { - /* invalid tree type, disable */ - snode->tree_idname[0] = '\0'; - ED_node_tree_start(snode, NULL, NULL, NULL); + /* invalid tree type, skip + * NB: not resetting the node path here, invalid bNodeTreeType + * may still be registered at a later point. + */ return; } diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 07fa6997e99..8d6363d3bbe 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "BKE_node.h" @@ -83,6 +84,8 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) BLI_strncpy(path->node_name, id->name + 2, sizeof(path->node_name)); BLI_addtail(&snode->treepath, path); + + id_us_ensure_real(&ntree->id); } /* update current tree */ @@ -116,6 +119,8 @@ void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) BLI_addtail(&snode->treepath, path); + id_us_ensure_real(&ntree->id); + /* update current tree */ snode->edittree = ntree; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index eeacaab464c..cef4e1880ab 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -3273,7 +3273,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D Object *ob = base->object; Mesh *me = ob->data; Material *ma = give_current_material(ob, 1); - const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO)); + const short hasHaloMat = (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene)); eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; int /* totvert,*/ totedge, totface; DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 7f2e5b4b81c..52f87c19dc8 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -59,6 +59,7 @@ #include "ED_mball.h" #include "ED_mesh.h" #include "ED_object.h" +#include "ED_render.h" #include "ED_screen.h" #include "ED_sculpt.h" #include "ED_util.h" @@ -140,9 +141,12 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) SpaceImage *sima = (SpaceImage *)sa->spacedata.first; if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) - if (U.uiflag & USER_GLOBALUNDO) + if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { + if (U.uiflag & USER_GLOBALUNDO) { + ED_viewport_render_kill_jobs(C); BKE_undo_name(C, undoname); + } + } WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; @@ -192,6 +196,8 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) /* for example, texface stores image pointers */ undo_editmode_clear(); + ED_viewport_render_kill_jobs(C); + if (undoname) BKE_undo_name(C, undoname); else @@ -363,6 +369,8 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) { int retval; + ED_viewport_render_kill_jobs(C); + if (G.debug & G_DEBUG) printf("redo_cb: operator redo %s\n", op->type->name); ED_undo_pop_op(C, op); @@ -529,6 +537,7 @@ static int undo_history_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } else { + ED_viewport_render_kill_jobs(C); BKE_undo_number(C, item); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); } diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 437229d63a8..38cbd95b61f 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -211,6 +211,10 @@ typedef struct Curve { void *lastsel; /* font part */ + /* WARNING: cu->len is... + * - strlen(cu->str) object-mode (bytes). + * - BLI_strlen_utf8(cu->str) in edit-mode. + * This should be cleaned up and some point, see 'write_curves' - campbell */ short len, lines, pos, spacemode; float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight; float xof, yof; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index f67561954be..5499386dcf1 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -6385,6 +6385,15 @@ bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, bool i return equals; } + case PROP_POINTER: + { + if (!STREQ(RNA_property_identifier(prop), "rna_type")) { + PointerRNA propptr_a = RNA_property_pointer_get(a, prop); + PointerRNA propptr_b = RNA_property_pointer_get(b, prop); + return RNA_struct_equals(&propptr_a, &propptr_b, is_strict); + } + } + default: break; } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 85bb8125a3a..fc4b78b5c05 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -1531,7 +1531,7 @@ void IDP_spit(IDProperty *prop) ret_str = PyObject_Repr(ret_dict); Py_DECREF(ret_dict); - printf("IDProperty: %s\n", _PyUnicode_AsString(ret_str)); + printf("IDProperty(%p): %s\n", prop, _PyUnicode_AsString(ret_str)); Py_DECREF(ret_str); diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index b6c3668512b..786c67f5305 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -70,6 +70,7 @@ struct Scene; /* RenderEngine.update_flag, used by internal now */ #define RE_ENGINE_UPDATE_MA 1 #define RE_ENGINE_UPDATE_OTHER 2 +#define RE_ENGINE_UPDATE_DATABASE 4 extern ListBase R_engines; @@ -97,7 +98,7 @@ typedef struct RenderEngine { RenderEngineType *type; void *py_instance; - int flag, update_flag; + int flag; struct Object *camera_override; int tile_x; @@ -110,6 +111,15 @@ typedef struct RenderEngine { int resolution_x, resolution_y; struct ReportList *reports; + + /* for blender internal only */ + int update_flag; + int job_update_flag; + + rctf last_viewplane; + rcti last_disprect; + float last_viewmat[4][4]; + int last_winx, last_winy; } RenderEngine; RenderEngine *RE_engine_create(RenderEngineType *type); diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index da53bc5a819..e154fd42119 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -207,6 +207,7 @@ void RE_GetViewPlane(struct Render *re, rctf *viewplane, rcti *disprect); /* make or free the dbase */ void RE_Database_FromScene(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, int use_camera_view); +void RE_Database_Preprocess(struct Render *re); void RE_Database_Free(struct Render *re); /* project dbase again, when viewplane/perspective changed */ diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 6e70b4bcfc9..ce71ab188a9 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4863,7 +4863,11 @@ static void init_render_object(Render *re, Object *ob, Object *par, DupliObject void RE_Database_Free(Render *re) { LampRen *lar; - + + /* will crash if we try to free empty database */ + if (!re->i.convertdone) + return; + /* statistics for debugging render memory usage */ if ((G.debug & G_DEBUG) && (G.is_rendering)) { if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) { @@ -5321,14 +5325,10 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l database_init_objects(re, lay, 0, 0, 0, 0); if (!re->test_break(re->tbh)) { - int tothalo; - set_material_lightgroups(re); for (sce= re->scene; sce; sce= sce->set) set_renderlayer_lightgroups(re, sce); - slurph_opt= 1; - /* for now some clumsy copying still */ re->i.totvert= re->totvert; re->i.totface= re->totvlak; @@ -5336,7 +5336,16 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l re->i.tothalo= re->tothalo; re->i.totlamp= re->totlamp; re->stats_draw(re->sdh, &re->i); - + } + + slurph_opt= 1; +} + +void RE_Database_Preprocess(Render *re) +{ + if (!re->test_break(re->tbh)) { + int tothalo; + /* don't sort stars */ tothalo= re->tothalo; if (!re->test_break(re->tbh)) { @@ -5392,11 +5401,12 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l if (!re->test_break(re->tbh)) if (re->r.mode & R_RAYTRACE) volume_precache(re); - } - if (re->test_break(re->tbh)) + if (re->test_break(re->tbh)) { + re->i.convertdone = TRUE; RE_Database_Free(re); + } else re->i.convertdone = TRUE; @@ -5866,8 +5876,10 @@ void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned RE_Database_Free(re); re->strandsurface= strandsurface; - if (!re->test_break(re->tbh)) + if (!re->test_break(re->tbh)) { RE_Database_FromScene(re, bmain, sce, lay, 1); + RE_Database_Preprocess(re); + } if (!re->test_break(re->tbh)) { int vectorlay= get_vector_renderlayers(re->scene); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index dfdfe973241..848e94c8d4b 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1142,10 +1142,13 @@ static void do_render_3d(Render *re) re->draw_lock(re->dlh, 1); /* make render verts/faces/halos/lamps */ - if (render_scene_needs_vector(re)) + if (render_scene_needs_vector(re)) { RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay); - else + } + else { RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); + RE_Database_Preprocess(re); + } /* clear UI drawing locks */ if (re->draw_lock) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index afd380a77f7..d293ca07c5a 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -404,6 +404,9 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, int job_type); int WM_jobs_has_running(struct wmWindowManager *wm); +void WM_job_main_thread_lock_acquire(struct wmJob *job); +void WM_job_main_thread_lock_release(struct wmJob *job); + /* clipboard */ char *WM_clipboard_text_get(int selection); void WM_clipboard_text_set(char *buf, int selection); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 03af5e9e8a6..c6e067dc2f9 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -128,8 +128,43 @@ struct wmJob { ListBase threads; double start_time; + + /* ticket mutex for main thread locking while some job accesses + * data that the main thread might modify at the same time */ + TicketMutex *main_thread_mutex; + bool main_thread_mutex_ending; }; +/* Main thread locking */ + +void WM_job_main_thread_lock_acquire(wmJob *wm_job) +{ + BLI_ticket_mutex_lock(wm_job->main_thread_mutex); + + /* if BLI_end_threads is being called to stop the job before it's finished, + * we no longer need to lock to get access to the main thread as it's + * waiting and can't respond */ + if (wm_job->main_thread_mutex_ending) + BLI_ticket_mutex_unlock(wm_job->main_thread_mutex); +} + +void WM_job_main_thread_lock_release(wmJob *wm_job) +{ + if (!wm_job->main_thread_mutex_ending) + BLI_ticket_mutex_unlock(wm_job->main_thread_mutex); +} + +static void wm_job_main_thread_yield(wmJob *wm_job, bool ending) +{ + if (ending) + wm_job->main_thread_mutex_ending = true; + + /* unlock and lock the ticket mutex. because it's a fair mutex any job that + * is waiting to acquire the lock will get it first, before we can lock */ + BLI_ticket_mutex_unlock(wm_job->main_thread_mutex); + BLI_ticket_mutex_lock(wm_job->main_thread_mutex); +} + /* finds: * if type, compare for it, otherwise any matching job */ @@ -162,13 +197,16 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char * if (wm_job == NULL) { wm_job = MEM_callocN(sizeof(wmJob), "new job"); - + BLI_addtail(&wm->jobs, wm_job); wm_job->win = win; wm_job->owner = owner; wm_job->flag = flag; wm_job->job_type = job_type; BLI_strncpy(wm_job->name, name, sizeof(wm_job->name)); + + wm_job->main_thread_mutex = BLI_ticket_mutex_alloc(); + BLI_ticket_mutex_lock(wm_job->main_thread_mutex); } /* else: a running job, be careful */ @@ -369,12 +407,21 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) } } +static void wm_job_free(wmWindowManager *wm, wmJob *wm_job) +{ + BLI_remlink(&wm->jobs, wm_job); + BLI_ticket_mutex_unlock(wm_job->main_thread_mutex); + BLI_ticket_mutex_free(wm_job->main_thread_mutex); + MEM_freeN(wm_job); +} + /* stop job, end thread, free data completely */ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job) { if (wm_job->running) { /* signal job to end */ wm_job->stop = TRUE; + wm_job_main_thread_yield(wm_job, true); BLI_end_threads(&wm_job->threads); if (wm_job->endjob) @@ -389,9 +436,7 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job) wm_job->run_free(wm_job->run_customdata); /* remove wm_job */ - BLI_remlink(&wm->jobs, wm_job); - MEM_freeN(wm_job); - + wm_job_free(wm, wm_job); } /* wait until every job ended */ @@ -483,7 +528,6 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) float total_progress = 0.f; float jobs_progress = 0; - for (wm_job = wm->jobs.first; wm_job; wm_job = wm_jobnext) { wm_jobnext = wm_job->next; @@ -491,6 +535,9 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) /* running threads */ if (wm_job->threads.first) { + + /* let threads get temporary lock over main thread if needed */ + wm_job_main_thread_yield(wm_job, false); /* always call note and update when ready */ if (wm_job->do_update || wm_job->ready) { @@ -522,7 +569,9 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) } wm_job->running = FALSE; + wm_job_main_thread_yield(wm_job, true); BLI_end_threads(&wm_job->threads); + wm_job->main_thread_mutex_ending = false; if (wm_job->endnote) WM_event_add_notifier(C, wm_job->endnote, NULL); @@ -539,8 +588,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) wm_job->wt = NULL; /* remove wm_job */ - BLI_remlink(&wm->jobs, wm_job); - MEM_freeN(wm_job); + wm_job_free(wm, wm_job); } } else if (wm_job->flag & WM_JOB_PROGRESS) {