From 3f5b2e268295083d9dddb9628b7b7aed39f3350a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 18 Feb 2017 17:25:12 +0100 Subject: [PATCH 01/18] Fix T50564: 3D view panning with scroll wheel inconsistent with dragging. --- .../editors/space_view3d/view3d_edit.c | 73 +++++++------------ 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 2b53eb71d99..5e13b3f27fc 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -90,19 +90,6 @@ bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d) return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); } -static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op) -{ - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (ED_view3d_offset_lock_check(v3d, rv3d)) { - BKE_report(op->reports, RPT_WARNING, "View offset is locked"); - return true; - } - else { - return false; - } -} - /* ********************** view3d_edit: view manipulations ********************* */ /** @@ -2596,6 +2583,19 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) /* ************************ viewdolly ******************************** */ +static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (ED_view3d_offset_lock_check(v3d, rv3d)) { + BKE_report(op->reports, RPT_WARNING, "Cannot dolly when the view offset is locked"); + return true; + } + else { + return false; + } +} + static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac) { RegionView3D *rv3d = ar->regiondata; @@ -2746,7 +2746,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; - if (view3d_operator_offset_lock_check(C, op)) + if (viewdolly_offset_lock_check(C, op)) return OPERATOR_CANCELLED; /* makes op->customdata */ @@ -4364,41 +4364,24 @@ static EnumPropertyItem prop_view_pan_items[] = { {0, NULL, 0, NULL, NULL} }; -static int viewpan_exec(bContext *C, wmOperator *op) +static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - float vec[3]; - const float co_zero[3] = {0.0f}; - float mval_f[2] = {0.0f, 0.0f}; - float zfac; - int pandir; + int x = 0, y = 0; + int pandir = RNA_enum_get(op->ptr, "type"); - if (view3d_operator_offset_lock_check(C, op)) - return OPERATOR_CANCELLED; + if (pandir == V3D_VIEW_PANRIGHT) { x = -32; } + else if (pandir == V3D_VIEW_PANLEFT) { x = 32; } + else if (pandir == V3D_VIEW_PANUP) { y = -25; } + else if (pandir == V3D_VIEW_PANDOWN) { y = 25; } - pandir = RNA_enum_get(op->ptr, "type"); + viewops_data_alloc(C, op); + viewops_data_create(C, op, event); + ViewOpsData *vod = op->customdata; - ED_view3d_camera_lock_init(v3d, rv3d); + viewmove_apply(vod, vod->oldx + x, vod->oldy + y); - zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); - if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; } - else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; } - else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; } - else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; } - ED_view3d_win_to_delta(ar, mval_f, vec, zfac); - add_v3_v3(rv3d->ofs, vec); - - if (rv3d->viewlock & RV3D_BOXVIEW) - view3d_boxview_sync(sa, ar); - - ED_view3d_depth_tag_update(rv3d); - - ED_view3d_camera_lock_sync(v3d, rv3d); - - ED_region_tag_redraw(ar); + ED_view3d_depth_tag_update(vod->rv3d); + viewops_data_free(C, op); return OPERATOR_FINISHED; } @@ -4411,7 +4394,7 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot) ot->idname = "VIEW3D_OT_view_pan"; /* api callbacks */ - ot->exec = viewpan_exec; + ot->invoke = viewpan_invoke; ot->poll = ED_operator_region_view3d_active; /* flags */ From 9992e6a1693a7fe7512759811d79287c18a699a9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 18 Feb 2017 23:52:31 +0100 Subject: [PATCH 02/18] Fix a few compiler warnings with macOS / clang. --- intern/libmv/libmv/numeric/numeric.h | 2 +- source/blender/blenlib/intern/array_store.c | 49 +++++++++---------- .../blender/bmesh/operators/bmo_primitive.c | 2 +- source/blender/collada/SkinInfo.cpp | 1 - source/blender/imbuf/intern/imbuf.h | 2 - .../blender/modifiers/intern/MOD_displace.c | 2 +- 6 files changed, 26 insertions(+), 32 deletions(-) diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index a42dab8c7a2..1a23d653676 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -36,7 +36,7 @@ #if !defined(__MINGW64__) # if defined(_WIN32) || defined(__APPLE__) || \ defined(__FreeBSD__) || defined(__NetBSD__) -static void sincos(double x, double *sinx, double *cosx) { +inline void sincos(double x, double *sinx, double *cosx) { *sinx = sin(x); *cosx = cos(x); } diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c index 21ddddad32e..874130a315c 100644 --- a/source/blender/blenlib/intern/array_store.c +++ b/source/blender/blenlib/intern/array_store.c @@ -217,9 +217,6 @@ /** \name Internal Structs * \{ */ -typedef unsigned int uint; -typedef unsigned char ubyte; - typedef uint64_t hash_key; @@ -291,7 +288,7 @@ typedef struct BChunkList { /* a chunk of an array */ typedef struct BChunk { - const ubyte *data; + const uchar *data; size_t data_len; /** number of #BChunkList using this. */ int users; @@ -332,7 +329,7 @@ static size_t bchunk_list_size(const BChunkList *chunk_list); * \{ */ static BChunk *bchunk_new( - BArrayMemory *bs_mem, const ubyte *data, const size_t data_len) + BArrayMemory *bs_mem, const uchar *data, const size_t data_len) { BChunk *chunk = BLI_mempool_alloc(bs_mem->chunk); chunk->data = data; @@ -345,9 +342,9 @@ static BChunk *bchunk_new( } static BChunk *bchunk_new_copydata( - BArrayMemory *bs_mem, const ubyte *data, const size_t data_len) + BArrayMemory *bs_mem, const uchar *data, const size_t data_len) { - ubyte *data_copy = MEM_mallocN(data_len, __func__); + uchar *data_copy = MEM_mallocN(data_len, __func__); memcpy(data_copy, data, data_len); return bchunk_new(bs_mem, data_copy, data_len); } @@ -367,7 +364,7 @@ static void bchunk_decref( static bool bchunk_data_compare( const BChunk *chunk, - const ubyte *data_base, const size_t data_base_len, + const uchar *data_base, const size_t data_base_len, const size_t offset) { if (offset + (size_t)chunk->data_len <= data_base_len) { @@ -426,7 +423,7 @@ static void bchunk_list_decref( #ifdef USE_VALIDATE_LIST_DATA_PARTIAL static size_t bchunk_list_data_check( - const BChunkList *chunk_list, const ubyte *data) + const BChunkList *chunk_list, const uchar *data) { size_t total_size = 0; for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) { @@ -466,7 +463,7 @@ static void bchunk_list_ensure_min_size_last( chunk_list->chunk_refs.last = cref->prev; chunk_list->chunk_refs_len -= 1; - ubyte *data_merge = MEM_mallocN(data_merge_len, __func__); + uchar *data_merge = MEM_mallocN(data_merge_len, __func__); memcpy(data_merge, chunk_prev->data, chunk_prev->data_len); memcpy(&data_merge[chunk_prev->data_len], chunk_curr->data, chunk_curr->data_len); @@ -487,8 +484,8 @@ static void bchunk_list_ensure_min_size_last( /* merge and split */ const size_t data_prev_len = split; const size_t data_curr_len = data_merge_len - split; - ubyte *data_prev = MEM_mallocN(data_prev_len, __func__); - ubyte *data_curr = MEM_mallocN(data_curr_len, __func__); + uchar *data_prev = MEM_mallocN(data_prev_len, __func__); + uchar *data_curr = MEM_mallocN(data_curr_len, __func__); if (data_prev_len <= chunk_prev->data_len) { const size_t data_curr_shrink_len = chunk_prev->data_len - data_prev_len; @@ -597,7 +594,7 @@ static void bchunk_list_append_only( static void bchunk_list_append_data( const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, - const ubyte *data, const size_t data_len) + const uchar *data, const size_t data_len) { BLI_assert(data_len != 0); @@ -613,13 +610,13 @@ static void bchunk_list_append_data( const size_t data_merge_len = chunk_prev->data_len + data_len; /* realloc for single user */ if (cref->link->users == 1) { - ubyte *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len); + uchar *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len); memcpy(&data_merge[chunk_prev->data_len], data, data_len); cref->link->data = data_merge; cref->link->data_len = data_merge_len; } else { - ubyte *data_merge = MEM_mallocN(data_merge_len, __func__); + uchar *data_merge = MEM_mallocN(data_merge_len, __func__); memcpy(data_merge, chunk_prev->data, chunk_prev->data_len); memcpy(&data_merge[chunk_prev->data_len], data, data_len); cref->link = bchunk_new(bs_mem, data_merge, data_merge_len); @@ -654,7 +651,7 @@ static void bchunk_list_append_data( static void bchunk_list_append_data_n( const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, - const ubyte *data, size_t data_len) + const uchar *data, size_t data_len) { size_t data_trim_len, data_last_chunk_len; bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len); @@ -714,7 +711,7 @@ static void bchunk_list_append( static void bchunk_list_fill_from_array( const BArrayInfo *info, BArrayMemory *bs_mem, BChunkList *chunk_list, - const ubyte *data, + const uchar *data, const size_t data_len) { BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs)); @@ -765,13 +762,13 @@ static void bchunk_list_fill_from_array( #define HASH_INIT (5381) -BLI_INLINE uint hash_data_single(const ubyte p) +BLI_INLINE uint hash_data_single(const uchar p) { return (HASH_INIT << 5) + HASH_INIT + (unsigned int)p; } /* hash bytes, from BLI_ghashutil_strhash_n */ -static uint hash_data(const ubyte *key, size_t n) +static uint hash_data(const uchar *key, size_t n) { const signed char *p; unsigned int h = HASH_INIT; @@ -788,7 +785,7 @@ static uint hash_data(const ubyte *key, size_t n) #ifdef USE_HASH_TABLE_ACCUMULATE static void hash_array_from_data( - const BArrayInfo *info, const ubyte *data_slice, const size_t data_slice_len, + const BArrayInfo *info, const uchar *data_slice, const size_t data_slice_len, hash_key *hash_array) { if (info->chunk_stride != 1) { @@ -929,7 +926,7 @@ static hash_key key_from_chunk_ref( static const BChunkRef *table_lookup( const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start, - const ubyte *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array) + const uchar *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array) { size_t size_left = data_len - offset; hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)]; @@ -985,7 +982,7 @@ static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref static const BChunkRef *table_lookup( const BArrayInfo *info, BTableRef **table, const size_t table_len, const uint UNUSED(i_table_start), - const ubyte *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array)) + const uchar *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array)) { const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; /* TODO, cache */ @@ -1025,7 +1022,7 @@ static const BChunkRef *table_lookup( */ static BChunkList *bchunk_list_from_data_merge( const BArrayInfo *info, BArrayMemory *bs_mem, - const ubyte *data, const size_t data_len_original, + const uchar *data, const size_t data_len_original, const BChunkList *chunk_list_reference) { ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size); @@ -1579,7 +1576,7 @@ BArrayState *BLI_array_store_state_add( if (state_reference) { chunk_list = bchunk_list_from_data_merge( &bs->info, &bs->memory, - (const ubyte *)data, data_len, + (const uchar *)data, data_len, /* re-use reference chunks */ state_reference->chunk_list); } @@ -1588,7 +1585,7 @@ BArrayState *BLI_array_store_state_add( bchunk_list_fill_from_array( &bs->info, &bs->memory, chunk_list, - (const ubyte *)data, data_len); + (const uchar *)data, data_len); } chunk_list->users += 1; @@ -1655,7 +1652,7 @@ void BLI_array_store_state_data_get( BLI_assert(data_test_len == state->chunk_list->total_size); #endif - ubyte *data_step = (ubyte *)data; + uchar *data_step = (uchar *)data; for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) { BLI_assert(cref->link->users > 0); memcpy(data_step, cref->link->data, cref->link->data_len); diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 8408169d85e..723e0b168e0 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1122,7 +1122,7 @@ static void bm_mesh_calc_uvs_sphere_face(BMFace *f, const int cd_loop_uv_offset) } /* Shift borderline coordinates to the left. */ - if (fabsf(theta - M_PI) < 0.0001f) { + if (fabsf(theta - (float)M_PI) < 0.0001f) { theta = -M_PI; } diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index 7242a24523c..71875d6274a 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -230,7 +230,6 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::mapobject = ob_arm; - struct bArmature *armature = (bArmature *)ob_arm->data; #if 1 bc_set_parent(ob, ob_arm, C); diff --git a/source/blender/imbuf/intern/imbuf.h b/source/blender/imbuf/intern/imbuf.h index 897a149a45c..90dad70fa61 100644 --- a/source/blender/imbuf/intern/imbuf.h +++ b/source/blender/imbuf/intern/imbuf.h @@ -67,8 +67,6 @@ # define BIG_LONG SWAP_LONG #endif -typedef unsigned char uchar; - #define IMB_DPI_DEFAULT 72.0f #endif /* __IMBUF_H__ */ diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index f6acbef96e9..18f60bab490 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -325,7 +325,7 @@ static void displaceModifier_do( float (*tex_co)[3]; float weight = 1.0f; /* init value unused but some compilers may complain */ float (*vert_clnors)[3] = NULL; - float local_mat[4][4] = {0}; + float local_mat[4][4] = {{0}}; const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL; if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return; From 333dc8d60ff4589fe73a7d0f63c3f7589d6b345a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 20 Feb 2017 11:02:19 +0100 Subject: [PATCH 03/18] Fix T50719: Memory usage won't reset to zero while re-rendering on two video cards Was only visible with Persistent Images option ON. --- intern/cycles/device/device_multi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 31b800640d3..61d78ee65de 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -162,6 +162,7 @@ public: void mem_free(device_memory& mem) { device_ptr tmp = mem.device_pointer; + stats.mem_free(mem.device_size); foreach(SubDevice& sub, devices) { mem.device_pointer = sub.ptr_map[tmp]; @@ -170,7 +171,6 @@ public: } mem.device_pointer = 0; - stats.mem_free(mem.device_size); } void const_copy_to(const char *name, void *host, size_t size) @@ -202,6 +202,7 @@ public: void tex_free(device_memory& mem) { device_ptr tmp = mem.device_pointer; + stats.mem_free(mem.device_size); foreach(SubDevice& sub, devices) { mem.device_pointer = sub.ptr_map[tmp]; @@ -210,7 +211,6 @@ public: } mem.device_pointer = 0; - stats.mem_free(mem.device_size); } void pixels_alloc(device_memory& mem) From 75ce4ebc1221445028b74e9ef2504663e0c99bcf Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 20 Feb 2017 11:47:43 +0100 Subject: [PATCH 04/18] Mesh faces split: Add missing vertex normal copy --- source/blender/blenkernel/intern/mesh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 24a01b17e53..5a3f7fabcb0 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2269,6 +2269,7 @@ static void split_faces_split_verts(Mesh *mesh, if ((vert_flags[ml->v] & SPLIT_VERT_REUSED) == 0) { /* Ignore first split on vertex, re-use it instead. */ vert_flags[ml->v] |= SPLIT_VERT_REUSED; + normal_float_to_short_v3(mvert[ml->v].no, lnors[poly_loop]); continue; } /* Create new vertex. */ From 696836af1dbda1ed104167f9eb535d4603d23f49 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 20 Feb 2017 11:56:02 +0100 Subject: [PATCH 05/18] Fix T50718: Regression: Split Normals Render Problem with Cycles The issue seems to be caused by vertex normal being re-calculated to something else than loop normal, which also caused wrong loop normals after re-calculation. For now issue is solved by preserving CD_NORMAL for loops after split_faces() is finished, so render engine can access original proper value. --- intern/cycles/blender/blender_util.h | 1 - source/blender/blenkernel/intern/mesh.c | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 4411181dbcc..8120de96362 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -80,7 +80,6 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, } else { me.split_faces(); - me.calc_normals_split(); } } if(subdivision_type == Mesh::SUBDIVISION_NONE) { diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 5a3f7fabcb0..73fcd7615f7 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2334,6 +2334,9 @@ static void split_faces_split_edges(Mesh *mesh, /* Split faces based on the edge angle. * Matches behavior of face splitting in render engines. + * + * NOTE: Will leave CD_NORMAL loop data layer which is + * used by render engines to set shading up. */ void BKE_mesh_split_faces(Mesh *mesh) { @@ -2377,10 +2380,6 @@ void BKE_mesh_split_faces(Mesh *mesh) /* Perform actual split of vertices and adjacent edges. */ split_faces_split_verts(mesh, num_new_verts, vert_flags); split_faces_split_edges(mesh, num_new_edges, edge_flags); - /* CD_NORMAL is expected to be temporary only, and it's invalid at - * this point anyway. - */ - CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); MEM_freeN(vert_flags); MEM_freeN(edge_flags); #ifdef VALIDATE_MESH From 34a502c16a5bf258d67e0371fc5fd9015d28dfa1 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Mon, 20 Feb 2017 20:19:07 -0500 Subject: [PATCH 06/18] Cleanup: use proper link to the api --- release/scripts/startup/bl_ui/space_userpref.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 075a6f870fa..3033dbc5c6f 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1243,7 +1243,7 @@ class USERPREF_MT_addons_online_resources(Menu): "wm.url_open", text="API Concepts", icon='URL', ).url = bpy.types.WM_OT_doc_view._prefix + "/info_quickstart.html" layout.operator("wm.url_open", text="Add-on Tutorial", icon='URL', - ).url = "http://www.blender.org/api/blender_python_api_current/info_tutorial_addon.html" + ).url = bpy.types.WM_OT_doc_view._prefix + "/info_tutorial_addon.html" class USERPREF_PT_addons(Panel): From 4e9b17da4ca7b0b77b796080217af495b9bd180b Mon Sep 17 00:00:00 2001 From: Mai Lavelle Date: Tue, 21 Feb 2017 07:24:33 -0500 Subject: [PATCH 07/18] Cycles: Speedup by avoiding extra calculations in noise texture when unneeded Noise texture is now faster when the color socket is unused. Potential for speedup spotted by @nutel. Some performance results: Render Time Before After Difference Gooseberry benchmark 47:51.34 45:55.57 -4% Koro 12:24.92 12:18.46 -0.8% Simple cube (Color socket) 48.53 48.72 +0.3% Simple cube (Fac socket) 48.74 32.78 -32.7% Goethe displacement 1:21.18 1:08.47 -15.6% Cycles brick displacement 3:02.38 2:16.76 -25.0% Large displacement scene 23:54.12 20:09.62 -15.6% Reviewed By: sergey Differential Revision: https://developer.blender.org/D2513 --- intern/cycles/kernel/svm/svm_noisetex.h | 48 +++++++++++-------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h index 62ff38cf1c5..0347ab7b193 100644 --- a/intern/cycles/kernel/svm/svm_noisetex.h +++ b/intern/cycles/kernel/svm/svm_noisetex.h @@ -18,8 +18,19 @@ CCL_NAMESPACE_BEGIN /* Noise */ -ccl_device_inline void svm_noise(float3 p, float detail, float distortion, float *fac, float3 *color) +ccl_device void svm_node_tex_noise(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) { + uint co_offset, scale_offset, detail_offset, distortion_offset, fac_offset, color_offset; + + decode_node_uchar4(node.y, &co_offset, &scale_offset, &detail_offset, &distortion_offset); + decode_node_uchar4(node.z, &color_offset, &fac_offset, NULL, NULL); + + uint4 node2 = read_node(kg, offset); + + float scale = stack_load_float_default(stack, scale_offset, node2.x); + float detail = stack_load_float_default(stack, detail_offset, node2.y); + float distortion = stack_load_float_default(stack, distortion_offset, node2.z); + float3 p = stack_load_float3(stack, co_offset) * scale; int hard = 0; if(distortion != 0.0f) { @@ -32,36 +43,17 @@ ccl_device_inline void svm_noise(float3 p, float detail, float distortion, float p += r; } - *fac = noise_turbulence(p, detail, hard); - *color = make_float3(*fac, - noise_turbulence(make_float3(p.y, p.x, p.z), detail, hard), - noise_turbulence(make_float3(p.y, p.z, p.x), detail, hard)); -} + float f = noise_turbulence(p, detail, hard); -ccl_device void svm_node_tex_noise(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) -{ - uint co_offset, scale_offset, detail_offset, distortion_offset, fac_offset, color_offset; - - decode_node_uchar4(node.y, &co_offset, &scale_offset, &detail_offset, &distortion_offset); - - uint4 node2 = read_node(kg, offset); - - float scale = stack_load_float_default(stack, scale_offset, node2.x); - float detail = stack_load_float_default(stack, detail_offset, node2.y); - float distortion = stack_load_float_default(stack, distortion_offset, node2.z); - float3 co = stack_load_float3(stack, co_offset); - - float3 color; - float f; - - svm_noise(co*scale, detail, distortion, &f, &color); - - decode_node_uchar4(node.z, &color_offset, &fac_offset, NULL, NULL); - - if(stack_valid(fac_offset)) + if(stack_valid(fac_offset)) { stack_store_float(stack, fac_offset, f); - if(stack_valid(color_offset)) + } + if(stack_valid(color_offset)) { + float3 color = make_float3(f, + noise_turbulence(make_float3(p.y, p.x, p.z), detail, hard), + noise_turbulence(make_float3(p.y, p.z, p.x), detail, hard)); stack_store_float3(stack, color_offset, color); + } } CCL_NAMESPACE_END From 3622074bf7672caddd2f939615cec8f308df1893 Mon Sep 17 00:00:00 2001 From: raa Date: Tue, 21 Feb 2017 21:02:56 +0300 Subject: [PATCH 08/18] Fix Drawing nested box layouts (D2508) --- source/blender/editors/interface/interface_layout.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index ca2538022b0..78860206c2f 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -3134,8 +3134,6 @@ static void ui_item_align(uiLayout *litem, short nr) else if (item->type == ITEM_LAYOUT_BOX) { box = (uiLayoutItemBx *)item; box->roundbox->alignnr = nr; - BLI_remlink(&litem->root->block->buttons, box->roundbox); - BLI_addhead(&litem->root->block->buttons, box->roundbox); } else if (((uiLayout *)item)->align) { ui_item_align((uiLayout *)item, nr); From ae1c1cd8c0da0c4b86efc171d5a6e34fbfb50d67 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 22 Feb 2017 09:40:46 +0100 Subject: [PATCH 09/18] Refactor Mesh split_faces() code to use loop normal spaces. Finding which loop should share its vertex with which others is not easy with regular Mesh data (mostly due to lack of advanced topology info, as opposed with BMesh case). Custom loop normals computing already does that - and can return 'loop normal spaces', which among other things contain definitions of 'smooth fans' of loops around vertices. Using those makes it easy to find vertices (and then edges) that needs splitting. This commit also adds support of non-autosmooth meshes, where we want to split out flat faces from smooth ones. --- source/blender/blenkernel/BKE_mesh.h | 4 +- source/blender/blenkernel/intern/mesh.c | 542 +++++++++--------- .../blender/blenkernel/intern/mesh_evaluate.c | 1 - 3 files changed, 286 insertions(+), 261 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index d41878825bb..e42692622f4 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -131,7 +131,6 @@ bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const cha float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3]; -void BKE_mesh_calc_normals_split(struct Mesh *mesh); void BKE_mesh_split_faces(struct Mesh *mesh); struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob, @@ -228,6 +227,9 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float bool BKE_mesh_has_custom_loop_normals(struct Mesh *me); +void BKE_mesh_calc_normals_split(struct Mesh *mesh); +void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh, struct MLoopNorSpaceArray *r_lnors_spacearr); + void BKE_mesh_normals_loop_split( const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges, struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops, diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 73fcd7615f7..7a27c43e28f 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -39,7 +39,9 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_linklist.h" #include "BLI_listbase.h" +#include "BLI_memarena.h" #include "BLI_edgehash.h" #include "BLI_string.h" @@ -2053,7 +2055,7 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) (me->mselect[me->totselect - 1].type == type)); } -void BKE_mesh_calc_normals_split(Mesh *mesh) +void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) { float (*r_loopnors)[3]; float (*polynors)[3]; @@ -2088,251 +2090,249 @@ void BKE_mesh_calc_normals_split(Mesh *mesh) BKE_mesh_normals_loop_split( mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, - (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL); + (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, r_lnors_spacearr, clnors, NULL); if (free_polynors) { MEM_freeN(polynors); } } +void BKE_mesh_calc_normals_split(Mesh *mesh) +{ + BKE_mesh_calc_normals_split_ex(mesh, NULL); +} + /* Split faces helper functions. */ -enum { - /* Vertex is adjacent to some loop which normal is different, - * hence split of this vertex is required. - */ - SPLIT_VERT_NEED_SPLIT = (1 << 0), - /* Original vertex was already re-used by split logic. */ - SPLIT_VERT_REUSED = (1 << 1), -}; -enum { - /* Edge is adjacent to any of vertex tagged for split. - */ - SPLIT_EDGE_NEED_SPLIT = (1 << 0), - /* Original edge was already re-used by split logic. */ - SPLIT_EDGE_REUSED = (1 << 1), -}; +typedef struct SplitFaceNewVert { + struct SplitFaceNewVert *next; + int new_index; + int orig_index; + float *vnor; +} SplitFaceNewVert; -/* Tag vertices which normals are not equal to any adjacent loop - * and hence split on that vertex is required. - * - * Returns truth if any of vertex needs to be split. - */ -static bool split_faces_tag_verts(const Mesh *mesh, uchar *vert_flags) -{ - const int num_polys = mesh->totpoly; - const MVert *mvert = mesh->mvert; - const MLoop *mloop = mesh->mloop; - const MPoly *mpoly = mesh->mpoly; - float (*lnors)[3] = CustomData_get_layer(&mesh->ldata, CD_NORMAL); - bool has_split_verts = false; - for (int poly = 0; poly < num_polys; poly++) { - const MPoly *mp = &mpoly[poly]; - for (int loop = 0; loop < mp->totloop; loop++) { - const MLoop *ml = &mloop[mp->loopstart + loop]; - const MVert *mv = &mvert[ml->v]; - float vn[3]; - normal_short_to_float_v3(vn, mv->no); - if (len_squared_v3v3(vn, lnors[mp->loopstart + loop]) > FLT_EPSILON) { - vert_flags[ml->v] |= SPLIT_VERT_NEED_SPLIT; - has_split_verts = true; - } - } - } - return has_split_verts; -} +typedef struct SplitFaceNewEdge { + struct SplitFaceNewEdge *next; + int new_index; + int orig_index; + int v1; + int v2; +} SplitFaceNewEdge; -/* Count number of new vertices to be added. - * - * Note that one of the loop where split is required will re-use - * it's vertex in order to avoid creation of loose vertices. - */ -static int split_faces_count_new_verts(const Mesh *mesh, uchar *vert_flags) +/* Detect needed new vertices, and update accordingly loops' vertex indices. + * WARNING! Leaves mesh in invalid state. */ +static int split_faces_prepare_new_verts( + const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena, + bool *r_need_vnors_recalc) { - const int num_polys = mesh->totpoly; - const MLoop *mloop = mesh->mloop; - const MPoly *mpoly = mesh->mpoly; - int num_new_verts = 0; - for (int poly = 0; poly < num_polys; poly++) { - const MPoly *mp = &mpoly[poly]; - for (int loop = 0; loop < mp->totloop; loop++) { - const MLoop *ml = &mloop[mp->loopstart + loop]; - if (vert_flags[ml->v] & SPLIT_VERT_NEED_SPLIT) { - if (vert_flags[ml->v] & SPLIT_VERT_REUSED) { - ++num_new_verts; - } - else { - vert_flags[ml->v] |= SPLIT_VERT_REUSED; - } - } - } - } - return num_new_verts; -} - -/* Tag edges which are adjacent to at least one vertex tagged for split. */ -static void split_faces_tag_edges(Mesh *mesh, - const uchar *vert_flags, - uchar *edge_flags) -{ - const int num_polys = mesh->totpoly; - const MLoop *mloop = mesh->mloop; - const MPoly *mpoly = mesh->mpoly; - for (int poly = 0; poly < num_polys; poly++) { - const MPoly *mp = &mpoly[poly]; - int loop_prev = mp->totloop - 1; - for (int loop = 0; loop < mp->totloop; loop++) { - const int poly_loop_prev = mp->loopstart + loop_prev; - const MLoop *ml = &mloop[mp->loopstart + loop]; - const MLoop *ml_prev = &mloop[poly_loop_prev]; - const int mv_flag = vert_flags[ml->v]; - const int mv_prev_flag = vert_flags[ml_prev->v]; - bool need_split = false; - if (mv_flag & SPLIT_VERT_NEED_SPLIT) { - if (mv_prev_flag & SPLIT_VERT_NEED_SPLIT) { - /* Create new edge between twp split vertices. */ - need_split = true; - } - else { - /* Create new edge from existing vertex to a split one. */ - need_split = true; - } - } - else if (mv_prev_flag & SPLIT_VERT_NEED_SPLIT) { - /* Create new edge from split vertex to existing one. */ - need_split = true; - } - if (need_split) { - edge_flags[ml_prev->e] |= SPLIT_EDGE_NEED_SPLIT; - } - loop_prev = loop; - } - } -} - -/* Count number of new edges to be added. - * - * Note that one of the loop where split is required will re-use - * it's edge in order to avoid creation of loose edges. - */ -static int split_faces_count_new_edges(const Mesh *mesh, uchar *edge_flags) -{ - const int num_polys = mesh->totpoly; - const MLoop *mloop = mesh->mloop; - const MPoly *mpoly = mesh->mpoly; - int num_new_edges = 0; - for (int poly = 0; poly < num_polys; poly++) { - const MPoly *mp = &mpoly[poly]; - for (int loop = 0; loop < mp->totloop; loop++) { - const MLoop *ml = &mloop[mp->loopstart + loop]; - if (edge_flags[ml->e] & SPLIT_EDGE_NEED_SPLIT) { - if (edge_flags[ml->e] & SPLIT_EDGE_REUSED) { - ++num_new_edges; - } - else { - edge_flags[ml->e] |= SPLIT_EDGE_REUSED; - } - } - } - } - return num_new_edges; -} - -/* Perform actual split of vertices. - * - * NOTE: Will leave edges in inconsistent state. - */ -static void split_faces_split_verts(Mesh *mesh, - const int num_new_verts, - uchar *vert_flags) -{ - const int num_verts = mesh->totvert - num_new_verts; - const int num_polys = mesh->totpoly; + /* Note: if lnors_spacearr is NULL, ther is no autosmooth handling, and we only split out flat polys. */ + const int num_loops = mesh->totloop; + int num_verts = mesh->totvert; MVert *mvert = mesh->mvert; MLoop *mloop = mesh->mloop; - MPoly *mpoly = mesh->mpoly; - const float (*lnors)[3] = CustomData_get_layer(&mesh->ldata, CD_NORMAL); - int num_added_verts = 0; - /* Clear reused flag, we need it again. */ - for (int i = 0; i < num_verts; ++i) { - vert_flags[i] &= ~SPLIT_VERT_REUSED; - } - for (int poly = 0; poly < num_polys; poly++) { - MPoly *mp = &mpoly[poly]; - /* First we split all vertices to get proper flag whether they are - * split or not for all of them before handling edges. - */ - for (int loop = 0; loop < mp->totloop; loop++) { - int poly_loop = mp->loopstart + loop; - MLoop *ml = &mloop[poly_loop]; - if (vert_flags[ml->v] & SPLIT_VERT_NEED_SPLIT) { - if ((vert_flags[ml->v] & SPLIT_VERT_REUSED) == 0) { - /* Ignore first split on vertex, re-use it instead. */ - vert_flags[ml->v] |= SPLIT_VERT_REUSED; - normal_float_to_short_v3(mvert[ml->v].no, lnors[poly_loop]); - continue; - } - /* Create new vertex. */ - int new_vert = num_verts + num_added_verts; - CustomData_copy_data(&mesh->vdata, &mesh->vdata, - ml->v, new_vert, 1); - normal_float_to_short_v3(mvert[new_vert].no, - lnors[poly_loop]); - ml->v = new_vert; - num_added_verts++; - } - } - } -} -/* Perform actual split of edges. - * - * NOTE: Will correct all edges. - */ -static void split_faces_split_edges(Mesh *mesh, - const int num_new_edges, - uchar *edge_flags) -{ - const int num_edges = mesh->totedge - num_new_edges; - const int num_polys = mesh->totpoly; - MEdge *medge = mesh->medge; - MLoop *mloop = mesh->mloop; - MPoly *mpoly = mesh->mpoly; - int num_added_edges = 0; - /* Clear reused flag, we need it again. */ - for (int i = 0; i < num_edges; ++i) { - edge_flags[i] &= ~SPLIT_EDGE_REUSED; - } - for (int poly = 0; poly < num_polys; poly++) { - MPoly *mp = &mpoly[poly]; - for (int loop = 0, loop_prev = mp->totloop - 1; loop < mp->totloop; loop++) { - const int poly_loop_prev = mp->loopstart + loop_prev; - const MLoop *ml = &mloop[mp->loopstart + loop]; - MLoop *ml_prev = &mloop[poly_loop_prev]; - MEdge *me_prev = &medge[ml_prev->e]; - if (edge_flags[ml_prev->e] & SPLIT_EDGE_NEED_SPLIT) { - if ((edge_flags[ml_prev->e] & SPLIT_EDGE_REUSED) == 0) { - edge_flags[ml_prev->e] |= SPLIT_EDGE_REUSED; - me_prev->v1 = ml_prev->v; - me_prev->v2 = ml->v; + BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__); + + if (lnors_spacearr) { + BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__); + + MLoop *ml = mloop; + MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; + for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) { + if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { + const int vert_idx = ml->v; + const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx); + /* If vert is already used by another smooth fan, we need a new vert for this one. */ + const int new_vert_idx = vert_used ? num_verts++ : vert_idx; + + if ((*lnor_space)->loops) { + for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) { + const int ml_fan_idx = GET_INT_FROM_POINTER(lnode->link); + BLI_BITMAP_ENABLE(done_loops, ml_fan_idx); + if (vert_used) { + mloop[ml_fan_idx].v = new_vert_idx; + } + } } else { - const int index = num_edges + num_added_edges; - CustomData_copy_data(&mesh->edata, &mesh->edata, - ml_prev->e, index, 1); - MEdge *me_new = &medge[index]; - me_new->v1 = ml_prev->v; - me_new->v2 = ml->v; - ml_prev->e = index; - num_added_edges++; + /* Single loop in this fan... */ + BLI_BITMAP_ENABLE(done_loops, loop_idx); + if (vert_used) { + ml->v = new_vert_idx; + } + } + + if (!vert_used) { + BLI_BITMAP_ENABLE(verts_used, vert_idx); + /* We need to update that vertex's normal here, we won't go over it again. */ + /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to + * 'automatic normal' value computed from its polys, not some custom normal. + * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */ + normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor); + } + else { + /* Add new vert to list. */ + SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); + new_vert->orig_index = vert_idx; + new_vert->new_index = new_vert_idx; + new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ + new_vert->next = *new_verts; + *new_verts = new_vert; } } - loop_prev = loop; + } + + MEM_freeN(done_loops); + } + else { + /* No loop normal spaces available, we only split out flat polys. */ + const int num_polys = mesh->totpoly; + const MPoly *mpoly = mesh->mpoly; + + /* We do that in two loops, to keep original edges/verts to smooth polys preferencially. */ + const MPoly *mp = mpoly; + for (int i = 0; i < num_polys; i++, mp++) { + if (mp->flag & ME_SMOOTH) { + const MLoop *ml = &mloop[mp->loopstart]; + for (int j = 0; j < mp->totloop; j++, ml++) { + /* Just mark the vertex as used/reserved, that way neighbor flat polys, if any, + * will have to create their own. */ + BLI_BITMAP_ENABLE(verts_used, ml->v); + } + } + } + + mp = mpoly; + for (int i = 0; i < num_polys; i++, mp++) { + if (!(mp->flag & ME_SMOOTH)) { + MLoop *ml = &mloop[mp->loopstart]; + for (int j = 0; j < mp->totloop; j++, ml++) { + const int vert_idx = ml->v; + + if (BLI_BITMAP_TEST(verts_used, vert_idx)) { + /* Add new vert to list. */ + const int new_vert_idx = num_verts++; + ml->v = new_vert_idx; + + SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); + new_vert->orig_index = vert_idx; + new_vert->new_index = new_vert_idx; + new_vert->vnor = NULL; /* See note below about normals. */ + new_vert->next = *new_verts; + *new_verts = new_vert; + } + else { + BLI_BITMAP_ENABLE(verts_used, vert_idx); + } + } + /* Note: there is no way to get new normals for smooth vertices here (and we don't have direct access + * to poly normals either for flat ones), so we'll have to recompute all vnors at the end... */ + *r_need_vnors_recalc = true; + } + } + } + + MEM_freeN(verts_used); + + return num_verts - mesh->totvert; +} + +/* Detect needed new edges, and update accordingly loops' edge indices. + * WARNING! Leaves mesh in invalid state. */ +static int split_faces_prepare_new_edges( + const Mesh *mesh, SplitFaceNewEdge **new_edges, MemArena *memarena) +{ + const int num_polys = mesh->totpoly; + int num_edges = mesh->totedge; + MEdge *medge = mesh->medge; + MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + + BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__); + EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges); + + const MPoly *mp = mpoly; + for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) { + MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1]; + MLoop *ml = &mloop[mp->loopstart]; + for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) { + void **eval; + if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) { + /* That edge has not been encountered yet, define it. */ + if (BLI_BITMAP_TEST(edges_used, ml_prev->e)) { + /* Original edge has already been used, we need to define a new one. */ + const int edge_idx = num_edges++; + *eval = SET_INT_IN_POINTER(edge_idx); + ml_prev->e = edge_idx; + + SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge)); + new_edge->orig_index = ml_prev->e; + new_edge->new_index = edge_idx; + new_edge->v1 = ml_prev->v; + new_edge->v2 = ml->v; + new_edge->next = *new_edges; + *new_edges = new_edge; + } + else { + /* We can re-use original edge. */ + const int edge_idx = ml_prev->e; + medge[edge_idx].v1 = ml_prev->v; + medge[edge_idx].v2 = ml->v; + *eval = SET_INT_IN_POINTER(edge_idx); + BLI_BITMAP_ENABLE(edges_used, edge_idx); + } + } + else { + /* Edge already known, just update loop's edge index. */ + ml_prev->e = GET_INT_FROM_POINTER(*eval); + } + + ml_prev = ml; + } + } + + MEM_freeN(edges_used); + BLI_edgehash_free(edges_hash, NULL); + + return num_edges - mesh->totedge; +} + +/* Perform actual split of vertices. */ +static void split_faces_split_new_verts( + Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts) +{ + const int num_verts = mesh->totvert - num_new_verts; + MVert *mvert = mesh->mvert; + + /* Remember new_verts is a single linklist, so its items are in reversed order... */ + MVert *new_mv = &mvert[mesh->totvert - 1]; + for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) { + BLI_assert(new_verts->new_index == i); + CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1); + if (new_verts->vnor) { + normal_float_to_short_v3(new_mv->no, new_verts->vnor); } } } -/* Split faces based on the edge angle. +/* Perform actual split of edges. */ +static void split_faces_split_new_edges( + Mesh *mesh, SplitFaceNewEdge *new_edges, const int num_new_edges) +{ + const int num_edges = mesh->totedge - num_new_edges; + MEdge *medge = mesh->medge; + + /* Remember new_edges is a single linklist, so its items are in reversed order... */ + MEdge *new_med = &medge[mesh->totedge - 1]; + for (int i = mesh->totedge - 1; i >= num_edges ; i--, new_med--, new_edges = new_edges->next) { + BLI_assert(new_edges->new_index == i); + CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1); + new_med->v1 = new_edges->v1; + new_med->v2 = new_edges->v2; + } +} + +/* Split faces based on the edge angle and loop normals. * Matches behavior of face splitting in render engines. * * NOTE: Will leave CD_NORMAL loop data layer which is @@ -2340,48 +2340,72 @@ static void split_faces_split_edges(Mesh *mesh, */ void BKE_mesh_split_faces(Mesh *mesh) { - const int num_verts = mesh->totvert; - const int num_edges = mesh->totedge; const int num_polys = mesh->totpoly; - if ((mesh->flag & ME_AUTOSMOOTH) == 0) { - return; - } + if (num_polys == 0) { return; } BKE_mesh_tessface_clear(mesh); - /* Compute loop normals if needed. */ - if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - BKE_mesh_calc_normals_split(mesh); + + MLoopNorSpaceArray *lnors_spacearr = NULL; + MemArena *memarena; + bool need_vnors_recalc = false; + + if (mesh->flag & ME_AUTOSMOOTH) { + lnors_spacearr = MEM_callocN(sizeof(*lnors_spacearr), __func__); + /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ + BKE_mesh_calc_normals_split_ex(mesh, lnors_spacearr); + /* Stealing memarena from loop normals space array. */ + memarena = lnors_spacearr->mem; } - /* Runtime flags. */ - uchar *vert_flags = MEM_callocN(sizeof(*vert_flags) * num_verts, - "split faces vert flags"); - /* Tag vertces and check whether anything is tagged. */ - if (!split_faces_tag_verts(mesh, vert_flags)) { - /* No new vertices to be split added, can do early exit. */ - MEM_freeN(vert_flags); - return; + else { + /* We still have to split out flat faces... */ + memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + } + + SplitFaceNewVert *new_verts = NULL; + SplitFaceNewEdge *new_edges = NULL; + + /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */ + const int num_new_verts = split_faces_prepare_new_verts(mesh, lnors_spacearr, &new_verts, memarena, &need_vnors_recalc); + + if (num_new_verts > 0) { + /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of + * loops' vertex and edge indices to new, to-be-created split ones). */ + + const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena); + BLI_assert(num_new_edges > 0); + + /* Reallocate all vert and edge related data. */ + mesh->totvert += num_new_verts; + mesh->totedge += num_new_edges; + CustomData_realloc(&mesh->vdata, mesh->totvert); + CustomData_realloc(&mesh->edata, mesh->totedge); + /* Update pointers to a newly allocated memory. */ + BKE_mesh_update_customdata_pointers(mesh, false); + + /* Perform actual split of vertices and edges. */ + split_faces_split_new_verts(mesh, new_verts, num_new_verts); + split_faces_split_new_edges(mesh, new_edges, num_new_edges); + } + + /* Note: after this point mesh is expected to be valid again. */ + + /* CD_NORMAL is expected to be temporary only. */ + CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); + + if (lnors_spacearr) { + /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */ + BKE_lnor_spacearr_free(lnors_spacearr); + MEM_freeN(lnors_spacearr); + } + else { + BLI_memarena_free(memarena); + } + + if (need_vnors_recalc) { + BKE_mesh_calc_normals(mesh); } - /* Flush vertex flags to edges. */ - uchar *edge_flags = MEM_callocN(sizeof(*edge_flags) * num_edges, - "split faces edge flags"); - split_faces_tag_edges(mesh, vert_flags, edge_flags); - /* Count amount of new geometry. */ - int num_new_verts = split_faces_count_new_verts(mesh, vert_flags); - int num_new_edges = split_faces_count_new_edges(mesh, edge_flags); - /* Reallocate all vert and edge related data. */ - mesh->totvert += num_new_verts; - mesh->totedge += num_new_edges; - CustomData_realloc(&mesh->vdata, mesh->totvert); - CustomData_realloc(&mesh->edata, mesh->totedge); - /* Update pointers to a newly allocated memory. */ - BKE_mesh_update_customdata_pointers(mesh, false); - /* Perform actual split of vertices and adjacent edges. */ - split_faces_split_verts(mesh, num_new_verts, vert_flags); - split_faces_split_edges(mesh, num_new_edges, edge_flags); - MEM_freeN(vert_flags); - MEM_freeN(edge_flags); #ifdef VALIDATE_MESH BKE_mesh_validate(mesh, true, true); #endif diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index f9eba118383..003b7b784d5 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -1152,7 +1152,6 @@ void BKE_mesh_normals_loop_split( const bool use_split_normals, float split_angle, MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly) { - /* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */ BLI_assert(use_split_normals || !(r_lnors_spacearr)); From 2c30fd83f1513b4e9f146024501b15bd31ee4804 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 22 Feb 2017 10:04:13 +0100 Subject: [PATCH 10/18] Cycles: Additionally report all OpenCL cflags This way we can control exact spaces and such added to the cflags which is crucial to troubleshoot certain drivers. --- intern/cycles/device/opencl/opencl_util.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 82e1640e508..c7760e075cb 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -309,6 +309,8 @@ bool OpenCLDeviceBase::OpenCLProgram::build_kernel(const string *debug_src) string build_options; build_options = device->kernel_build_options(debug_src) + kernel_build_options; + VLOG(1) << "Build options passed to clBuildProgram: '" + << build_options << "'."; cl_int ciErr = clBuildProgram(program, 0, NULL, build_options.c_str(), NULL, NULL); /* show warnings even if build is successful */ From 36c4fc1ea9d987ec88b27c04927ac44e12a49778 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 22 Feb 2017 10:53:28 +0100 Subject: [PATCH 11/18] Cycles: Fix shading with autosmooth and custom normals New logic of split_faces was leaving mesh in a proper state from Blender's point of view, but Cycles wanted loop normals to be "flushed" to vertex normals. Now we do such a flush from Cycles side again, so we don't leave bad meshes behind. Thanks Bastien for assistance here! --- intern/cycles/blender/blender_mesh.cpp | 9 +++++++++ intern/cycles/blender/blender_util.h | 2 +- source/blender/blenkernel/BKE_mesh.h | 2 +- source/blender/blenkernel/intern/mesh.c | 6 ++++-- source/blender/editors/object/object_bake_api.c | 2 +- source/blender/makesrna/intern/rna_mesh_api.c | 9 ++++++++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index a1ff81e750a..fdc287084eb 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -777,6 +777,15 @@ static void create_mesh(Scene *scene, int shader = clamp(f->material_index(), 0, used_shaders.size()-1); bool smooth = f->use_smooth() || use_loop_normals; + if(use_loop_normals) { + BL::Array loop_normals = f->split_normals(); + for(int i = 0; i < n; i++) { + N[vi[i]] = make_float3(loop_normals[i * 3], + loop_normals[i * 3 + 1], + loop_normals[i * 3 + 2]); + } + } + /* Create triangles. * * NOTE: Autosmooth is already taken care about. diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 8120de96362..23df3c1bc30 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -79,7 +79,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, me.calc_normals_split(); } else { - me.split_faces(); + me.split_faces(false); } } if(subdivision_type == Mesh::SUBDIVISION_NONE) { diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index e42692622f4..b83bec5a302 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -131,7 +131,7 @@ bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const cha float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3]; -void BKE_mesh_split_faces(struct Mesh *mesh); +void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals); struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob, int apply_modifiers, int settings, int calc_tessface, int calc_undeformed); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 7a27c43e28f..918032b2df8 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2338,7 +2338,7 @@ static void split_faces_split_new_edges( * NOTE: Will leave CD_NORMAL loop data layer which is * used by render engines to set shading up. */ -void BKE_mesh_split_faces(Mesh *mesh) +void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) { const int num_polys = mesh->totpoly; @@ -2392,7 +2392,9 @@ void BKE_mesh_split_faces(Mesh *mesh) /* Note: after this point mesh is expected to be valid again. */ /* CD_NORMAL is expected to be temporary only. */ - CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); + if (free_loop_normals) { + CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); + } if (lnors_spacearr) { /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */ diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index fd95d6129ad..6b06e7b0a6c 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -619,7 +619,7 @@ static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob) ED_object_editmode_load(ob); Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0); - BKE_mesh_split_faces(me); + BKE_mesh_split_faces(me, true); return me; } diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index ff9873fb3d1..9b0a25560f9 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -209,6 +209,11 @@ static void rna_Mesh_flip_normals(Mesh *mesh) DAG_id_tag_update(&mesh->id, 0); } +static void rna_Mesh_split_faces(Mesh *mesh, int free_loop_normals) +{ + BKE_mesh_split_faces(mesh, free_loop_normals != 0); +} + #else void RNA_api_mesh(StructRNA *srna) @@ -240,8 +245,10 @@ void RNA_api_mesh(StructRNA *srna) func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split"); RNA_def_function_ui_description(func, "Free split vertex normals"); - func = RNA_def_function(srna, "split_faces", "BKE_mesh_split_faces"); + func = RNA_def_function(srna, "split_faces", "rna_Mesh_split_faces"); RNA_def_function_ui_description(func, "Split faces based on the edge angle"); + RNA_def_boolean(func, "free_loop_normals", 1, "Free Loop Notmals", + "Free loop normals custom data layer"); func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents"); RNA_def_function_flag(func, FUNC_USE_REPORTS); From 75cc33fa20457695d33e90886e8802c28fd96c2a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 22 Feb 2017 13:06:24 +0100 Subject: [PATCH 12/18] Fix Cycles still saving render output when error happened This was fixed ages ago for the interface case but not for the command line. The thing here is that currently external engines are relying on reports system to indicate that error happened so suppressing reports storage in the background mode prevented render pipeline from detecting errors happened. This is all weak and i don't like it, but this is better than delivering black frames from the farm. --- source/creator/creator_args.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 27579e58dba..77ca055dcea 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1364,7 +1364,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data) re = RE_NewRender(scene->id.name); BLI_begin_threaded_malloc(); - BKE_reports_init(&reports, RPT_PRINT); + BKE_reports_init(&reports, RPT_STORE); RE_SetReports(re, &reports); for (int i = 0; i < frames_range_len; i++) { @@ -1379,6 +1379,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data) } } RE_SetReports(re, NULL); + BKE_reports_clear(&reports); BLI_end_threaded_malloc(); MEM_freeN(frame_range_arr); return 1; From 99947e2943b5157de2ecba873e5c2d844f2b6911 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 22 Feb 2017 11:17:09 -0500 Subject: [PATCH 13/18] Use new api doc links Differential Revision: https://developer.blender.org/D2522 --- release/scripts/startup/bl_operators/wm.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index f5460d58d44..869070ed778 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1008,11 +1008,9 @@ class WM_OT_doc_view(Operator): doc_id = doc_id if bpy.app.version_cycle == "release": - _prefix = ("https://www.blender.org/api/blender_python_api_%s%s_release" % - ("_".join(str(v) for v in bpy.app.version[:2]), bpy.app.version_char)) + _prefix = ("https://docs.blender.org/api/blender_python_api_current") else: - _prefix = ("https://www.blender.org/api/blender_python_api_%s" % - "_".join(str(v) for v in bpy.app.version)) + _prefix = ("https://docs.blender.org/api/blender_python_api_master") def execute(self, context): url = _wm_doc_get_id(self.doc_id, do_url=True, url_prefix=self._prefix) From b637db2a7a828fe40668114242e4c1bc36970ce1 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 22 Feb 2017 18:06:09 +0100 Subject: [PATCH 14/18] Cleanup: remove unused orig_nu from keyIndex ghash of editcurves. --- source/blender/editors/curve/editcurve.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index b09186b970b..5686cacd4e5 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -96,7 +96,6 @@ typedef struct { void *orig_cv; int key_index, nu_index, pt_index, vertex_index; bool switched; - Nurb *orig_nu; } CVKeyIndex; void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus); @@ -138,7 +137,7 @@ void printknots(Object *obedit) /* ********************* Shape keys *************** */ -static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index, Nurb *orig_nu) +static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index) { CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), "init_cvKeyIndex"); @@ -148,7 +147,6 @@ static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt cvIndex->pt_index = pt_index; cvIndex->vertex_index = vertex_index; cvIndex->switched = false; - cvIndex->orig_nu = orig_nu; return cvIndex; } @@ -174,7 +172,7 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase) origbezt = orignu->bezt; pt_index = 0; while (a--) { - keyIndex = init_cvKeyIndex(origbezt, key_index, nu_index, pt_index, vertex_index, orignu); + keyIndex = init_cvKeyIndex(origbezt, key_index, nu_index, pt_index, vertex_index); BLI_ghash_insert(gh, bezt, keyIndex); key_index += 12; vertex_index += 3; @@ -189,7 +187,7 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase) origbp = orignu->bp; pt_index = 0; while (a--) { - keyIndex = init_cvKeyIndex(origbp, key_index, nu_index, pt_index, vertex_index, orignu); + keyIndex = init_cvKeyIndex(origbp, key_index, nu_index, pt_index, vertex_index); BLI_ghash_insert(gh, bp, keyIndex); key_index += 4; bp++; From 5e1d4714fef72407e3497e70ddac3f1caa959f39 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 22 Feb 2017 21:20:50 +0100 Subject: [PATCH 15/18] Fix T50745: Shape key editing on bezier objects broken with Rendered Viewport Shading So... Curve+shapekey was even more broken than it looked, this report was actually a nice crasher (immediate crash in an ASAN build when trying to edit a curve shapekey with some viewport rendering enabled). There were actually two different issues here. I) The less critical: rB6f1493f68fe was not fully fixing issues from T50614. More specifically, if you updated obdata from editnurb *without* freeing editnurb afterwards, you had a 'restored' (to original curve) editnurb, without the edited shapekey modifications anymore. This was fixed by tweaking again `calc_shapeKeys()` behavior in `ED_curve_editnurb_load()`. II) The crasher: in `ED_curve_editnurb_make()`, the call to `init_editNurb_keyIndex()` was directly storing pointers of obdata nurbs. Since those get freed every time `ED_curve_editnurb_load()` is executed, it easily ended up being pointers to freed memory. This was fixed by copying those data, which implied more complex handling code for editnurbs->keyindex, and some reshuffling of a few functions to avoid duplicating things between editor's editcurve.c and BKE's curve.c Note that the separation of functions between editors and BKE area for curve could use a serious update, it's currently messy to say the least. Then again, that area is due to rework since a long time now... :/ Finally, aligned 'for_render' curve evaluation to mesh one - now editing a shapekey will show in rendered viewports, if it does have some weight (exactly as with shapekeys of meshes). --- source/blender/blenkernel/BKE_curve.h | 11 ++- source/blender/blenkernel/intern/curve.c | 23 ++++-- source/blender/blenkernel/intern/displist.c | 2 +- source/blender/editors/curve/editcurve.c | 88 +++++++++++---------- 4 files changed, 77 insertions(+), 47 deletions(-) diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 5558786d254..e111bd0e16b 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -36,6 +36,7 @@ struct BezTriple; struct Curve; struct EditNurb; +struct GHash; struct ListBase; struct Main; struct Nurb; @@ -52,6 +53,13 @@ typedef struct CurveCache { struct Path *path; } CurveCache; +/* Definitions needed for shape keys */ +typedef struct CVKeyIndex { + void *orig_cv; + int key_index, nu_index, pt_index, vertex_index; + bool switched; +} CVKeyIndex; + #define KNOTSU(nu) ( (nu)->orderu + (nu)->pntsu + (((nu)->flagu & CU_NURB_CYCLIC) ? ((nu)->orderu - 1) : 0) ) #define KNOTSV(nu) ( (nu)->orderv + (nu)->pntsv + (((nu)->flagv & CU_NURB_CYCLIC) ? ((nu)->orderv - 1) : 0) ) @@ -108,7 +116,8 @@ void BK_curve_nurbs_vertexCos_apply(struct ListBase *lb, float (*vertexCos)[3]); float (*BKE_curve_nurbs_keyVertexCos_get(struct ListBase *lb, float *key))[3]; void BKE_curve_nurbs_keyVertexTilts_apply(struct ListBase *lb, float *key); -void BKE_curve_editNurb_keyIndex_free(struct EditNurb *editnurb); +void BKE_curve_editNurb_keyIndex_delCV(struct GHash *keyindex, const void *cv); +void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex); void BKE_curve_editNurb_free(struct Curve *cu); struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 90a514781d7..439abb1d593 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -89,20 +89,33 @@ void BKE_curve_editfont_free(Curve *cu) } } -void BKE_curve_editNurb_keyIndex_free(EditNurb *editnurb) +static void curve_editNurb_keyIndex_cv_free_cb(void *val) { - if (!editnurb->keyindex) { + CVKeyIndex *index = val; + MEM_freeN(index->orig_cv); + MEM_freeN(val); +} + +void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv) +{ + BLI_assert(keyindex != NULL); + BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb); +} + +void BKE_curve_editNurb_keyIndex_free(GHash **keyindex) +{ + if (!(*keyindex)) { return; } - BLI_ghash_free(editnurb->keyindex, NULL, MEM_freeN); - editnurb->keyindex = NULL; + BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb); + *keyindex = NULL; } void BKE_curve_editNurb_free(Curve *cu) { if (cu->editnurb) { BKE_nurbList_free(&cu->editnurb->nurbs); - BKE_curve_editNurb_keyIndex_free(cu->editnurb); + BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex); MEM_freeN(cu->editnurb); cu->editnurb = NULL; } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 49db75a0474..f8a9d57f579 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -819,7 +819,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, if (editmode) required_mode |= eModifierMode_Editmode; - if (cu->editnurb == NULL) { + if (!editmode) { keyVerts = BKE_key_evaluate_object(ob, &numVerts); if (keyVerts) { diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 5686cacd4e5..47f42ab5321 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -91,13 +91,6 @@ typedef struct { int flag; } UndoCurve; -/* Definitions needed for shape keys */ -typedef struct { - void *orig_cv; - int key_index, nu_index, pt_index, vertex_index; - bool switched; -} CVKeyIndex; - void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus); static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split); static int curve_delete_segments(Object *obedit, const bool split); @@ -139,7 +132,7 @@ void printknots(Object *obedit) static CVKeyIndex *init_cvKeyIndex(void *cv, int key_index, int nu_index, int pt_index, int vertex_index) { - CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), "init_cvKeyIndex"); + CVKeyIndex *cvIndex = MEM_callocN(sizeof(CVKeyIndex), __func__); cvIndex->orig_cv = cv; cvIndex->key_index = key_index; @@ -172,7 +165,12 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase) origbezt = orignu->bezt; pt_index = 0; while (a--) { - keyIndex = init_cvKeyIndex(origbezt, key_index, nu_index, pt_index, vertex_index); + /* We cannot keep *any* reference to curve obdata, + * it might be replaced and freed while editcurve remain in use (in viewport render case e.g.). + * Note that we could use a pool to avoid lots of malloc's here, but... not really a problem for now. */ + BezTriple *origbezt_cpy = MEM_mallocN(sizeof(*origbezt), __func__); + *origbezt_cpy = *origbezt; + keyIndex = init_cvKeyIndex(origbezt_cpy, key_index, nu_index, pt_index, vertex_index); BLI_ghash_insert(gh, bezt, keyIndex); key_index += 12; vertex_index += 3; @@ -187,7 +185,12 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase) origbp = orignu->bp; pt_index = 0; while (a--) { - keyIndex = init_cvKeyIndex(origbp, key_index, nu_index, pt_index, vertex_index); + /* We cannot keep *any* reference to curve obdata, + * it might be replaced and freed while editcurve remain in use (in viewport render case e.g.). + * Note that we could use a pool to avoid lots of malloc's here, but... not really a problem for now. */ + BPoint *origbp_cpy = MEM_mallocN(sizeof(*origbp_cpy), __func__); + *origbp_cpy = *origbp; + keyIndex = init_cvKeyIndex(origbp_cpy, key_index, nu_index, pt_index, vertex_index); BLI_ghash_insert(gh, bp, keyIndex); key_index += 4; bp++; @@ -248,23 +251,22 @@ static int getKeyIndexOrig_keyIndex(EditNurb *editnurb, void *cv) return index->key_index; } -static void keyIndex_delCV(EditNurb *editnurb, const void *cv) +static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt) { if (!editnurb->keyindex) { return; } - BLI_ghash_remove(editnurb->keyindex, cv, NULL, MEM_freeN); -} - -static void keyIndex_delBezt(EditNurb *editnurb, BezTriple *bezt) -{ - keyIndex_delCV(editnurb, bezt); + BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt); } static void keyIndex_delBP(EditNurb *editnurb, BPoint *bp) { - keyIndex_delCV(editnurb, bp); + if (!editnurb->keyindex) { + return; + } + + BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp); } static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu) @@ -280,7 +282,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu) a = nu->pntsu; while (a--) { - BLI_ghash_remove(editnurb->keyindex, bezt, NULL, MEM_freeN); + BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bezt); bezt++; } } @@ -289,7 +291,7 @@ static void keyIndex_delNurb(EditNurb *editnurb, Nurb *nu) a = nu->pntsu * nu->pntsv; while (a--) { - BLI_ghash_remove(editnurb->keyindex, bp, NULL, MEM_freeN); + BKE_curve_editNurb_keyIndex_delCV(editnurb->keyindex, bp); bp++; } } @@ -533,6 +535,7 @@ static GHash *dupli_keyIndexHash(GHash *keyindex) CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index"); memcpy(newIndex, index, sizeof(CVKeyIndex)); + newIndex->orig_cv = MEM_dupallocN(index->orig_cv); BLI_ghash_insert(gh, cv, newIndex); } @@ -622,7 +625,7 @@ static void calc_keyHandles(ListBase *nurb, float *key) } } -static void calc_shapeKeys(Object *obedit) +static void calc_shapeKeys(Object *obedit, ListBase *newnurbs) { Curve *cu = (Curve *)obedit->data; @@ -634,7 +637,7 @@ static void calc_shapeKeys(Object *obedit) KeyBlock *actkey = BLI_findlink(&cu->key->block, editnurb->shapenr - 1); BezTriple *bezt, *oldbezt; BPoint *bp, *oldbp; - Nurb *nu; + Nurb *nu, *newnu; int totvert = BKE_nurbList_verts_count(&editnurb->nurbs); float (*ofs)[3] = NULL; @@ -704,20 +707,25 @@ static void calc_shapeKeys(Object *obedit) currkey = cu->key->block.first; while (currkey) { - int apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr - 1 == currkey->relative)); + const bool apply_offset = (ofs && (currkey != actkey) && (editnurb->shapenr - 1 == currkey->relative)); float *fp = newkey = MEM_callocN(cu->key->elemsize * totvert, "currkey->data"); ofp = oldkey = currkey->data; nu = editnurb->nurbs.first; + /* We need to restore to original curve into newnurb, *not* editcurve's nurbs. + * Otherwise, in case we update obdata *without* leaving editmode (e.g. viewport render), we would + * invalidate editcurve. */ + newnu = newnurbs->first; i = 0; while (nu) { if (currkey == actkey) { - int restore = actkey != cu->key->refkey; + const bool restore = actkey != cu->key->refkey; if (nu->bezt) { bezt = nu->bezt; a = nu->pntsu; + BezTriple *newbezt = newnu->bezt; while (a--) { int j; oldbezt = getKeyIndexOrig_bezt(editnurb, bezt); @@ -726,7 +734,7 @@ static void calc_shapeKeys(Object *obedit) copy_v3_v3(fp, bezt->vec[j]); if (restore && oldbezt) { - copy_v3_v3(bezt->vec[j], oldbezt->vec[j]); + copy_v3_v3(newbezt->vec[j], oldbezt->vec[j]); } fp += 3; @@ -734,16 +742,18 @@ static void calc_shapeKeys(Object *obedit) fp[0] = bezt->alfa; if (restore && oldbezt) { - bezt->alfa = oldbezt->alfa; + newbezt->alfa = oldbezt->alfa; } fp += 3; ++i; /* alphas */ bezt++; + newbezt++; } } else { bp = nu->bp; a = nu->pntsu * nu->pntsv; + BPoint *newbp = newnu->bp; while (a--) { oldbp = getKeyIndexOrig_bp(editnurb, bp); @@ -752,12 +762,13 @@ static void calc_shapeKeys(Object *obedit) fp[3] = bp->alfa; if (restore && oldbp) { - copy_v3_v3(bp->vec, oldbp->vec); - bp->alfa = oldbp->alfa; + copy_v3_v3(newbp->vec, oldbp->vec); + newbp->alfa = oldbp->alfa; } fp += 4; bp++; + newbp++; i += 2; } } @@ -1193,11 +1204,6 @@ void ED_curve_editnurb_load(Object *obedit) remap_hooks_and_vertex_parents(obedit); - /* We have to apply shapekeys *before* copying nurbs into newnurb, otherwise the reset to - * refkey/original curve data that has to be done when editing non-refkey shapekey would be useless, - * only affecting editnurb and not ob->data. */ - calc_shapeKeys(obedit); - for (nu = editnurb->first; nu; nu = nu->next) { newnu = BKE_nurb_duplicate(nu); BLI_addtail(&newnurb, newnu); @@ -1207,6 +1213,11 @@ void ED_curve_editnurb_load(Object *obedit) } } + /* We have to pass also new copied nurbs, since we want to restore original curve (without edited shapekey) + * on obdata, but *not* on editcurve itself (ED_curve_editnurb_load call does not always implies freeing + * of editcurve, e.g. when called to generate render data...). */ + calc_shapeKeys(obedit, &newnurb); + cu->nurb = newnurb; ED_curve_updateAnimPaths(obedit->data); @@ -1233,8 +1244,7 @@ void ED_curve_editnurb_make(Object *obedit) if (editnurb) { BKE_nurbList_free(&editnurb->nurbs); - BKE_curve_editNurb_keyIndex_free(editnurb); - editnurb->keyindex = NULL; + BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex); } else { editnurb = MEM_callocN(sizeof(EditNurb), "editnurb"); @@ -1314,8 +1324,7 @@ static int separate_exec(bContext *C, wmOperator *op) ED_curve_editnurb_make(newob); newedit = newcu->editnurb; BKE_nurbList_free(&newedit->nurbs); - BKE_curve_editNurb_keyIndex_free(newedit); - newedit->keyindex = NULL; + BKE_curve_editNurb_keyIndex_free(&newedit->keyindex); BLI_movelisttolist(&newedit->nurbs, &newnurb); /* 4. put old object out of editmode and delete separated geometry */ @@ -6115,7 +6124,7 @@ static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *cu_v) BKE_nurbList_free(editbase); if (undoCurve->undoIndex) { - BLI_ghash_free(editnurb->keyindex, NULL, MEM_freeN); + BKE_curve_editNurb_keyIndex_free(&editnurb->keyindex); editnurb->keyindex = dupli_keyIndexHash(undoCurve->undoIndex); } @@ -6193,8 +6202,7 @@ static void free_undoCurve(void *ucv) BKE_nurbList_free(&undoCurve->nubase); - if (undoCurve->undoIndex) - BLI_ghash_free(undoCurve->undoIndex, NULL, MEM_freeN); + BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex); free_fcurves(&undoCurve->fcurves); free_fcurves(&undoCurve->drivers); From 43299f9465aa7ae6ae66f70a70aaea455280e90a Mon Sep 17 00:00:00 2001 From: raa Date: Thu, 23 Feb 2017 00:03:31 +0300 Subject: [PATCH 16/18] Columns should be expandable by default --- source/blender/editors/interface/interface_layout.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 78860206c2f..9acc8cf8271 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2216,7 +2216,6 @@ static void ui_litem_estimate_column(uiLayout *litem) { uiItem *item; int itemw, itemh; - bool min_size_flag = true; litem->w = 0; litem->h = 0; @@ -2224,18 +2223,12 @@ static void ui_litem_estimate_column(uiLayout *litem) for (item = litem->items.first; item; item = item->next) { ui_item_size(item, &itemw, &itemh); - min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN); - litem->w = MAX2(litem->w, itemw); litem->h += itemh; if (item->next) litem->h += litem->space; } - - if (min_size_flag) { - litem->item.flag |= UI_ITEM_MIN; - } } static void ui_litem_layout_column(uiLayout *litem) From 7359cc1060e43bf094d471d5a4bdbd56f672ddbf Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 23 Feb 2017 01:59:40 +0100 Subject: [PATCH 17/18] Fix possible crash in various 3D View operators Was actually harmeless and not crashing, but I'd say more or less only by luck: the NULL-check for region data would only evaluate to true for the correct 3D View region. However, if we were to add region data to a different region type in future, this would lead to undefined behavior if executed in the wrong region. --- source/blender/editors/space_view3d/space_view3d.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 964f4bcdd9c..e73cc507f3e 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -180,8 +180,8 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar) View3D *v3d = (View3D *)sa->spacedata.first; if (ar) { - RegionView3D *rv3d = ar->regiondata; - if (rv3d && (rv3d->viewlock & RV3D_LOCKED) == 0) { + RegionView3D *rv3d; + if ((ar->regiontype == RGN_TYPE_WINDOW) && (rv3d = ar->regiondata) && (rv3d->viewlock & RV3D_LOCKED) == 0) { *r_v3d = v3d; *r_ar = ar; return true; From 9dd194716b0f43fa02ae6cd32ada556d8d622390 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 23 Feb 2017 10:39:51 +0100 Subject: [PATCH 18/18] Fix T50736: Zero streaks in Glare node. Please never, ever use same DNA var for two different things. Even worse if they do not have same type and ranges! This is only ensuring issues (as described in report, but also if animating both RNA props using same DNA var... yuck). And we were not even saving any byte in DNA, could reuse some padding there to store the two new needed vars (yes, two, since we cannot re-use existing one if we want to keep backward *and* forward compatibility). --- .../blenloader/intern/versioning_270.c | 23 +++++++++++++++++++ source/blender/blenloader/intern/writefile.c | 19 +++++++++++++++ .../COM_GlareSimpleStarOperation.cpp | 16 ++++++------- .../operations/COM_GlareStreaksOperation.cpp | 2 +- source/blender/makesdna/DNA_node_types.h | 3 ++- source/blender/makesrna/intern/rna_nodetree.c | 6 ++--- .../composite/nodes/node_composite_glare.c | 3 ++- 7 files changed, 58 insertions(+), 14 deletions(-) diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 6235ebf28ee..7106cf60721 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1575,6 +1575,29 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } + /* Fix for T50736, Glare comp node using same var for two different things. */ + if (!DNA_struct_elem_find(fd->filesdna, "NodeGlare", "char", "star_45")) { + FOREACH_NODETREE(main, ntree, id) { + if (ntree->type == NTREE_COMPOSIT) { + ntreeSetTypes(NULL, ntree); + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_GLARE) { + NodeGlare *ndg = node->storage; + switch (ndg->type) { + case 2: /* Grrrr! magic numbers :( */ + ndg->streaks = ndg->angle; + break; + case 0: + ndg->star_45 = ndg->angle != 0; + break; + default: + break; + } + } + } + } + } FOREACH_NODETREE_END + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 998d4161c2f..38a032f4907 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1026,6 +1026,25 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) { /* pass */ } + else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) { + /* Simple forward compat for fix for T50736. + * Not ideal (there is no ideal solution here), but should do for now. */ + NodeGlare *ndg = node->storage; + /* Not in undo case. */ + if (!wd->current) { + switch (ndg->type) { + case 2: /* Grrrr! magic numbers :( */ + ndg->angle = ndg->streaks; + break; + case 0: + ndg->angle = ndg->star_45; + break; + default: + break; + } + } + writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); + } else { writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); } diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp index 957ac5af748..57aa3a1bac2 100644 --- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp @@ -44,18 +44,18 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil xp = x + i; tbuf1->read(c, x, y); mul_v3_fl(c, f1); - tbuf1->read(tc, (settings->angle ? xm : x), ym); + tbuf1->read(tc, (settings->star_45 ? xm : x), ym); madd_v3_v3fl(c, tc, f2); - tbuf1->read(tc, (settings->angle ? xp : x), yp); + tbuf1->read(tc, (settings->star_45 ? xp : x), yp); madd_v3_v3fl(c, tc, f2); c[3] = 1.0f; tbuf1->writePixel(x, y, c); tbuf2->read(c, x, y); mul_v3_fl(c, f1); - tbuf2->read(tc, xm, (settings->angle ? yp : y)); + tbuf2->read(tc, xm, (settings->star_45 ? yp : y)); madd_v3_v3fl(c, tc, f2); - tbuf2->read(tc, xp, (settings->angle ? ym : y)); + tbuf2->read(tc, xp, (settings->star_45 ? ym : y)); madd_v3_v3fl(c, tc, f2); c[3] = 1.0f; tbuf2->writePixel(x, y, c); @@ -73,18 +73,18 @@ void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTil xp = x + i; tbuf1->read(c, x, y); mul_v3_fl(c, f1); - tbuf1->read(tc, (settings->angle ? xm : x), ym); + tbuf1->read(tc, (settings->star_45 ? xm : x), ym); madd_v3_v3fl(c, tc, f2); - tbuf1->read(tc, (settings->angle ? xp : x), yp); + tbuf1->read(tc, (settings->star_45 ? xp : x), yp); madd_v3_v3fl(c, tc, f2); c[3] = 1.0f; tbuf1->writePixel(x, y, c); tbuf2->read(c, x, y); mul_v3_fl(c, f1); - tbuf2->read(tc, xm, (settings->angle ? yp : y)); + tbuf2->read(tc, xm, (settings->star_45 ? yp : y)); madd_v3_v3fl(c, tc, f2); - tbuf2->read(tc, xp, (settings->angle ? ym : y)); + tbuf2->read(tc, xp, (settings->star_45 ? ym : y)); madd_v3_v3fl(c, tc, f2); c[3] = 1.0f; tbuf2->writePixel(x, y, c); diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp index da6076337b4..535f2952e5d 100644 --- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp @@ -28,7 +28,7 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile, int x, y, n; unsigned int nump = 0; float c1[4], c2[4], c3[4], c4[4]; - float a, ang = DEG2RADF(360.0f) / (float)settings->angle; + float a, ang = DEG2RADF(360.0f) / (float)settings->streaks; int size = inputTile->getWidth() * inputTile->getHeight(); int size4 = size * 4; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index fd601e55550..47677e50451 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -668,7 +668,8 @@ typedef struct NodeScriptDict { /* qdn: glare node */ typedef struct NodeGlare { char quality, type, iter; - char angle, pad_c1, size, pad[2]; + /* XXX angle is only kept for backward/forward compatibility, was used for two different things, see T50736. */ + char angle DNA_DEPRECATED, pad_c1, size, star_45, streaks; float colmod, mix, threshold, fade; float angle_ofs, pad_f1; } NodeGlare; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index b35142f2a58..784004182dd 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -5721,8 +5721,8 @@ static void def_cmp_glare(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "streaks", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "angle"); - RNA_def_property_range(prop, 2, 16); + RNA_def_property_int_sdna(prop, NULL, "streaks"); + RNA_def_property_range(prop, 1, 16); RNA_def_property_ui_text(prop, "Streaks", "Total number of streaks"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -5739,7 +5739,7 @@ static void def_cmp_glare(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_rotate_45", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "angle", 0); + RNA_def_property_boolean_sdna(prop, NULL, "star_45", 0); RNA_def_property_ui_text(prop, "Rotate 45", "Simple star filter: add 45 degree rotation offset"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.c b/source/blender/nodes/composite/nodes/node_composite_glare.c index c512ea49586..76020e55463 100644 --- a/source/blender/nodes/composite/nodes/node_composite_glare.c +++ b/source/blender/nodes/composite/nodes/node_composite_glare.c @@ -50,7 +50,8 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node) ndg->colmod = 0.25; ndg->mix = 0; ndg->threshold = 1; - ndg->angle = 4; + ndg->star_45 = true; + ndg->streaks = 4; ndg->angle_ofs = 0.0f; ndg->fade = 0.9; ndg->size = 8;